Search code examples
lispelisp

elisp functions as parameters and as return value


I have the following code

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

A call

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

returns 55.0 (the correct value) in SBCL but crashes with the following stack in 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)

How can I make it work in Emacs lisp?


Solution

  • A tricky question, but finally got this figured out. The problem is that #' in the definition of avg-damp makes the compiler compile the lambda function at the time when avg-damp itself is compiled, before the actual value of f is known. You need to delay the compilation of this function to a later point in time, when avg-damp is called, like this:

    (defun avg-damp (f)
       `(lambda(x) (/ (+ (funcall ,f x) x) 2.0)))
    
    (funcall (avg-damp #'(lambda(v) (* v v))) 10)
    

    Backquoting does the trick.

    Edit: Of course, the whole problem goes away if you define avg-damp in an uncurried form, such as this:

    (defun avg-damp (f x)
       (/ (+ (funcall f x) x) 2.0))
    
    (funcall 'avg-damp #'(lambda(v) (* v v)) 10)
    

    But I guess you have your reasons not to do so.