Macros 使用标签+;defmacro中的macrolet

Macros 使用标签+;defmacro中的macrolet,macros,common-lisp,Macros,Common Lisp,我正在使用defmacro用commonlisp编写一种小型专用语言。我无法找到正确的反引号过程,使变量在顶级let语句中定义,在嵌套的macrolet中隐藏,并在嵌套的标签中返回,所有变量都指向同一个符号 下面是一些显示问题的小示例代码: (defmacro with-keylang (&body body) (let ((keyblank-size-x (gensym))) `(let ((,keyblank-size-x 42)) (labels ((ke

我正在使用defmacro用commonlisp编写一种小型专用语言。我无法找到正确的反引号过程,使变量在顶级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

如果我们完全展开代码(这里使用LispWorks中的Walk命令):


重新绑定
#:G19508
没有效果,也不能有。函数
keyblank-size-x
具有不同的词法绑定。这只是词法绑定的常见效果。

如果我们完全扩展代码(这里使用LispWorks中的Walk命令):


重新绑定
#:G19508
没有效果,也不能有。函数
keyblank-size-x
具有不同的词法绑定。这只是词法绑定的常见效果。

重新绑定变量没有效果,因为标签定义的函数具有不同的词法绑定。重新绑定变量没有效果,因为标签定义的函数具有不同的词法绑定。
(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))))))