ccQ*_*ein 2 lisp macros clisp common-lisp
家伙.
今天我想编写sigma宏来计算灵活表达式输入的总和.
下面的代码是我今天下午写的.但它不符合我的目的.
(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))
Run Code Online (Sandbox Code Playgroud)
我希望它有效,(+ (+ 2 2) (+ 3 2) (+ 4 2))
但loop collect
给我一个奇怪的答案.
它为什么这样工作?我有一些方法可以解决这个问题吗?
您正在改变文字数据(引用).如果您同意在该循环期间(+ 1 2)
,绑定到exp 的列表在每次迭代中是相同的,并且您在每次迭代中改变第二个元素,则很容易想象已经收集相同列表exp
3次的列表将具有3个完全相同的列表与第二个元素的最后一个突变相同的元素.
这绝不是宏中的一个特性.对所有引用数据进行变异可以产生这样的结果.标准规定结果将是未定义的,因此没有实现者需要解决这个问题,并且您会从特定实现的其他方面获得意外行为.
编译后的文件可能会将所有引用的数据连接在一起,从而'(+ 1 2)
使代码中的其他位置也可能受到此宏的影响.
要解决这个问题,请不要改变:
(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))
Run Code Online (Sandbox Code Playgroud)
关于这一点的好处是保证模板中至少有两个参数.
(macroexpand-1 '(sigma (x) (2 3 4)))
; ==> *** - SIGMA: (X) does not match lambda list element (OP R &REST REST)
Run Code Online (Sandbox Code Playgroud)