Почему макрос оценивается при компиляции определения функции (Clozure Common Lisp)?
Я имею:
(defmacro assign (name value)
(format t "assigning ~A to ~A~%" `,name `,value))
(defun opcode-call (&rest args)
(mapcar (lambda (arg)
(if (stringp arg)
(let ((var (gensym)))
(assign var arg)
var)
arg))
args))
Когда я компилирую opcode-call, REPL выводит:
assigning VAR to ARG
OPCODE-CALL
Почему присвоение оценивается во время компиляции?
1 ответ
Решение
Макросы - это функции. Они принимают код через свои аргументы и возвращают новый код. Макросы могут иметь побочные эффекты.
Ваш код печатает что-то как побочный эффект при расширении макроса и возвращает NIL
(результат вызова FORMAT
функция).
(defmacro assign (name value)
(format t "assigning ~A to ~A~%" `,name `,value))
Используй это:
CL-USER 11 > (multiple-value-list (macroexpand '(assign foo bar)))
assigning FOO to BAR ; prints as a side effect
(NIL T) ; the macro expansion returns two values NIL and T
Не имеет смысла приводить аргументы. Код эквивалентен этому:
(defmacro assign (name value)
(format t "assigning ~A to ~A~%" name value))
Все еще возвращается NIL
как расширение, которое, вероятно, не то, что вы хотите.
Если вы хотите, чтобы макрос расширил форму в вызов format
, то вам нужно вернуть этот вызов в виде списка. Здесь мы используем quasiquote
построить список из шаблона, заполнив два значения: name
а также value
,
(defmacro assign (name value)
`(format t "assigning ~A to ~A~%" ,name ,value))
Может быть, вы хотите процитировать имя:
(defmacro assign (name value)
`(format t "assigning ~A to ~A~%" ',name ,value))