Common Lisp中的动态变量闭包(SBCL)

时间:2016-06-25 12:21:17

标签: scope lisp common-lisp sbcl

我理解这段代码的工作原理:

(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

闭包的概念不适用于动态绑定变量,还是我做错了什么?如果我错误地理解了闭包的概念,有人可以向我解释一下吗?

2 个答案:

答案 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 的主体中没有自由变量。