10

我有以下代码

(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 中工作?

4

2 回答 2

19

这种编程风格不适用于普通的 Emacs Lisp。Emacs Lisp 使用动态绑定,Scheme 和 Common Lisp 等语言使用词法绑定。您的代码暴露了差异。请参阅:Emacs Lisp 中的范围

另请参阅此问题:如何在 Emacs Lisp 中进行闭包?以及 lexical-let 的“解决方案”。lexical-let 是“cl”包中 Emacs Lisp 的扩展。

另请参阅:从 Emacs 24.1 开始,有可选的词法绑定。学习如何使用它:使用词法绑定

于 2009-03-19T09:39:48.057 回答
12

一个棘手的问题,但最终解决了这个问题。问题在于,在 avg-damp 的定义中,编译器在编译avg-damp 本身时#'编译了 lambda 函数,在f 的实际值已知之前。您需要将此函数的编译延迟到稍后的时间点,即调用 avg-damp 时,如下所示:

(defun avg-damp (f)
   `(lambda(x) (/ (+ (funcall ,f x) x) 2.0)))

(funcall (avg-damp #'(lambda(v) (* v v))) 10)

反引号可以解决问题。

编辑:当然,如果您以非咖喱形式定义 avg-damp,整个问题就会消失,例如:

(defun avg-damp (f x)
   (/ (+ (funcall f x) x) 2.0))

(funcall 'avg-damp #'(lambda(v) (* v v)) 10)

但我想你有理由不这样做。

于 2009-03-19T09:20:20.037 回答