我有以下代码
(defun avg-damp(f)
#'(lambda(x) (/ (+ (funcall f x) x) 2.0)))
致电
(funcall (avg-damp #'(lambda(v) (* v v))) 10)
在SBCL中返回55.0(正确的值),但在emacs lisp中使用以下堆栈崩溃
Debugger entered--Lisp error: (void-variable f)
(funcall f x)
(+ (funcall f x) x)
(/ (+ (funcall f x) x) 2.0)
(lambda (x) (/ (+ ... x) 2.0))(10)
funcall((lambda (x) (/ (+ ... x) 2.0)) 10)
eval((funcall (avg-damp (function ...)) 10))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp)
如何在Emacs lisp中使其工作?
答案 0 :(得分:19)
这种编程风格在普通的Emacs Lisp中不起作用。 Emacs Lisp使用动态绑定,而Scheme和Common Lisp等语言正在使用词法绑定。您的代码暴露了差异。请参阅:Extent in Emacs Lisp
另见这个问题:How do I do closures in Emacs Lisp?和lexical-let的'解决方案'。 lexical-let是“cl”包中Emacs Lisp的扩展。
另请参阅:自Emacs 24.1起,有可选的lexical binding。了解如何使用它:using lexical binding。
答案 1 :(得分:12)
一个棘手的问题,但终于搞清楚了。问题是avg-damp定义中的#'
使得编译器在知道f的实际值之前编译avg-damp本身时编译lambda函数。您需要将此函数的编译延迟到稍后的时间,当调用avg-damp时,如下所示:
(defun avg-damp (f)
`(lambda(x) (/ (+ (funcall ,f x) x) 2.0)))
(funcall (avg-damp #'(lambda(v) (* v v))) 10)
Backquoting可以解决问题。
编辑:当然,如果你以一种不受欢迎的形式定义avg-damp,整个问题就会消失,例如:
(defun avg-damp (f x)
(/ (+ (funcall f x) x) 2.0))
(funcall 'avg-damp #'(lambda(v) (* v v)) 10)
但我猜你有理由不这样做。