Common lisp eval form应该在空词汇环境中计算给定的形式,我不';我得不到我所期望的

Common lisp eval form应该在空词汇环境中计算给定的形式,我不';我得不到我所期望的,common-lisp,Common Lisp,假设我有一个特殊的变量: (defvar x 20) 然后,我做以下工作: (let ((x 1)) (eval '(+ x 1)) 计算结果为2 根据CLHS,eval“在当前动态环境和空词汇环境中评估表单”。所以,我希望得到21而不是2 我错过什么了吗 现在如果我没有符号y的动态绑定,那么 (let ((y 1)) (eval '(+ y 1)) 我得到一个条件:“变量Y未绑定”,这很有意义,因为Y没有动态绑定 注意:我使用的是SBCL 1.0.57 提前感谢您的帮助 在您的示例中,x

假设我有一个特殊的变量:

(defvar x 20)
然后,我做以下工作:

(let ((x 1)) (eval '(+ x 1))
计算结果为2

根据CLHS,eval“在当前动态环境和空词汇环境中评估表单”。所以,我希望得到21而不是2

我错过什么了吗

现在如果我没有符号y的动态绑定,那么

(let ((y 1)) (eval '(+ y 1))
我得到一个条件:“变量Y未绑定”,这很有意义,因为Y没有动态绑定

注意:我使用的是SBCL 1.0.57


提前感谢您的帮助

在您的示例中,
x
特殊的
,这意味着它是在动态环境中绑定的

y
不是特殊的,因此它被绑定在词汇环境中


因此,在第一次
eval
评估时,环境可以这样表示:

dynamic environment:  { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment:  nil
dynamic environment: { x : 20,  ...other global variables... } -> nil
lexical environment: { y :  1 } -> nil
符号
x
是特殊的,因此
eval
在当前动态中查找
x
环境并查找
x=1


假设它是在与上一个示例相同的lisp中运行的,则第二个
eval
的环境如下所示:

dynamic environment:  { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment:  nil
dynamic environment: { x : 20,  ...other global variables... } -> nil
lexical environment: { y :  1 } -> nil
符号
y
不特殊,因此
eval
在空值中查找
y
词法环境——不是当前的词法环境——什么也找不到

当您意识到lisp通常是编译的,并且词法
在某些情况下,环境可以优化为简单的
mov
指令。

DEFVAR
声明其特殊变量。全球各地。您也无法轻松删除此项


这也是您不应使用诸如
x
i
list
等常用名称作为
DEFVAR
的变量名的原因。请确保改用
*x*
*i*
*list*
。否则,所有具有这些通用名称的变量,即使是本地变量,都会被声明为特殊的。

是的,使用带有特殊变量的耳罩是所有人(包括我在内,因为它使代码更清晰)都支持的最佳实践,但《让Lambda过去》一书的作者并没有指出语法的双重性。在这个特殊的例子中,我想看看eval会选择哪个绑定。根据我的理解,因为X是特殊的,所以让我们将现有的X的“全局”绑定更改为let form指定的绑定,这就是为什么eval选择let新绑定的值1。如果我理解错了,请纠正我。@Svarog:不要更改全局绑定。它创建一个新的本地绑定。在本例中是动态绑定。由于要计算的代码中的X自动是一个特殊变量(DEFVAR声明有效),EVAL使用本地动态绑定。这非常有帮助!我非常感谢你的帮助!