我正在尝试在 emacs lisp 中应用闭包。我在这里找到了一篇文章: 如何在 Emacs Lisp 中进行闭包?
有一些代码,如:
(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))
但是按照 emacs文档lambda 的格式应该像 '(lambda () x) ==> 使用这种格式,我得到一个错误:符号的值作为变量是无效的:x
当“,”在“()”和“x”之间添加时,一切正常。
为什么?
发生这种情况是因为 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 的一些链接:
请注意,您可以x
使用这样的 let 进行定义:
(defun foo (x)
(lambda () x))
(message (string (let ((x 66)) (funcall
(foo 'i-dont-care)))))
这个答案在@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 参数的值)。x
foo
foo
但是这个:
'(lambda () x)
(同样,因为 lambda 形式是自评估的,(lambda () x)
)返回此列表:(lambda () x)
。当使用动态范围(Emacs Lisp 中的默认范围机制)评估时,x
它是未绑定的 - 它没有任何价值。因此会引发 void-variable 错误。