Macros 宏观膨胀下特殊变量的行为

Macros 宏观膨胀下特殊变量的行为,macros,common-lisp,special-variables,Macros,Common Lisp,Special Variables,我关于宏观扩张的思维模式(显然是错误的)说,以下情况按顺序发生: 运行bot的宏扩展(将*foo*绑定到17),运行bar的宏扩展,它打印*foo*的当前值(即17),并返回表单(+1 1),该表单不是宏,宏扩展时间现已结束,最后计算表单(+1 1),并返回2 为什么我错了 有没有一种简单的方法可以实现我的目的?当REPL被告知评估(bot),它首先必须执行宏扩展。它调用宏扩展函数bot,这实际上意味着 FUZZ> (defvar *foo* nil) *FOO* FUZZ> (de

我关于宏观扩张的思维模式(显然是错误的)说,以下情况按顺序发生:

运行
bot
的宏扩展(将
*foo*
绑定到
17
),运行
bar
的宏扩展,它打印
*foo*
的当前值(即
17
),并返回表单
(+1 1)
,该表单不是宏,宏扩展时间现已结束,最后计算表单
(+1 1)
,并返回
2

为什么我错了


有没有一种简单的方法可以实现我的目的?

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

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
它返回
(bar)
,然后from
let
的绑定被解除。现在我们有了
(条)
bar
是一个宏,所以现在是进行下一轮宏扩展的时候了,这意味着

(let ((*foo* 17))
  `(bar))
它打印
foo:NIL
,并返回
(+1)

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

但是,如果你打算自己进行宏观扩张,一定要保留。在这种情况下,
baz
的更好定义是:

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

啊哈,所以我的错误是把
*foo*
的绑定看作一个动态变量,在宏扩展
(bar)
和(关键的)它依次变成的所有形式所花费的所有时间里都是有效的。事实上,一旦
(bar)
被返回,我们就完成了
*foo*
,正如约书亚所说的那样。。。
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
(defmacro baz (&environment env)
  (let ((*foo* 42))
    (macroexpand '(bar) env)))