scheme
Макросы схемы
Поиск…
Гигиенические и ссылочно-прозрачные макросы с синтаксическими правилами
Наибольшее преимущество LISP и Scheme по сравнению с другими основными языками программирования - их макросистема. В отличие от препроцессора C и других языков макросов, макросы Scheme анализируют код как входной и возвращают расширенный код в качестве вывода. Это одно из приложений фразы Scheme «code is data», и именно это делает язык настолько мощным.
Макросы в схеме создаются с помощью define-syntax , который может определять макрос несколькими способами. Самый простой способ - использовать syntax-rules , которые используют сопоставление шаблонов для преобразования входного кода в выходной код.
В этом примере создается простой for item in list а for list as item синтаксис for list as item для циклизации элементов в списке:
(define-syntax for
(syntax-rules (in as) ; 'in' and 'as' keywords must match in the pattern
; When the 'for' macro is called, try matching this pattern
((for element in list
body ...) ; Match one or more body expressions
; Transform the input code
(for-each (lambda (element)
body ...)
list))
; Try matching another pattern if the first fails
((for list as element
body ...)
; Use the existing macro for the transform
(for element in list
body ...))))
Затем эти два макроса можно использовать следующим образом, обеспечивая более императивный стиль:
(let ((names '(Alice Bob Eve)))
(for name in names
(display "Hello ")
(display name)
(newline))
(for names as name
(display "name: ")
(display name)
(newline)))
Запуск кода обеспечит ожидаемый результат:
Hello Alice
Hello Bob
Hello Eve
name: Alice
name: Bob
name: Eve
Наиболее распространенной ошибкой для поиска является не перенос правильных значений в макрос, что часто приводит к бесполезному сообщению об ошибке, которое применяется к расширенной форме вместо вызова макроса.
for определения синтаксиса выше не проверяют они передаются ли идентификатор и список, так что прохождение любого другого типа приведет к ошибке , указывая на имеющиеся в наличии for-each вызова , а не из for вызов. Отладка этого приводит к победе над целью макроса, поэтому пользователю нужно помещать туда чеки и сообщать об ошибках использования, которые затем можно поймать во время компиляции.