Macros 写入“循环”时出现的问题。。。宏中的collect`
伙计们 今天我想写sigma宏来计算灵活表达式输入的和 下面的代码是我今天下午编写的。但这不符合我的目的Macros 写入“循环”时出现的问题。。。宏中的collect`,macros,lisp,common-lisp,clisp,Macros,Lisp,Common Lisp,Clisp,伙计们 今天我想写sigma宏来计算灵活表达式输入的和 下面的代码是我今天下午编写的。但这不符合我的目的 (defmacro sigma (exp ll) `(+ ,@(loop for i in ll collect (progn (setf (elt exp 1) i) (print exp) exp))) ) >>(pprint (macroexpand-1 '(
(defmacro sigma (exp ll)
`(+ ,@(loop for i in ll collect
(progn (setf (elt exp 1) i)
(print exp)
exp)))
)
>>(pprint (macroexpand-1 '(sigma (+ 1 2) (2 3 4))))
>>(+ 2 2)
(+ 3 2)
(+ 4 2)
(+ (+ 4 2) (+ 4 2) (+ 4 2))
我希望它能工作(+(+22)(+32)(+42))
但是循环收集
给我一个奇怪的答案
为什么它是这样工作的?我有一些方法来解决这个问题吗?您正在修改文字数据(引用)。如果您同意在该循环期间,列表
(+12)
,绑定到exp,在每次迭代中都是相同的,并且在每次迭代中都会对第二个元素进行变异。很容易想象,一个已经收集了相同列表exp
3次的列表将有3个与第二个元素的最后一次变异完全相同的元素
这绝不是宏中的一项功能。对所有引用的数据进行变异可以产生这样的结果。标准规定结果将是未定义的,因此没有实现者需要解决这个问题,并且您可以从特定实现的其他方面获得意外行为
编译后的文件可能会将所有引用的数据连接在一起,成为一个相同的数据,这样代码中的其他位置也可能受到此宏的影响
要解决此问题,请不要突变:
(defmacro sigma ((op r &rest rest) ll)
`(+ ,@(loop :for i :in ll
:collect (list* op i rest))))
(macroexpand-1 '(sigma (+ 1 2) (2 3 4)))
; ==> (+ (+ 2 2) (+ 3 2) (+ 4 2))
这样做的好处是保证模板中至少有两个参数
(macroexpand-1 '(sigma (x) (2 3 4)))
; ==> *** - SIGMA: (X) does not match lambda list element (OP R &REST REST)
如果您想要一份新消耗的列表,那么
复制列表
是一种方法:
(defmacro sigma (exp ll)
`(+ ,@(loop for i in ll and exp1 = (copy-list exp)
do (setf (second exp1) i)
collect exp1)))
也可以使用嵌套的反引号表达式:
(defmacro sigma ((op arg0 &rest args) ll)
(declare (ignore arg0))
`(+ ,@(loop for i in ll collect `(,op ,i ,@args))))
即使他没有对它进行变异,他每次都通过循环收集相同的
exp
对象。@Barmar我记得我有一次ncoc
-对同一个参数进行了两次修改,得到了一个双倍大小的列表:-)