1

我正在尝试在 emacs lisp 中应用闭包。我在这里找到了一篇文章: 如何在 Emacs Lisp 中进行闭包?

有一些代码,如:

(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))

但是按照 emacs文档lambda 的格式应该像 '(lambda () x) ==> 使用这种格式,我得到一个错误:符号的值作为变量是无效的:x

当“,”在“()”和“x”之间添加时,一切正常。

为什么?

4

2 回答 2

3

发生这种情况是因为 Emacs Lisp 是动态作用域的,因此会foo返回一个x空闲的 lambda。这就是错误告诉你的。

要在 Emacs Lisp 中进行闭包,您必须使用lexical-let它来模拟词法绑定,因此您可以创建真正的闭包。

(defun foo (x)
  (lexical-let ((x x))
               (lambda () x)))

(message (string (funcall (foo 66))))

以下是来自 Emacs Wiki 的一些链接:

  1. 动态绑定与词法绑定
  2. 假闭包

请注意,您可以x使用这样的 let 进行定义:

(defun foo (x)
  (lambda () x))

(message (string (let ((x 66)) (funcall 
                                (foo 'i-dont-care)))))
于 2011-12-23T10:21:18.787 回答
0

这个答案在@Daimrod 正确答案的第一部分背后提供了一些细节。

你的问题是为什么这有效:

(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))

这不起作用:

(defun foo (x) '(lambda () x)) (message (string (funcall (foo 66))))

首先,第二个中的引号 ( ') 是不必要的,因为在 Emacs Lisp 中,lambda 形式是自评估的。也就是说,'(lambda (...) ...)通常与 相同(lambda (...) ...)

但是反引号 ( `) 而不是引号 ( ')有什么作用呢

在反引号表达式中,逗号 ( ,) 表示将下一个表达式替换为其值,即计算它。所以这:

`(lambda () ,x)

表示创建并返回一个列表,其第一个元素是符号lambda(未计算),第二个元素是()(未计算),第三个元素是变量的x。它相当于评估这段代码,它使用函数list

(list 'lambda '() x)

这就是你想要的:用它的当前值替换 (在这种情况下,它在 function中的值,即's 参数的值)。xfoofoo

但是这个:

'(lambda () x)

(同样,因为 lambda 形式是自评估的,(lambda () x))返回此列表:(lambda () x)。当使用动态范围(Emacs Lisp 中的默认范围机制)评估时,x它是未绑定的 - 它没有任何价值。因此会引发 void-variable 错误。

于 2020-05-08T23:29:24.307 回答