Common lisp 如何在common lisp中将变量传递给宏?

Common lisp 如何在common lisp中将变量传递给宏?,common-lisp,Common Lisp,对于一个程序,我试图使用这样的宏来简化下游代码,避免重复相同的代码: (defmacro destructure (values &body body) `(let* ((other-values (rest values)) (age (getf other-values :age)) (len (getf other-values :len)) (all (getf other-values :all))) (progn ,@(loo

对于一个程序,我试图使用这样的宏来简化下游代码,避免重复相同的代码:

(defmacro destructure (values &body body)
  `(let* ((other-values (rest values))
      (age (getf other-values :age))
      (len (getf other-values :len))
      (all (getf other-values :all)))
     (progn ,@(loop for e in body collect `(,@e)))))
它应该使用如下列表:

'(name :age 1 :len 2 :all '(1 2 3 4 5))
我的想法是我应该能够运行以下代码:

(destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
    (type-of age)
    (first all))
或者,使用变量,如下所示:

(setf *values* '(name :age 1 :len 2 :all '(1 2 3 4 5)))
(destructure *values*
    (type-of age)
    (first all))
而不是每次都要访问不同的元素。当然,这是一个简化的例子,但我要研究的是现实,这个列表要长得多

我发现要做到这一点非常困难。基本上,上面的代码不起作用,除非我通过设置一个全局变量值来保存我的列表进行欺骗,因为宏正在这样处理符号值,而没有扩展它应该指向的列表

另一方面,我不能使用常规函数,因为我在体内传递的指令会立即执行,但我必须将它们放在let中


我对这门语言还很陌生,我相信我可能错过了一些东西,也许有一种方法可以做到这一点。是否存在?

您需要计算宏中的变量值:

? (defmacro destructure (values &body body)
    `(let* ((other-values (rest ,values))
            (age (getf other-values :age))
            (len (getf other-values :len))
            (all (getf other-values :all)))
       (progn ,@body)))
DESTRUCTURE
? (destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
    (print (type-of age))
    (print (first all)))
;Compiler warnings :
;   In an anonymous lambda form at position 0: Unused lexical variable LEN

BIT 
QUOTE 
QUOTE
数据中的报价不是您想要的。引用的数据不需要内部引用

? (destructure '(name :age 1 :len 2 :all (1 2 3 4 5))
    (print (type-of age))
    (print (first all)))
;Compiler warnings :
;   In an anonymous lambda form at position 0: Unused lexical variable LEN

BIT 
1 
1
它也适用于一个变量:

? (let ((values '(name :age 1 :len 2 :all (1 2 3 4 5))))
    (destructure values
      (print (type-of age))
      (print (first all))))

;Compiler warnings :
;   In an anonymous lambda form at position 59: Unused lexical variable LEN

BIT 
1 
1
? 
您还可以将这三个变量声明为可忽略的。这将使上述警告静音

要修复什么

变量“其他值”在主体中可见。
您需要计算宏中的values变量:

? (defmacro destructure (values &body body)
    `(let* ((other-values (rest ,values))
            (age (getf other-values :age))
            (len (getf other-values :len))
            (all (getf other-values :all)))
       (progn ,@body)))
DESTRUCTURE
? (destructure '(name :age 1 :len 2 :all '(1 2 3 4 5))
    (print (type-of age))
    (print (first all)))
;Compiler warnings :
;   In an anonymous lambda form at position 0: Unused lexical variable LEN

BIT 
QUOTE 
QUOTE
数据中的报价不是您想要的。引用的数据不需要内部引用

? (destructure '(name :age 1 :len 2 :all (1 2 3 4 5))
    (print (type-of age))
    (print (first all)))
;Compiler warnings :
;   In an anonymous lambda form at position 0: Unused lexical variable LEN

BIT 
1 
1
它也适用于一个变量:

? (let ((values '(name :age 1 :len 2 :all (1 2 3 4 5))))
    (destructure values
      (print (type-of age))
      (print (first all))))

;Compiler warnings :
;   In an anonymous lambda form at position 59: Unused lexical variable LEN

BIT 
1 
1
? 
您还可以将这三个变量声明为可忽略的。这将使上述警告静音

要修复什么

变量“其他值”在主体中可见。
首先,对于您的问题,您可以使用解构绑定:

现在,关于代码的一些注释:

您已将对值的引用放在反引号内,因此它不是对宏参数的引用,而是对某些外部变量名为值的扩展形式的自由引用。你可能想做的是:

(defmacro destructure (values &body body)
  `(let* ((other-values ,(rest values)))
          (age (getf other-values :age))
          (len (getf other-values :len))
          (all (getf other-values :all)))
     …))
这有一个问题,因为它会从宏调用窗体外部隐藏任何名为其他值的变量。您应该使用gensyms来避免以下情况:

(defmacro destructure (values &body body)
  (let ((other-values (gensym "other-values")))
    `(let* ((,other-values ,(rest values)))
            (age (getf other-values :age))
            (len (getf other-values :len))
            (all (getf other-values :all)))
       …))
有关代码模板的说明:

(progn ,@(loop for e in body collect `(,@e))
简化为

(progn ,@(loop for e in body collect e))
(progn ,@body)
简化为

(progn ,@(loop for e in body collect e))
(progn ,@body)
由于let的主体已经是一个隐式程序:

最后,您的示例数据:

(name :age 1 :len 2 :all '(1 2 3 4 5))
实际上是:

(name :age 1 :len 2 :all (quote (1 2 3 4 5)))

读者总是将“引用”扩展为引用形式。嵌套报价单表单时,您几乎总是出错。

首先,对于您的问题,您可以使用解构绑定:

现在,关于代码的一些注释:

您已将对值的引用放在反引号内,因此它不是对宏参数的引用,而是对某些外部变量名为值的扩展形式的自由引用。你可能想做的是:

(defmacro destructure (values &body body)
  `(let* ((other-values ,(rest values)))
          (age (getf other-values :age))
          (len (getf other-values :len))
          (all (getf other-values :all)))
     …))
这有一个问题,因为它会从宏调用窗体外部隐藏任何名为其他值的变量。您应该使用gensyms来避免以下情况:

(defmacro destructure (values &body body)
  (let ((other-values (gensym "other-values")))
    `(let* ((,other-values ,(rest values)))
            (age (getf other-values :age))
            (len (getf other-values :len))
            (all (getf other-values :all)))
       …))
有关代码模板的说明:

(progn ,@(loop for e in body collect `(,@e))
简化为

(progn ,@(loop for e in body collect e))
(progn ,@body)
简化为

(progn ,@(loop for e in body collect e))
(progn ,@body)
由于let的主体已经是一个隐式程序:

最后,您的示例数据:

(name :age 1 :len 2 :all '(1 2 3 4 5))
实际上是:

(name :age 1 :len 2 :all (quote (1 2 3 4 5)))

读者总是将“引用”扩展为引用形式。嵌套报价表时,您几乎总是出错。

相关:一个好的开始是手动编写宏的扩展。相关:一个好的开始是手动编写宏的扩展。感谢您的完整解释,这是我的一些食物,我在过去的一个小时里主要是研究和玩耍,让一切都融入其中。最后,我决定使用一个宏来包装一个解构绑定,这样最终的代码就更清晰了,因为宏的名称在程序中是有意义的。真的,谢谢你。谢谢你的完整解释,虽然这是我的一些食物,但我花了过去的一个小时主要是研究和玩耍,让一切都融入其中。最后,我决定使用一个宏来包装一个解构绑定,这样最终的代码就更清晰了,因为宏的名称在程序中是有意义的。真的,谢谢你。