В интерпретаторе Lisp может легко быть ветвь в eval
, которая может развернуть макрос и в процессе его расширения вызвать функции для создания расширенного выражения. Я сделал это, прежде чем использовать макросы низкого уровня, и это легко получить.
Но в компиляторе нет никаких функций для вызова расширенного кода: проблему можно увидеть довольно просто в следующем примере:
(defmacro cube (n)
(let ((x (gensym)))
`(let ((,x ,n))
(* ,x ,x ,x))))
Когда макрос расшифровывается интерпретатором, он вызывает gensym
и делает то, что вы ожидаете. При расширении компилятором вы создадите код для let
, который связывает x
с (gensym)
, но символ gensymmed необходим только для того, чтобы компилятор делал правильные действия. А поскольку gensym
фактически не вызывается перед компиляцией макроса, это не очень полезно.
Это становится еще более странным для меня, когда макрос создает список, который будет использоваться в качестве расширения с помощью map
или filter
.
Итак, как это работает? Конечно, скомпилированный код не скомпилирован в (eval *macro-code*)
, потому что это было бы ужасно неэффективно. Есть ли хорошо написанный компилятор Lisp, где это ясно?