我正在使用 defmacro 在 Common Lisp 中编写一种小型专用语言。我无法找出正确的反引号过程来在顶级 let 语句中定义一个变量,在嵌套的宏中隐藏,并在嵌套的标签中返回,所有这些都指向同一个符号。
这是一些显示问题的小示例代码:
(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