我正在尝试 Emacs 词法作用域(Emacs 24 的新特性)之间add-to-list
的相互作用,发现相互作用令人困惑,我不知道如何理解它。这是一个最小的示例,除了我使用set
而不是add-to-list
. (set
类似于add-to-list
它通常采用带引号的变量名)
(eval
'(progn
(setq a "global")
(let ((a "apple"))
(defun my-print-a ()
(print a)
(set 'a "by set")
(print a))
(setq a "mature apple"))
(let ((a "banana"))
(my-print-a))
(print a))
t) ;; t for lexical scoping
上面的代码按顺序打印“mature apple”、“mature apple”、“by set”。第一个打印结果“成熟的苹果”与词法作用域的预期一致(支持词法闭包),在这里看到并不奇怪。但是第二次和第三次打印的结果让我感到惊讶。好像(set 'a "by set")
只是识别和影响 name 的全局绑定a
。
这是预期的行为吗?或者这是一个错误?如果有意,如何理解这种行为?
我是否正确地假设set
只要词法范围打开,它总是会影响全局绑定?
使用(eval '(progn ...) nil)
时,事情会按照动态作用域的预期工作,并且 的行为与这种情况下的行为(set 'a ...)
相同(setq a ...)
。只有当一个人同时使用词法作用域和带引号的变量时,才会出现这个问题。
更新:
根据手册,这似乎是一种预期的行为。在Void Variables上,手册说
在词法绑定规则下,值单元只保存变量的全局值,即任何词法绑定结构之外的值。当一个变量被词法绑定时,局部值由词法环境决定;如果其符号的值单元格未分配,则该变量可能具有局部值。
和词法绑定
symbol-value、boundp 和 set 等函数仅检索或修改变量的动态绑定(即其符号值单元格的内容)。
symbol-value、boundp、set 是通常用带引号的变量名 ( (symbol-value 'var) (boundp 'var) (set 'var 123)
) 调用的函数。这些函数仅获取或设置符号的值单元格,并且在词法绑定规则下,值单元格仅保存全局值。所以在词法绑定下,使用带引号的变量只能获取或设置全局值(除非变量是特殊变量)。尽管结果既不是词汇(苹果)也不是动态(香蕉)看起来仍然很奇怪。