Common Lisp中macroexpand-1与macrolet的异常交互问题咨询
全局宏与局部宏的展开差异原因
首先明确两个宏定义的核心区别:
defmacro定义的是全局宏,它的绑定会被加入全局宏环境,任何位置都能识别并展开它。macrolet定义的是局部词法宏,它的绑定仅在macrolet的体内部生效,且仅存在于编译阶段的词法环境中。
为什么两次macroexpand-1的结果不同?
全局宏的展开逻辑
对于(macroexpand-1 '(double-g 3)),double-g是全局宏,macroexpand-1默认会在全局宏环境中查找定义,因此能成功展开为(+ 3 3),并返回T表示展开成功。局部宏的展开逻辑
看这段代码:(macrolet ((double-l (x) (list '+' x x))) (macroexpand-1 '(double-l 3)))问题出在
'(double-l 3)这个被quote包裹的形式:quote会阻止编译期的宏展开,把(double-l 3)变成一个字面量列表。- 当运行时调用
macroexpand-1时,它默认使用的是全局宏环境,而double-l是局部宏,其绑定只存在于编译期的词法环境中,运行时已经不存在这个绑定了。因此macroexpand-1找不到double-l的宏定义,只能返回原形式(DOUBLE-L 3)和NIL表示未展开。
如何让局部宏被macroexpand-1正确展开?
如果要在macrolet体内让macroexpand-1识别局部宏,需要传入当前的词法环境变量*lexical-environment*,修改后的代码如下:
(macrolet ((double-l (x) (list '+' x x))) (macroexpand-1 '(double-l 3) *lexical-environment*))
在SBCL中执行这段代码会返回(+ 3 3), T,因为macroexpand-1会在传入的词法环境中查找局部宏的绑定。
内容的提问来源于stack exchange,提问作者Zachary Benavides
相关产品推荐
相关产品推荐

