2

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))

我认为现在 common lisp 应该是词法范围的,那么为什么var1内部 lambda 没有捕获的值test呢?我怎样才能确保它被捕获?

4

2 回答 2

4

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

我们先来看一个编译器:

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

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

您正在使用解释器:

首先加载函数。没有任何东西被编译。然后DEFVAR声明VAR1VAR2作为特殊。

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

区别

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

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

风格

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

于 2015-04-10T21:23:16.180 回答
3

defvar(和defparameter)声明变量是特殊的(动态的)。提供您的特殊变量*earmuffs*以防止对绑定是词法还是动态感到意外。

于 2015-04-10T21:14:56.880 回答