Higher-order functions in Elisp
Asked Answered
S

3

11

I created a function that returns a function in Elisp:

(defun singleton-set (elem)
  (defun f (n) (= n elem))
  f)

I try to run this in IELM, and it fails:

ELISP> (singleton-set 5)
*** Eval error ***  Symbol's value as variable is void: f
ELISP> ((singleton-set 5) 5)
*** Eval error ***  Invalid function: (singleton-set 5)

Due to What is the difference between Lisp-1 and Lisp-2? i changed the code to

(defun singleton-set (elem)
  (defun f (n) (= n elem))
  #'f)

And invocation to (funcall (singleton-set 5) 5), but now the error is

*** Eval error *** Symbol's value as variable is void: elem

I understand from elisp: capturing variable from inner function that this is due to dynamic binding of Emacs Lisp.

How to make functions returning functions possible in Emacs Lisp? What is the reason this mechanism is different from other languages like Python, Scala or Clojure?

Related questions:

Sahaptin answered 7/10, 2012 at 20:16 Comment(2)
possible duplicate of elisp functions as parameters and as return valueInsular
You don't want to use defun inside of singleton-set. Use something like (defun singleton-set (elem) #'(lambda ...)) instead, and look at @geocar's pointers below.Hepta
B
11

From the NEWS for Emacs 24:

Lisp changes in Emacs 24.1

  • Code can now use lexical scoping by default instead of dynamic scoping. The lexical-binding variable enables lexical scoping for local variables. It is typically set via a file-local variable in the first line of the file, in which case it applies to all the code in that file.

So, in Emacs 24:

(setq lexical-binding t)
(defun singleton-set (elem) (lambda (n) (= n elem)))
(mapcar (singleton-set 1) '(0 1 2 3))
    ===> (nil t nil nil)
Buzzell answered 7/10, 2012 at 20:55 Comment(2)
That doesn't appear to use lexical binding to me -- maybe I'm missing something. I don't see any kind of closure in the code.Treadway
@CharlieFlowers: You're missing something. (Try it with lexical-binding turned on and off and you'll see.) elem needs to be lexically bound if the lambda is to be callable outside of the call to singleton-set.Buzzell
V
6

How to make functions returning functions possible in Emacs Lisp?

Using fake closures, and lexical-let.

What is the reason this mechanism is different from other languages like Python, Scala or Clojure?

Richard Stallman answered this question in a paper he wrote a while ago.

Voncile answered 7/10, 2012 at 20:32 Comment(0)
I
3
(defun singleton-set (elem)
  `(lambda (n) (= n ,elem))

See: elisp functions as parameters and as return value

Insular answered 7/10, 2012 at 20:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.