Почему макрос оценивается при компиляции определения функции (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))
Другие вопросы по тегам