Sake
Sake

Reputation: 4133

How to overcome the lack of local variable for emacs lisp closure

I'm now studying Emacs Lisp from the reference manual and Common Lisp from a LISP Book.

from the Common Lisp book

>> (setf power-of-two
     (let ((previous-power-of-two 1))
       #'(lambda ()
           (setf previous-power-of-two
             (* previous-power-of-two 2)))))

>> (funcall power-of-two)
2

>> (funcall power-of-two)
4

>> (funcall power-of-two)
8

The function won't work in Emacs Lisp because of its dynamic binding behavior.

I wonder if it is possible to implement the same function in Emacs Lisp without introducing a global variable ?

Upvotes: 11

Views: 924

Answers (4)

danlei
danlei

Reputation: 14291

Update:

By now, Emacs 24 has been officially released, and it supports lexical binding without using lexical-let, when the buffer-local variable lexical-binding is non-nil. See also M-: (info "(elisp) using lexical binding") and pokita's answer.


You can use lexical-let from the Common Lisp Extensions (the "CL package"):

elisp> (require 'cl)
cl
elisp> (setf power-of-two
             (lexical-let ((previous-power-of-two 1))
               #'(lambda ()
                   (setf previous-power-of-two
                         (* previous-power-of-two 2)))))
(lambda
  (&rest --cl-rest--)
  (apply
   (lambda
     (G175638)
     (set G175638
          (*
           (symbol-value G175638)
           2)))
   '--previous-power-of-two-- --cl-rest--))

elisp> (funcall power-of-two)
2
elisp> (funcall power-of-two)
4
elisp> (funcall power-of-two)
8

I've also heard about a lexbind branch of GNU Emacs.

Upvotes: 19

Sake
Sake

Reputation: 4133

another solution using Emacs' unintern symbol:

ELISP> (setf power-of-two
         (let ((p (make-symbol "previous-power-of-two")))
           (set p 1) (list 'lambda '()
           (list 'setf p
             (list '* p 2)))))

ELISP> (funcall power-of-two)
2
ELISP> (funcall power-of-two)
4
ELISP> (funcall power-of-two)
8

Upvotes: 1

Drew
Drew

Reputation: 30708

See this page: http://www.emacswiki.org/emacs/FakeClosures

Upvotes: 2

pokita
pokita

Reputation: 1261

Emacs24 from bzr now supports lexical binding out of the box; it just isn't activated by default since there are many packages which still deliberately or inadvertently depend on dynamical scoping. Your above code should work just fine in Emacs24 in a buffer where the variable 'lexical-binding' is set to 't'.

Upvotes: 12

Related Questions