问题 eval表单应该在null词法环境中评估给定的表单,我没有得到我期望的结果


假设我有一个特殊的var:

(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

提前感谢您的帮助!


2483
2017-07-24 18:10


起源



答案:


在你的例子中 x 是 special 这意味着它受到约束 动态环境

y 是  特别的,所以它受到约束 词汇环境


所以在第一次的时候 eval 环境可以这样表示:

dynamic environment:  { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment:  nil

符号 x 很特别 eval 仰望;查询 x 在里面 当前 动态 环境和发现 x = 1


假设它与最后一个例子在同一个lisp中运行,第二个例子就是环境 eval 看起来像这样:

dynamic environment: { x : 20,  ...other global variables... } -> nil
lexical environment: { y :  1 } -> nil

符号 y 是  特别的 eval 仰望;查询 y 在里面 空值  词汇环境 -  当前的词汇环境 - 一无所获。

当你意识到通常编译lisp和词法时,这是有道理的 环境可以优化到简单 mov 某些情况下的说明。


7
2017-07-24 19:06



这有很大帮助!非常感谢你的帮助! - Svarog


答案:


在你的例子中 x 是 special 这意味着它受到约束 动态环境

y 是  特别的,所以它受到约束 词汇环境


所以在第一次的时候 eval 环境可以这样表示:

dynamic environment:  { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment:  nil

符号 x 很特别 eval 仰望;查询 x 在里面 当前 动态 环境和发现 x = 1


假设它与最后一个例子在同一个lisp中运行,第二个例子就是环境 eval 看起来像这样:

dynamic environment: { x : 20,  ...other global variables... } -> nil
lexical environment: { y :  1 } -> nil

符号 y 是  特别的 eval 仰望;查询 y 在里面 空值  词汇环境 -  当前的词汇环境 - 一无所获。

当你意识到通常编译lisp和词法时,这是有道理的 环境可以优化到简单 mov 某些情况下的说明。


7
2017-07-24 19:06



这有很大帮助!非常感谢你的帮助! - Svarog


DEFVAR 声明其变量特殊。在全球范围内,无处不在。你也不能轻易删除它。

这也是你永远不应该使用常见名称的原因 xilist 作为变量名称 DEFVAR。确保使用 *x**i* 和 *list* 代替。否则,具有这些通用名称的所有变量(甚至是本地变量)都被声明为特殊


5
2017-07-24 19:27



是的,使用带有特殊变量的耳罩是每个人都支持的最佳实践(包括,因为它使代码更清晰),但不是“Let Over Lambda”一书的作者指出语法的二元性。在这个特殊情况下,我想看看eval会选择哪个绑定。根据我的理解,因为X是特殊的,让我们将X的现有“全局”绑定更改为let表单指定的绑定,这就是为什么eval选择let新绑定的值为1的原因。如果我理解错了,请纠正我。 - Svarog
@Svarog:LET不会更改全局绑定。它创建一个新的本地绑定。在这种情况下是动态绑定。由于要计算的代码中的X自动是一个特殊变量(DEFVAR声明有效),EVAL使用本地动态绑定。 - Rainer Joswig