我想在emacs lisp中应用闭包。我在这里找到一个帖子: How do I do closures in Emacs Lisp?
使用一些代码:
(defun foo(x)`(lambda(),x))(message(string(funcall(foo) 66))))
但是跟随emacs documentation lambda应该像这样格式化 '(lambda()x)==>使用这种格式,我得到一个错误:符号的值作为变量是void:x
当“,”添加到“()”和“x”之间时,一切都正常。
为什么?
答案 0 :(得分: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的一些链接:
请注意,您可以使用以下内容定义x
:
(defun foo (x)
(lambda () x))
(message (string (let ((x 66)) (funcall
(foo 'i-dont-care)))))
答案 1 :(得分:0)
此答案在@Daimrod正确答案的第一部分后面提供了一些细节。
您的问题是为什么有效:
<body style="background-color: #aaa">
<span id="red" style="color:red"> RED </span>
<span id="blue" style="color:blue"> BLUE </span>
<span id="lightblue" style="color:lightblue"> LIGHTBLUE </span>
<span id="yellow" style="color:yellow"> YELLOW </span>
<span id="purple" style="color:purple"> PURPLE </span>
<span id="green" style="color:green"> GREEN </span>
</body>
这不起作用:
(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)
(在这种情况下,其在函数x
中的值,即{{1 }}的论点。
但这是
foo
(同样,由于Lambda形式是自评估的,因此foo
)将返回以下列表:'(lambda () x)
。而且,如果使用动态范围(Emacs Lisp中的默认范围设置)对它进行评估,则(lambda () x)
是不受约束的-它没有任何价值。因此会引发空变量错误。