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

ˆᵛˆ*_*ˆᵛˆ 0 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))
Run Code Online (Sandbox Code Playgroud)

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

assigning VAR to ARG
OPCODE-CALL
Run Code Online (Sandbox Code Playgroud)

为什么在编译时对赋值进行求值?

Rai*_*wig 5

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

您的代码在宏扩展期间打印出一些副作用并返回NIL(调用该FORMAT函数的结果).

(defmacro assign (name value)
  (format t "assigning ~A to ~A~%" `,name `,value))
Run Code Online (Sandbox Code Playgroud)

使用它:

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
Run Code Online (Sandbox Code Playgroud)

引用这些论点是没有意义的.代码等同于:

(defmacro assign (name value)
  (format t "assigning ~A to ~A~%" name value))
Run Code Online (Sandbox Code Playgroud)

它仍然NIL作为扩展返回,这可能不是你想要的.

如果您希望宏将表单扩展为调用format,则需要将该调用作为列表返回.这里我们用来quasiquote模板构造一个列表,填入两个值:namevalue.

(defmacro assign (name value)
  `(format t "assigning ~A to ~A~%" ,name ,value))
Run Code Online (Sandbox Code Playgroud)

也许你想引用这个名字:

(defmacro assign (name value)
  `(format t "assigning ~A to ~A~%" ',name ,value))
Run Code Online (Sandbox Code Playgroud)