问题描述
在以下循环中:
(let ((funs (loop for i upto 3 do (print i) collect #'(lambda () i))))
(loop for fun in funs collect (funcall fun)))
我会直觉上认为我会得到四个闭包的列表,这些闭包在被调用时会返回数字0 1 2和3,但这就是我得到的:
>> 0
>> 1
>> 2
>> 3
=> (4 4 4 4)
但是在本地将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)))
按预期工作:
>> 0
>> 1
>> 2
>> 3
=> (0 1 2 3)
每个函数都返回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)
做什么
(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))
返回?
怎么样:
(let (i
f)
(setf i 1)
(push (lambda () i) f)
(let (i)
(setf i 2)
(push (lambda () i) f))
(mapcar #'funcall f))
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)
Common Lisp标准表示DOTIMES
:
您写:
这种直觉只是部分正确.您有四个闭包,但是在这种情况下,它们都共享一个变量绑定.因此,他们只能看到此变量的当前绑定.在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|)))
以上是dotimes
构造宏扩展的一部分.如您所见,它首先递增变量,然后测试>=
.因此,当I
为>=
10时退出.因此,I
的最后一个值为10
.退出dotimes
之后,您将检索I
的值,然后是10
.
In the following loop:
(let ((funs (loop for i upto 3 do (print i) collect #'(lambda () i))))
(loop for fun in funs collect (funcall fun)))
i would intuitively think i would get a list of four closures which return the numbers 0 1 2 and 3 upon being called, but this is what i get:
>> 0
>> 1
>> 2
>> 3
=> (4 4 4 4)
But rebinding the i
locally to something else:
(let ((funs (loop for i upto 3 do (print i) collect (let ((x i))
#'(lambda () x)))))
(loop for fun in funs collect (funcall fun)))
works as expected:
>> 0
>> 1
>> 2
>> 3
=> (0 1 2 3)
So each of the functions return 4, why are all return values the same, and why 4?
update
This seems to be a question about lambda actually. See below:
(setq dynamic-var 8
funs ())
(push (lambda () dynamic-var) funs)
(incf dynamic-var)
(push (lambda () dynamic-var) funs)
(mapcar #'funcall funs) ;(9 9)
What does
(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))
return?
How about:
(let (i
f)
(setf i 1)
(push (lambda () i) f)
(let (i)
(setf i 2)
(push (lambda () i) f))
(mapcar #'funcall f))
Which is the LOOP
model?
See also:
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)
The Common Lisp standard says for DOTIMES
:
you write:
This intuition is only partly correct. You get four closures, but in this case they all share one variable binding. Thus they can only see the current binding of this one variable. In Common Lisp this binding is mutable and closures see the current binding, not the one of the initial binding of closure creation time.
Your intuition would be right, when each closure had its own variable binding.
Additional answer: why is this Lisp returning 10 ?
(PROGN
(SETQ I (THE INTEGER (1+ (THE INTEGER I))))
(WHEN (>= (THE INTEGER I)
(THE INTEGER #:|dotimes-count-1075|))
(GO #:|dotimes-end-tag1080|)))
Above is a part of the macro expansion of the dotimes
construct. As you can see it first increments the variable and then tests for >=
. Thus it exits when I
is >=
10. Thus the last value of I
is 10
. Later after exiting the dotimes
you are retrieving the value of I
and then it's 10
.
这篇关于普通Lisp循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!