4

为什么这些表格会这样?

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 将循环宏重新设计为一个版本,我期望的是返回的内容:

(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-用户>

循环宏版本是怎么回事?

4

2 回答 2

8

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

采用

(setf *closures*
  (loop for num in (list 1 2 3 4)
        collect (let ((num1 num))
                  (lambda ()
                    num1))))

num1是每次迭代的新鲜变量。

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.

于 2013-03-30T04:20:29.227 回答
4

The name num represents the same binding during the evaluation of LOOP. Maybe you want to write:

(mapcar 'constantly (list 1 2 3 4))

to get what you meant.

于 2013-03-30T10:12:11.143 回答