首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >循环宏和闭包的意外行为

循环宏和闭包的意外行为
EN

Stack Overflow用户
提问于 2013-03-30 11:12:34
回答 2查看 260关注 0票数 4

为什么这些表单会有这样的行为?

代码语言:javascript
复制
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实现都是一致的。

如果我使用dolist将循环宏重做为一个版本,我期望的是返回的结果:

代码语言:javascript
复制
(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-用户>

循环宏版本是怎么回事?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-30 12:20:29

num是所有lambda共享的相同变量。

使用

代码语言:javascript
复制
(setf *closures*
  (loop for num in (list 1 2 3 4)
        collect (let ((num1 num))
                  (lambda ()
                    num1))))

num1是每次迭代的新变量。

对于dolist,“dolist是在每次迭代中建立新的var绑定,还是在开始时为var建立一次绑定,然后在任何后续迭代中分配它,这取决于实现。”(CLHS,Macro DOLIST)因此,它可能在一个实现上工作,而在另一个实现上失败。

票数 8
EN

Stack Overflow用户

发布于 2013-03-30 18:12:11

在计算循环的过程中,名称num表示相同的绑定。也许你想这样写:

代码语言:javascript
复制
(mapcar 'constantly (list 1 2 3 4))

才能明白你的意思。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15714537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档