为什么Common Lisp中的闭包不能捕获封闭函数的参数



test.lisp:

(defvar test
#'(lambda (var1)
#'(lambda (var2)
`((var1 . ,var1)
(var2 . ,var2)))))
(defvar var1 'wrong)
(defvar var2 'wrong)

在REPL中:

$ clisp -q -i test.lisp
;; Loading file test.lisp ...
;; Loaded file test.lisp
[1]> (funcall (funcall test 'right) 'right)
((VAR1 . WRONG) (VAR2 . RIGHT))

我认为公共lisp现在应该在词汇范围内,那么为什么var1的值没有被test中的内部lambda捕获呢?我如何确保它被捕获?

这在使用解释器时是可见的。

让我们先来看编译器:

? (load "/tmp/test.lisp")
#P"/private/tmp/test.lisp"
? (funcall (funcall test 'right) 'right)
((VAR1 . RIGHT) (VAR2 . RIGHT))

首先对函数进行编译。编译器假定有词法绑定。然后DEFVAR声明变量VAR1VAR2是特殊的(->不是词法的)。在执行的代码中,代码仍然使用词法绑定。

您使用的是口译员:

首先加载函数。不会编译任何内容。然后DEFVARVAR1VAR2声明为特殊的。

在执行的代码中,解释器使用动态绑定,就像你声明的那样。解释器在运行时查看变量,发现它们被声明为特殊的。

差异

编译器在特殊声明之前生成了机器代码。因此,在运行时它使用词法绑定。

解释器在运行时查看现有的声明。

样式

如果希望避免动态绑定,请不要将变量声明为特殊变量。

defvar(和defparameter)将变量声明为特殊(动态)。给您的特殊变量*earmuffs*,以防止对绑定是词法绑定还是动态绑定产生意外。

最新更新