Common lisp 循环宏和闭包的意外行为
为什么这些表单会有这样的行为Common lisp 循环宏和闭包的意外行为,common-lisp,Common Lisp,为什么这些表单会有这样的行为 CL-USER> (setf *closures* (loop for num in (list 1 2 3 4) collect (lambda () num))) ( #<COMPILED-LEXICAL-CLOSURE #x302004932E1F> #<COMPILED-LEXICAL-CLOSURE #x302004932DCF> #&l
CL-USER>
(setf *closures*
(loop for num in (list 1 2 3 4)
collect (lambda ()
num)))
(
#<COMPILED-LEXICAL-CLOSURE #x302004932E1F>
#<COMPILED-LEXICAL-CLOSURE #x302004932DCF>
#<COMPILED-LEXICAL-CLOSURE #x302004932D7F>
#<COMPILED-LEXICAL-CLOSURE #x302004932D2F>)
CL-USER>
(funcall (first *closures*))
4
CL-USER>
(funcall (second *closures*))
4
CL-USER>
(setf*关闭*
(列表1 2 3 4中的num循环)
收集(λ()
num)))
(
#
#
#
#)
CL-USER>
(funcall(第一个*闭包*)
4.
CL-USER>
(funcall(第二个*闭包*)
4.
我希望第一个funcall返回1,第二个funcall返回2,以此类推。此行为与Clozure Common Lisp和Steel Bank Common Lisp实现一致
如果我使用dolist将循环宏返工为一个版本,我希望得到的是返回的内容:
(setf *closures*
(let ((out))
(dolist (item (list 1 2 3 4) (reverse out))
(push (lambda () item) out))))
(
#<COMPILED-LEXICAL-CLOSURE #x302004A12C4F>
#<COMPILED-LEXICAL-CLOSURE #x302004A12BFF>
#<COMPILED-LEXICAL-CLOSURE #x302004A12BAF>
#<COMPILED-LEXICAL-CLOSURE #x302004A12B5F>)
CL-USER>
(funcall (first *closures*))
1
CL-USER>
(funcall (second *closures*))
2
(setf*闭包)*
(放((出去))
(dolist(项目(清单1、2、3、4)(反向输出))
(推出(lambda()项)))
(
#
#
#
#)
CL-USER>
(funcall(第一个*闭包*)
1.
CL-USER>
(funcall(第二个*闭包*)
2.
CL-USER>
循环宏版本是怎么回事?
num
是所有lambda共享的同一个变量
使用
num1
是每个迭代的新变量
截至
dolist
,“dolist是在每次迭代中建立新的var绑定,还是在开始时为var建立一次绑定,然后在任何后续迭代中分配,这取决于实现。”(CLHS,宏dolist)。因此,它可能在一个实现上工作,而在另一个实现上失败。名称num
表示循环求值期间的相同绑定。
也许你想写:
(mapcar 'constantly (list 1 2 3 4))
为了理解你的意思。顺便说一句,你可以把
num1
命名为num
;)(let((num num))…)我以前使用过:(defmacro rebind(vars和body body)`(let,(mapcar#list vars vars),@body))
这适用于这里的简化示例,但不适用于实际用例,我需要在循环构造中收集词汇闭包。@ClaytonStanley-Hmm,实际上,您可以不断地将替换为(lambda(idx)…
,并将(列表…
)替换为(亚历山大:物联网…
)。如果有更多的迭代变量,您可以添加更多的列表。实际上,这是FP方式,所以如果循环中没有状态改变,您可以始终使用它。。。
(mapcar 'constantly (list 1 2 3 4))