为什么 Common Lisp 中的闭包没有捕获封闭函数的参数?
Why are arguments to an enclosing function not captured by closures in 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 捕获?我怎样才能确保它被捕获?
defvar
(和defparameter
)将变量声明为特殊(动态)。给你的特殊变量 *earmuffs*
以防止对绑定是词法的还是动态的感到意外。
这在使用解释器时是可见的。
先看一个编译器:
? (load "/tmp/test.lisp")
#P"/private/tmp/test.lisp"
? (funcall (funcall test 'right) 'right)
((VAR1 . RIGHT) (VAR2 . RIGHT))
首先编译函数。编译器假定词法绑定。然后 DEFVAR
声明变量 VAR1
和 VAR2
是特殊的(-> 不是词法的)。然后在执行的代码中,代码仍然使用词法绑定。
您使用的是口译员:
首先加载函数。什么都没有编译。然后 DEFVAR
声明 VAR1
和 VAR2
是特殊的。
然后在执行的代码中,解释器正在使用动态绑定 - 就像您声明的那样。解释器在运行时查看变量,发现它们被声明为特殊变量。
差异:
编译器已经生成特殊声明前的机器码。因此在运行时它使用词法绑定。
解释器在运行时查看现有声明。
风格
如果要避免动态绑定,请不要将变量声明为特殊变量。
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 捕获?我怎样才能确保它被捕获?
defvar
(和defparameter
)将变量声明为特殊(动态)。给你的特殊变量 *earmuffs*
以防止对绑定是词法的还是动态的感到意外。
这在使用解释器时是可见的。
先看一个编译器:
? (load "/tmp/test.lisp")
#P"/private/tmp/test.lisp"
? (funcall (funcall test 'right) 'right)
((VAR1 . RIGHT) (VAR2 . RIGHT))
首先编译函数。编译器假定词法绑定。然后 DEFVAR
声明变量 VAR1
和 VAR2
是特殊的(-> 不是词法的)。然后在执行的代码中,代码仍然使用词法绑定。
您使用的是口译员:
首先加载函数。什么都没有编译。然后 DEFVAR
声明 VAR1
和 VAR2
是特殊的。
然后在执行的代码中,解释器正在使用动态绑定 - 就像您声明的那样。解释器在运行时查看变量,发现它们被声明为特殊变量。
差异:
编译器已经生成特殊声明前的机器码。因此在运行时它使用词法绑定。
解释器在运行时查看现有声明。
风格
如果要避免动态绑定,请不要将变量声明为特殊变量。