普通Lisp循环 [英] Common Lisp Loop

查看:110
本文介绍了普通Lisp循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下循环中:

(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:

dotimes是否在每次迭代中建立新的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|)))

以上是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:

It is implementation-dependent whether dotimes 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.

you write:

i would intuitively think i would get a list of four closures which return the numbers 0 1 2 and 3 upon being called

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循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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