我理解这段代码的工作原理:
(defvar *nums* '(2 3 5))
(defun print-nums ()
(format t "~a~%" *nums*))
(print-nums)
-> (2 3 5)
-> NIL
我甚至理解动态绑定变量*nums*
的新值如何在此代码中传递给print-nums
:
(let ((*nums* '(1 2 3)))
(print-nums))
-> (1 2 3)
-> NIL
但为什么以下代码的工作方式不同?
(defvar *my-nums-f* (let ((*nums* '(1 2 3)))
#'(lambda () (format t "~a~%" *nums*))))
(funcall *my-nums-f*)
-> (2 3 5)
-> NIL
闭包的概念不适用于动态绑定变量,还是我做错了什么?如果我错误地理解了闭包的概念,有人可以向我解释一下吗?
答案 0 :(得分:3)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Check all</label>
<input type="checkbox" class="checkAll" />
<br/><br/>
<input type="checkbox" class="checkbox1" />
<input type="checkbox" class="checkbox1" />
<input type="checkbox" class="checkbox1" />
<input type="checkbox" class="checkbox1" />
这里我们将(defvar *my-nums-f* (let ((*nums* '(1 2 3)))
#'(lambda () (format t "~a~%" *nums*))))
设置为
*my-nums-f*
此表单首先动态绑定(let ((*nums* '(1 2 3)))
#'(lambda () (format t "~a~%" *nums*)))
到*nums*
,然后返回'(1 2 3)
,这是一个函数。最后,我们将#'(lambda () (format t "~a~%" *nums*))
重置为*nums*
。
'(2 3 5)
我们在此调用存储在(funcall *my-nums-f*)
中的函数,即*my-nums-f*
。此函数采用(lambda () (format t "~a~%" *nums*))
的当前值,即*nums*
。
'(2 3 5)
您似乎期望-> (2 3 5)
-> NIL
以某种方式内联函数体中使用的所有变量的当前值,这确实会在此时产生lambda
。
但这不是它的工作方式:函数指的是变量本身,而不是变量值的shapshot。这就是为什么函数在调用时会看到(format t "~a~%" '(1 2 3))
的当前值的原因。
答案 1 :(得分:0)
这是另一个模拟动态变量的外观。假设 NUMS 是在调用 BAR 之前绑定到 '(2 3 5) 的动态变量。 NUMS 在 lambda 中是免费的,并且已关闭。但是,在 lambda 返回之前,NUMS 会反弹。当动态 var 脱离将新绑定推送到其小值堆栈的词法范围时,就会发生这种情况。
(defun bar ()
(let ((nums '(1 2 3)))
(prog1
(lambda () nums)
(setf nums '(2 3 5)))))
SBCL 会告诉你它是否已经创建了一个闭包:#<FUNCTION ...>
vs #<CLOSURE ...>
。您的代码不会创建闭包,因为 lambda 的主体中没有自由变量。