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

sha*_*ica 3 lisp scope sbcl common-lisp

我了解此代码的工作原理:

(defvar *nums* '(2 3 5))

(defun print-nums ()
  (format t "~a~%" *nums*))

(print-nums)
-> (2 3 5)
-> NIL
Run Code Online (Sandbox Code Playgroud)

我什至明白动态绑定变量的新值是如何在这段代码中*nums*传递的print-nums

(let ((*nums* '(1 2 3)))
  (print-nums))
-> (1 2 3)
-> NIL
Run Code Online (Sandbox Code Playgroud)

但是为什么下面的代码不能以同样的方式工作?

(defvar *my-nums-f* (let ((*nums* '(1 2 3)))
                      #'(lambda () (format t "~a~%" *nums*))))

(funcall *my-nums-f*)
-> (2 3 5)
-> NIL
Run Code Online (Sandbox Code Playgroud)

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

mel*_*ene 5

(defvar *my-nums-f* (let ((*nums* '(1 2 3)))
                      #'(lambda () (format t "~a~%" *nums*))))
Run Code Online (Sandbox Code Playgroud)

这里我们设置*my-nums-f*

(let ((*nums* '(1 2 3)))
  #'(lambda () (format t "~a~%" *nums*)))
Run Code Online (Sandbox Code Playgroud)

这种形式首先动态绑定*nums*'(1 2 3),然后返回#'(lambda () (format t "~a~%" *nums*)),这是一个函数。最后,我们重置*nums*'(2 3 5).

(funcall *my-nums-f*)
Run Code Online (Sandbox Code Playgroud)

这里我们调用存储在 中的函数*my-nums-f*,即(lambda () (format t "~a~%" *nums*))。此函数获取 的当前值*nums*,即'(2 3 5)

-> (2 3 5)
-> NIL
Run Code Online (Sandbox Code Playgroud)

您似乎期望以lambda某种方式内联函数体中使用的所有变量的当前值,这确实会导致(format t "~a~%" '(1 2 3))该点。

但这不是它的工作原理:函数引用变量本身,而不是变量值的快照。这就是为什么该函数*nums*在调用它时会看到 的当前值。