循环宏和闭包的异常行为 [英] Unexpected behavior with loop macro and closures

查看:79
本文介绍了循环宏和闭包的异常行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这些表格会这样?

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.

这篇关于循环宏和闭包的异常行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆