为什么在编译函数定义时会对宏进行求值(Clozure Common Lisp)?

时间:2017-05-15 07:14:48

标签: common-lisp ccl lisp-macros

我有:

(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))

当我编译操作码调用时,REPL输出:

assigning VAR to ARG
OPCODE-CALL

为什么要在编译时评估分配?

1 个答案:

答案 0 :(得分:5)

宏是功能。他们通过参数获取代码并返回新代码。宏可能有副作用。

您的代码在宏扩展期间打印出一些副作用并返回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模板构建列表,填写两个值:namevalue

(defmacro assign (name value)
  `(format t "assigning ~A to ~A~%" ,name ,value))

也许你想引用这个名字:

(defmacro assign (name value)
  `(format t "assigning ~A to ~A~%" ',name ,value))