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

Почему assign оценивается во время компиляции?


person Capstone    schedule 15.05.2017    source источник
comment
Макросы всегда расширяются перед компиляцией, поэтому скомпилированный код включает только расширение. Если вы не хотите, чтобы ваш макрос печатал вывод во время макрорасширения, вам нужно вернуть форму (format ...) вместо ее оценки (поставьте перед ней обратную кавычку и удалите две имеющиеся у вас (которые в любом случае ничего не делают в данный момент)) .   -  person jkiiski    schedule 15.05.2017


Ответы (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))
person Rainer Joswig    schedule 15.05.2017