How do I do closures in Emacs Lisp?
Asked Answered
K

7

32

I'm trying to create a function on the fly that would return one constant value.

In JavaScript and other modern imperative languages I would use closures:

function id(a) {
    return function() {return a;};
}

but Emacs lisp doesn't support those.

I can create mix of identity function and partial function application but it's not supported either.

So how do I do that?

Kerbela answered 27/2, 2009 at 3:14 Comment(3)
As far as I have heard, JavaScript is actually rather functional.Numismatics
It depends on one's point of view. For me if most of the code in the language is imperative then it's imperative. Which is the case here.Kerbela
As of version 24, Emacs now has lexical scoping.Karalynn
Q
10

Stupid idea: how about:

(defun foo (x)
  `(lambda () ,x))

(funcall (foo 10))  ;; => 10
Quoit answered 27/2, 2009 at 3:47 Comment(1)
This breaks down when you want to write something like: (lexical-let ((a 0)) (cons (lambda () a) (lambda (new-a) (setf a new-a))))Aubigny
K
35

Found another solution with lexical-let

(defun foo (n) 
    (lexical-let ((n n)) #'(lambda() n)))

(funcall (foo 10)) ;; => 10
Kerbela answered 27/2, 2009 at 4:6 Comment(0)
O
13

Real (Not Fake) Closures in Emacs 24.

Although Emacs 24 has lexical scooping when the variable lexical-binding has value t, the defun special form doesn’t work properly in lexically bound contexts (at least not in Emacs 24.2.1.) This makes it difficult, but not impossible, to define real (not fake) closures. For example:

(let ((counter 0))
   (defun counting ()
    (setq counter (1+ counter))))

will not work as expected because the symbol counter in the defun will be bound to the global variable of that name, if there is one, and not the lexical variable define in the let. When the function counting is called, if the global variable doesn’t, exist then it will obviously fail. Hoever if there is such a global variable it be updated, which is probably not what was intended and could be a hard to trace bug since the function might appear to be working properly.

The byte compiler does give a warning if you use defun in this way and presumably the issue will be addressed in some future version of Emacs, but until then the following macro can be used:

(defmacro defun** (name args &rest body)
  "Define NAME as a function in a lexically bound context.

Like normal `defun', except that it works correctly in lexically
bound contexts.

\(fn NAME ARGLIST [DOCSTRING] BODY...)"
  (let ((bound-as-var (boundp  `,name)))
    (when (fboundp `,name)
      (message "Redefining function/macro: %s" `,name))
    (append
     `(progn
        (defvar ,name nil)
        (fset (quote ,name) (lambda (,@args) ,@body)))
     (if bound-as-var
         'nil
         `((makunbound `,name))))))

If you define counting as follows:

(let ((counter 0))
  (defun** counting ()
    (setq counter (1+ counter))))

it will work as expected and update the lexically bound variable count every time it is invoked, while returning the new value.

CAVEAT: The macro will not work properly if you try to defun** a function with the same name as one of the lexically bound variables. I.e if you do something like:

(let ((dont-do-this 10))
  (defun** dont-do-this ()
    .........
    .........))

I can’t imagine anyone actually doing that but it was worth a mention.

Note: I have named the macro defun** so that it doesn’t clash with the macro defun* in the cl package, however it doesn’t depend in any way on that package.

Offend answered 27/2, 2009 at 3:14 Comment(2)
Can you give a complete example? It seems that the code (let ((counter 0)) (defun** counting () (setq counter (1+ counter)))) don't work as expected.Dieball
The limitation wrt to defining closures with defun was lifted in Emacs-24.3 (where defun is now defined as a macro rather than a special form). So since 24.3 defun works like your defun** macro (tho without the broken (defvar ,name nil) and fixing various other minor downsides such as the use of fset rather than defalias and handling of so called "dynamic docstrings" which required changes in the bytecompiler).Aquiver
Q
10

Stupid idea: how about:

(defun foo (x)
  `(lambda () ,x))

(funcall (foo 10))  ;; => 10
Quoit answered 27/2, 2009 at 3:47 Comment(1)
This breaks down when you want to write something like: (lexical-let ((a 0)) (cons (lambda () a) (lambda (new-a) (setf a new-a))))Aubigny
D
7

Emacs lisp only has dynamic scoping. There's a lexical-let macro that approximates lexical scoping through a rather terrible hack.

Dragonnade answered 27/2, 2009 at 5:14 Comment(1)
Of course, the `rather terrible hack' is what goes on under the covers of other language implementations.Aubigny
E
4

Emacs 24 has lexical binding.

http://www.emacswiki.org/emacs/LexicalBinding

Empanel answered 4/11, 2012 at 3:11 Comment(1)
Refer also to the section in the GNU Emacs manual on Variable ScopingTripodic
O
4
;; -*- lexical-binding:t -*-

(defun create-counter ()
  (let ((c 0))
    (lambda ()
      (setq c (+ c 1))
      c)))

(setq counter (create-counter))

(funcall counter) ; => 1
(funcall counter) ; => 2
(funcall counter) ; => 3 ...
Ofay answered 11/5, 2019 at 7:46 Comment(0)
B
-1

http://www.emacswiki.org/emacs/FakeClosures

Bartko answered 5/9, 2011 at 5:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.