【问题标题】:elisp functions as parameters and as return valueelisp 函数作为参数和返回值
【发布时间】:2010-10-14 06:33:27
【问题描述】:

我有以下代码

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

【问题讨论】:

    标签: lisp elisp


    【解决方案1】:

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

    另请参阅此问题:How do I do closures in Emacs Lisp? 和 lexical-let 的“解决方案”。 lexical-let 是 Emacs Lisp 在 "cl" 包中的扩展。

    另请参阅:从 Emacs 24.1 开始,有可选的 lexical binding。了解如何使用它:using lexical binding

    【讨论】:

      【解决方案2】:

      一个棘手的问题,但终于弄明白了。问题是 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)
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-09
        • 2011-08-30
        • 1970-01-01
        • 1970-01-01
        • 2018-05-28
        • 2015-04-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多