Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elisp functions as parameters and as return value

Tags:

lisp

elisp

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?

like image 385
Oleg Pavliv Avatar asked Mar 19 '09 09:03

Oleg Pavliv


People also ask

How do you call a function in Elisp?

Calling a function is also known as invocation. The most common way of invoking a function is by evaluating a list. For example, evaluating the list (concat "a" "b") calls the function concat with arguments "a" and "b" . See Evaluation, for a description of evaluation.

How to define a function in Emacs?

To define a function, we use the special form defun. It's followed by the function name and its arguments. The arguments are private, so it does not change anything outside the function. Any other symbol called inside a function will bring its value from outside since Elisp has global scope.

What is defun in Emacs?

defun is the usual way to define new Lisp functions. It defines the symbol name as a function with argument list args (see Features of Argument Lists) and body forms given by body . Neither name nor args should be quoted.

How does let work in Lisp?

The let expression is a special form in Lisp that you will need to use in most function definitions. let is used to attach or bind a symbol to a value in such a way that the Lisp interpreter will not confuse the variable with a variable of the same name that is not part of the function.


2 Answers

This style of programming does not work in plain Emacs Lisp. Emacs Lisp uses dynamic binding and languages like Scheme and Common Lisp are using lexical binding. Your code exposes the difference. See: Extent in Emacs Lisp

See also this question: How do I do closures in Emacs Lisp? and the 'solution' with lexical-let. lexical-let is an extension for Emacs Lisp in the "cl" package.

See also: since Emacs 24.1 there is optional lexical binding. Learn how to use it: using lexical binding.

like image 132
Rainer Joswig Avatar answered Nov 11 '22 22:11

Rainer Joswig


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.

like image 39
David Hanak Avatar answered Nov 11 '22 22:11

David Hanak