emacs24中的词法评估

des*_*esu 4 emacs elisp emacs24

任何人都可以解释我如何eval使用emacs24?来自eval描述:

eval is a built-in function in `C source code'.

(eval FORM &optional LEXICAL)

Evaluate FORM and return its value.
If LEXICAL is t, evaluate using lexical scoping.
Run Code Online (Sandbox Code Playgroud)

这是否意味着,这样的事情应该有效?

(setq lexical-binding t)
(let ((myvarr 42)) (eval 'myvarr t)) ; (void-variable myvarr)
Run Code Online (Sandbox Code Playgroud)

更新:

(setq lexical-binding nil)
;; => nil
(let ((myvarr 42)) (eval 'myvarr))
;; => 42 (#o52, #x2a, ?*)
(setq lexical-binding t)
;; => t
(let ((myvarr 42)) (eval 'myvarr))
;; Debugger entered--Lisp error: (void-variable myvarr)
;;   eval(myvarr)
;;   (let ((myvarr 42)) (eval (quote myvarr)))
;;   (progn (let ((myvarr 42)) (eval (quote myvarr))))
;;   eval((progn (let ((myvarr 42)) (eval (quote myvarr)))) t)
;;   eval-last-sexp-1((4))
;;   eval-last-sexp((4))
;;   call-interactively(eval-last-sexp nil nil)
;;   call-last-kbd-macro(nil kmacro-loop-setup-function)
;;   kmacro-call-macro(nil nil)
;;   kmacro-end-or-call-macro(nil)
;;   call-interactively(kmacro-end-or-call-macro nil nil)
(ignore-errors (let ((myvarr 42)) (eval 'myvarr)))
;; => nil
(setq lexical-binding nil)
;; => nil
(eval (let ((myvarr 42)) (eval 'myvarr)) t)
;; => 42
(eval '(let ((myvarr 42)) (eval 'myvarr)) t)
;; Debugger entered--Lisp error: (void-variable myvarr)
;;   eval(myvarr)
;;   (let ((myvarr 42)) (eval (quote myvarr)))
;;   eval((let ((myvarr 42)) (eval (quote myvarr))) t)
;;   eval((eval (quote (let ((myvarr 42)) (eval (quote myvarr)))) t) nil)
;;   eval-last-sexp-1((4))
;;   eval-last-sexp((4))
;;   call-interactively(eval-last-sexp nil nil)
Run Code Online (Sandbox Code Playgroud)

Emacs版本: GNU Emacs 24.1.1 (i386-mingw-nt6.1.7600) of 2012-06-10 on MARVIN

cob*_*bal 8

由于词法绑定会破坏现有的elisp代码,因此它是一个选择加入的功能.

通过一个简单的例子可以最好地理解词法范围:

(defun some-func (callback)
 (let ((a 5))
  (funcall callback)))

(let ((a 3))
 (some-func (lambda () a)))
Run Code Online (Sandbox Code Playgroud)

在大多数语言中,这将返回3,因为asome-func似乎从底部形态不可见.但是,在24之前的emacs或没有词法范围的情况下,此程序返回5.

这导致了许多意想不到的惊喜以及相互作用的功能之间的微妙且经常隐藏的错误; 修复这个emacs 24引入了词法范围,但如前所述,是向后兼容的.

选择加入动态范围的机制是文件变量lexical-binding(每个源文件打开它)或者您看到的选项eval

因此,如果我们重写要使用的示例eval:

(eval '(let ((a 3))
        (some-func (lambda () a))) nil) ; => 5

(eval '(let ((a 3))
        (some-func (lambda () a))) t) ; => 3
Run Code Online (Sandbox Code Playgroud)

在您的示例中,产生差异的不在于内部代码是否eval是动态范围的,而是围绕它的代码是否是.变量绑定受词法范围的影响,而不是变量查找.我不完全确定eval这里的语义,但似乎正在发生的事情(以及最有意义的事情)是eval在一个全新的词汇语境中评估表达式.因此,外部词法范围从内部隐藏eval,但动态范围仍然可见(因此,当文件动态范围化时,查找成功,但不是这样).


dki*_*kim 5

eval在Emacs 24中找不到该函数的形式语义,但是当你假设它的工作方式与Common Lisp相同时(例如cobbal所示),你的所有例子都有意义.Common Lisp HyperSpec说:

句法:

eval 形成

描述:

评估当前动态环境和null词法环境中的表单 .

让我们一个一个地看一下你的例子,并附上描述.

(setq lexical-binding t)
(let ((myvarr 42)) (eval 'myvarr t)) ; Lisp error: (void-variable myvarr)
Run Code Online (Sandbox Code Playgroud)

词法结合是通过设置启用tlexical-binding,所以myvarr变成为词法绑定变量,这是不可用的内部eval如上述那样的功能.该eval功能的选项,t是这里无关紧要.

(setq lexical-binding nil)
(let ((myvarr 42)) (eval 'myvarr)) ; 42
Run Code Online (Sandbox Code Playgroud)

词法绑定是通过设置禁用nillexical-binding,所以myvarr变成为动态绑定的变量,它是可用的内部eval功能.该eval功能的选项,implicilty nil,在这里无关紧要.

(setq lexical-binding t)
(let ((myvarr 42)) (eval 'myvarr)) ; Lisp error: (void-variable myvarr)
Run Code Online (Sandbox Code Playgroud)

词法结合是通过设置启用tlexical-binding,所以myvarr变成为词法绑定变量,这是不可用的内部eval功能.该eval功能的选项,implicilty nil,在这里无关紧要.

(ignore-errors (let ((myvarr 42)) (eval 'myvarr))) ; nil
Run Code Online (Sandbox Code Playgroud)

同上.

(setq lexical-binding nil)
(eval (let ((myvarr 42)) (eval 'myvarr)) t) ; 42
Run Code Online (Sandbox Code Playgroud)

词法结合被设置禁用nillexical-binding,所以myvar变成为动态绑定的变量,它是可用的内内部eval功能.请注意,在调用外部之前,let表单(包括内部eval函数)将作为参数准备进行评估eval.外部eval函数和内部函数的选项都不在此处.

(eval '(let ((myvarr 42)) (eval 'myvarr)) t) ; Lisp error: (void-variable myvarr)
Run Code Online (Sandbox Code Playgroud)

myvarr变成一个词法绑定变量,在内部不可用eval.请注意,因为',let表单由外部eval函数计算,并启用了词法绑定.外部eval函数的选项与此相关,而内部eval函数则不是.


为什么空词法环境?

也就是说,我认为,因为如果使用当前的词汇环境,那么α等价将不再存在.

Alpha等价是一种形式化的方式来表示函数参数的名称并不重要.例如,(lambda (x) x)并且(lambda (y) y)是α等价的,我们认为它们是相同的.Alpha等价允许我们随时更改函数参数的名称.我们认为这是理所当然的,如果它不成立,我们会非常惊讶.有关更正式的解释,请参阅Lambda演算Alpha等价.

但是,当涉及自由变量(称为开放代码)的代码值可以像在Lisp中一样传递时,alpha等价会产生一些问题.我们来看下面的例子:

;;; -*- lexical-binding: t -*-
(lambda (x) (lambda (y) (eval x))) '(1+ y)
Run Code Online (Sandbox Code Playgroud)

如果eval在当前词汇环境下进行评估,表格将等同于(lambda (y) (1+ y)).现在看下面的程序:

(lambda (x) (lambda (z) (eval x))) '(1+ y)
Run Code Online (Sandbox Code Playgroud)

这个程序与前一个程序不同,只是在其参数的名称z中代替y,所以我们自然希望它们的行为方式相同.但后一个程序的评估(lambda (z) (1+ y))结果与之完全不同(lambda (y) (1+ y).考虑将结果函数值应用于同一参数时会发生什么.关键是当允许包含自由变量的代码值时,函数参数的名称很重要.

在这里,我们有两个选择,以保持alpha等价:我们不能放弃alpha等价,因为它感觉很自然,我们已经习惯了它.第一个选项是eval在null词法环境下评估为(Common)Lisp.使用此选项,自由变量yin (1+ y)不会绑定到形式参数y(lambda (y) ...).所以这两个程序表现一致,并且保持了α等价.另一种选择是通过从一开始就不允许开放代码值来排除问题.我听说这是MetaOCaml选择的一种方法

有人可能会问"如果是这样,为什么会出现当前的动态环境?".对于动态绑定(又称特殊)变量,我们已经很清楚他们的名字非常重要,如果你不小心改变它们,你的程序就会被打破.