这里有两个问题。第一个是语法问题,正如其他答案所指出的那样。问题中提到的第二个问题是范围问题。
句法问题
在 Emacs Lisp(和 Lisp-2 系列中的其他 Lisps)中,函数调用看起来像 (f args...),其中 f 是具有函数值的符号或 lambda expression。例如,
(list 1 2 3)
=> (1 2 3)
因为list 有一个函数绑定。还有,
((lambda (x y) (list x x y y)) 1 2)
=> (1 1 2 2)
因为(lambda (x y) (list x x y y)) 是lambda 表达式。但是,您不能做的是使用 which of 的值是函数的东西。
(let ((id (lambda (x) x)))
(id 3))
发出Lisp error: (void-function id) 的信号。但是我们可以使用funcall调用函数值:
(let ((id (lambda (x) x)))
(funcall id 3))
=> 3
注意:这是一种相当好的看待它的方式,但实际上事情要复杂一些。有关详细信息和函数间接等深奥部分,请参阅手册中的9.2 Kinds of Forms。
所以,现在我们可以解决语法问题了。原始代码,重新格式化以指示哪些函数正在获取哪些参数,是:
(((lambda (b)
(lambda (a)
(+ b a)))
3)
5)
据我了解,其目的是首先使用参数3 调用(lambda (b) ...) 以获取匿名函数(lambda (a) ...)。在 Emacs Lisp 中,这将是:
((lambda (b)
(lambda (a)
(+ b a)))
3)
=> (lambda (a) (+ b a))
现在,您还想用5 调用返回的匿名函数。我们使用funcall 来做到这一点:
(funcall ((lambda (b)
(lambda (a)
(+ b a)))
3)
5)
范围界定问题
令人失望的是,这段代码生成了一个Lisp error: (void-variable b)。 这是我们最终遇到动态与词法作用域问题的地方。因为变量b 是动态绑定的,所以它的值不会保留在匿名函数(lambda (a) (+ b a)) 中。我们可以通过将整个表单包围在绑定b 的东西中并查看发生了什么来检查是否发生了这种情况:
(let ((b 100))
(funcall ((lambda (b)
(lambda (a)
(+ b a)))
3)
5))
=> 105
我不是 Emacs Lisp 黑客,所以我不确定在 Emacs 中获得词法闭包的最佳方法。我读到 Emacs 24 有它,但我仍然在这里 23。但是,基于this answer,我们可以使用lexical-let 来获得我们需要的结果:
(funcall ((lambda (b)
(lexical-let ((b b))
(lambda (a)
(+ b a))))
3)
5)
=> 8
lexical-let 建立了我们需要的词法绑定,因此匿名函数(lambda (a) ...) 确实将3 嵌入其中。更具体地说,我们引入了b 的词法绑定,(lambda (a) …) 引用的正是该词法绑定。事实上,如果我们现在看返回的匿名函数,它不仅仅是(lambda (a) (+ b a)),而是以更复杂(也更没用)的方式打印出来的:
((lambda (b)
(lexical-let ((b b))
(lambda (a)
(+ b a))))
3)
=> (lambda (&rest --cl-rest--) (apply (lambda (G27322 a) (+ ... a)) (quote --b--) --cl-rest--))
顺便说一句,词法绑定的变量b 与动态绑定的b 同名并不重要;我们可以改用(lexical-let ((c b)) ... (+ c a) ...)。