在以下循环中:
(let ((funs (loop for i upto 3 do (print i) collect #'(lambda () i))))
(loop for fun in funs collect (funcall fun)))
Run Code Online (Sandbox Code Playgroud)
我直觉地认为我会得到一个包含四个闭包的列表,它们在被调用时返回数字 0 1 2 和 3,但这就是我得到的:
>> 0
>> 1
>> 2
>> 3
=> (4 4 4 4)
Run Code Online (Sandbox Code Playgroud)
但是将i本地重新绑定到其他东西:
(let ((funs (loop for i upto 3 do (print i) collect (let ((x i))
#'(lambda () x)))))
(loop for fun in funs collect (funcall fun)))
Run Code Online (Sandbox Code Playgroud)
按预期工作:
>> 0
>> 1
>> 2
>> 3
=> (0 1 2 3)
Run Code Online (Sandbox Code Playgroud)
所以每个函数都返回 4,为什么所有返回值都相同,为什么是 4?
更新
这实际上似乎是一个关于 lambda 的问题。见下文:
(setq dynamic-var 8
funs ())
(push (lambda () dynamic-var) funs)
(incf dynamic-var)
(push (lambda () dynamic-var) funs)
(mapcar #'funcall funs) ;(9 9)
Run Code Online (Sandbox Code Playgroud)
有什么作用
(let (i ; a counter variable
f) ; a list of functions
(setf i 1)
(push (lambda () i) f)
(setf i 2)
(push (lambda () i) f)
(mapcar #'funcall f))
Run Code Online (Sandbox Code Playgroud)
返回?
怎么样:
(let (i
f)
(setf i 1)
(push (lambda () i) f)
(let (i)
(setf i 2)
(push (lambda () i) f))
(mapcar #'funcall f))
Run Code Online (Sandbox Code Playgroud)
哪个是LOOP型号?
也可以看看:
CL-USER 42 > (let (f)
(dotimes (i 10 (mapcar #'funcall (reverse f)))
(push (lambda () i) f)))
(10 10 10 10 10 10 10 10 10 10)
CL-USER 43 > (let (f)
(dotimes (i 10 (mapcar #'funcall (reverse f)))
(push (let ((i i))
(lambda () i))
f)))
(0 1 2 3 4 5 6 7 8 9)
Run Code Online (Sandbox Code Playgroud)
Common Lisp 标准说DOTIMES:
dotime 是在每次迭代时建立新的 var 绑定,还是在开始时为 var 建立一次绑定,然后在任何后续迭代中分配它,这取决于实现。
你写:
我直觉地认为我会得到一个包含四个闭包的列表,它们在被调用时返回数字 0 1 2 和 3
这种直觉只是部分正确。你会得到四个闭包,但在这种情况下,它们都共享一个变量绑定。因此他们只能看到这个变量的当前绑定。在 Common Lisp 中,这个绑定是可变的,闭包看到的是当前绑定,而不是闭包创建时的初始绑定之一。
当每个闭包都有自己的变量绑定时,您的直觉是正确的。
附加答案:为什么这个 Lisp 返回 10 ?
(PROGN
(SETQ I (THE INTEGER (1+ (THE INTEGER I))))
(WHEN (>= (THE INTEGER I)
(THE INTEGER #:|dotimes-count-1075|))
(GO #:|dotimes-end-tag1080|)))
Run Code Online (Sandbox Code Playgroud)
以上是dotimes构造宏展开的一部分。如您所见,它首先增加变量,然后测试>=. 因此退出时I是>=10。因此的最后一个值I就是10。稍后退出后,dotimes您将检索 的值,I然后是10。