我正在使用defmacro在Common Lisp中编写一个小的专用语言。我无法弄清楚正确的反引用过程是在顶级let语句中定义一个变量,在嵌套的macrolet中隐藏,并在嵌套标签中返回,都指向相同的符号。
以下是一些显示问题的小示例代码:
(defmacro with-keylang (&body body)
(let ((keyblank-size-x (gensym)))
`(let ((,keyblank-size-x 42))
(labels ((keyblank-size-x ()
,keyblank-size-x))
(macrolet ((with-keyblank-size-x (size-x &body body)
`(let ((,',keyblank-size-x ,size-x))
,@body)))
,@body)))))
CL-USER>
(with-keylang
(print (keyblank-size-x)))
42
42
到目前为止一切都很顺利。
CL-USER>
(with-keylang
(with-keyblank-size-x 24
(print (keyblank-size-x))))
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable #:G123171
42
42
有问题。我希望代表keyblank-size-x的符号用值24进行阴影处理,但这不会发生。
我感觉,',
反引号模式不适合这种情况,因为这引用了代表keyblank-size-x的符号,因此不是eq。但是如果我尝试,,
,它就不起作用了,我得到了这个有趣的编译器错误:
While compiling WITH-KEYBLANK-SIZE-X :
Illegal reference to lexically defined variable #:G123192.
[Condition of type CCL::COMPILE-TIME-PROGRAM-ERROR]
编辑:
keyblank-size-x变量是词法范围的,我想要这个特殊情况的动态范围。所以这里是重写声明keyblank-size-x变量具有动态范围:
(defmacro with-keylang (&body body)
(let ((keyblank-size-x (gensym)))
`(let ((,keyblank-size-x 42))
(declare (special ,keyblank-size-x))
(labels ((keyblank-size-x ()
,keyblank-size-x))
(macrolet ((with-keyblank-size-x (size-x &body body)
`(let ((,',keyblank-size-x ,size-x))
(declare (special ,',keyblank-size-x))
,@body)))
,@body)))))
测试代码:
CL-USER>
(with-keylang
(with-keyblank-size-x 25
(with-keyblank-size-x 21
(print (keyblank-size-x)))
(print (keyblank-size-x)))
(print (keyblank-size-x)))
21
25
42
42
答案 0 :(得分:4)
如果我们完全展开代码(这里使用LispWorks中的Walk命令):
(LET ((#:G19508 42))
(LABELS ((KEYBLANK-SIZE-X () #:G19508))
(MACROLET ((WITH-KEYBLANK-SIZE-X (SIZE-X &BODY BODY)
`(LET ((#:G19508 ,SIZE-X))
,@BODY)))
(LET ((#:G19508 24))
(PRINT (KEYBLANK-SIZE-X))))))
重新绑定#:G19508
无效,无法生效。函数keyblank-size-x
具有不同的词法绑定。这只是词汇绑定的常见效果。