问题描述
为什么这些表格会这样?
Why do these forms behave this way?
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
我会预期第一个funcall返回1,第二个返回2,依此类推。此行为与Clozure Common Lisp和Steel-Bank Common Lisp实现都是一致的。
I would have expected the first funcall to return 1, and the second to return 2, etc. This behavior is consistent with both Clozure Common Lisp and Steel-Bank Common Lisp implementations.
如果我使用dolist将循环宏重新制作为一个版本,我期望返回的内容是:
If I rework the loop macro to a version using dolist, what I'd expect is what's returned:
(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
CL-USER >
CL-USER>
循环宏版本是怎么回事?
What's going on with the loop macro version?
推荐答案
num
是所有lambda共享的相同变量。
num
is same variable shared by all lambdas.
使用
(setf *closures*
(loop for num in (list 1 2 3 4)
collect (let ((num1 num))
(lambda ()
num1))))
num1
是每次迭代的新变量。
num1
is fresh variable for each iteration.
从 dolist
开始,这是实现-取决于dolist是在每次迭代中建立var的新绑定还是在开始时为var建立一次绑定,然后在任何后续迭代中将其分配。 (CLHS,宏DOLIST)。因此它可能在一种实现上起作用,而在另一种实现上失败。
As of dolist
, "It is implementation-dependent whether dolist establishes a new binding of var on each iteration or whether it establishes a binding for var once at the beginning and then assigns it on any subsequent iterations." (CLHS, Macro DOLIST). So it may work on one implementation and fail on other.
这篇关于循环宏和闭包的异常行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!