3
FUZZ> (defvar *foo* nil)
*FOO*
FUZZ> (defmacro bar ()
        (format t "foo: ~A" *foo*)
        `(+ 1 1))
BAR
FUZZ> (defmacro bot ()
        (let ((*foo* 17))
          `(bar)))
BOT
FUZZ> (bot)
foo: NIL

我的宏观扩展心智模型(显然是错误的)说以下是按顺序发生的:

运行bot( 绑定*foo*17) 的宏扩展,运行 的宏扩展,打印(being )bar的当前值,并返回不是宏的表单,宏扩展时间现在结束,最后评估表单,并返回*foo*17(+ 1 1)(+ 1 1)2

为什么我错了?

有没有一种简单的方法来做我想做的事?

4

1 回答 1

5

当 REPL 被告知要评估(bot)时,它首先必须执行宏扩展。它调用宏扩展函数bot,这实际上意味着评估

(let ((*foo* 17))
  `(bar))

返回(bar),然后let解除 from 的绑定。现在我们有了(bar). bar是一个宏,所以是时候进行另一轮宏扩展了,这意味着评估

(progn 
  (format t "foo: ~a" *foo*)
  `(+ 1 1))

打印foo: NIL并返回(+ 1 1)

如果您希望在某些绑定的范围内执行宏扩展,则需要自己调用宏扩展函数。例如,您可以使用macroexpand

CL-USER> (defparameter *foo* nil)
*FOO*
CL-USER> (defmacro bar ()
           (format t "foo: ~a" *foo*)
           `(+ 1 1))
BAR
CL-USER> (defmacro baz ()
           (let ((*foo* 42))
             (macroexpand '(bar))))
BAZ
CL-USER> (baz)
foo: 42
2

但是,如果您要自己进行宏扩展,请务必保留环境参数。在这种情况下,更好的定义baz是:

(defmacro baz (&environment env)
  (let ((*foo* 42))
    (macroexpand '(bar) env)))
于 2014-11-21T03:46:29.847 回答