Why does this defun closure not behave the same as the defparameter closure?

有些话、适合烂在心里 提交于 2019-12-11 07:26:07

问题


Consider these two:

(defparameter *lfn*
  (let ((count 0))
    #'(lambda ()
    (incf count))))

(defun testclosure ()
    (let ((count 0))
      #'(lambda ()
      (incf count))))

Why do they behave differently:

CL-USER> (funcall (testclosure))
1
CL-USER> (funcall (testclosure))
1
CL-USER> (funcall *lfn*)
1
CL-USER> (funcall *lfn*)
2

count is closed over in the defparameter version but not in the defun version. Why is this?


回答1:


Sylwester's answer explains this very well, but in a case an example with more explicit side effects makes this any clearer, consider:

CL-USER> (defparameter *foo* (progn (print 'hello) 0))
HELLO 
*FOO*
CL-USER> *foo*
0
CL-USER> *foo*
0

In defining *foo*, the (progn (print 'hello) 0) is evaluated once, so hello is printed, and the value is 0, which becomes the value of *foo*. Evaluating *foo* later just means looking up *foo*'s value (0), not reëvaluating the form that produced its original value. In contrast, consider calling a function whose body is(progn (print 'hello) 0)`:

CL-USER> (defun foo () (progn (print 'hello) 0))
FOO
CL-USER> (foo)
HELLO 
0
CL-USER> (foo)
HELLO 
0
CL-USER> (foo)
HELLO 
0

Each time foo is called, (progn (print 'hello) 0) is evaluated, so hello is printed and 0 is returned. After seeing this example, your code should be a bit clearer.

(defparameter *lfn*
  (let ((count 0))
    #'(lambda ()
    (incf count))))

(let ...) is evaluated once, and the closure that that evaluation produces its the value of *lfn*. On the other hand, in

(defun testclosure ()
    (let ((count 0))
      #'(lambda ()
      (incf count))))

(let ...) is evaluated every time that testclosure is called, a new closure is returned each time.




回答2:


When you are making *lfn* you are creating a function within one closure.. Calling it will increase the closed over count and evaluate to it.

testclosure does the same as what you did with *lfm* for every time it gets called. Thus:

(defparameter *lfn2* (testclosure))
(funcall *lfn2*) ; ==> 1
(funcall *lfn2*) ; ==> 2
(funcall *lfn2*) ; ==> 3

Will make exactly the same as *lfn* such that consecutive calls to it will increase the value returned. However

(funcall (testclosure)) ; ==> 1 (and the closure can be recycled)
(funcall (testclosure)) ; ==> 1 (and the closure can be recycled)

Here you are doing funcall on a newly created closure, that you don't store for consecutive calls, so it will return 1. Then you are doing funcall again on a completely new closure that you also don't store and it's first call also evaluates to 1.

So the answer is, count is closed over in both, but in you example you were creating a new closure and using it only once, several times.




回答3:


The value of *lfn* is a closure.

The function testclosure returns a new closure each time you call it.



来源:https://stackoverflow.com/questions/19919918/why-does-this-defun-closure-not-behave-the-same-as-the-defparameter-closure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!