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

4

11

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 ?

Norward answered 5/8, 2011 at 11:29 Comment(5)
You might save yourself a lot of time by using a Common Lisp with Slime in emacs. SBCL is my favourite.Sil
@justinhj: Thanks for the tip. However, I'm learning lisp just to get to know emacs better. Unless something is going to change my mind, I think I prefer python over lisp with a really wide margin.Norward
That makes sense. BTW when using emacs lisp to extend emacs think about how you would do the same in Python. IMHO emacs lisp is an ideal language for extending a text editor, whilst Python, which I also really like, has many different uses.Sil
Emacs lisp does not really reflect the experience of using lisps targeted at "real programming" like common lisp. Accordingly, it's not a fair comparison with python, which is not really intended to be used as an embedded scripting language as its first use.Prussia
Marcin, I'm sure lisp is a really powerful concept. Unfortunately, even after few months, I personally still not very comfortable with lisp syntax.Norward
A
19

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.

Aegeus answered 5/8, 2011 at 11:47 Comment(3)
And M-x ielm to get the elisp REPL.Imperator
@phil I suppose the hint is for me ? :)Norward
This is a good read to go deep into lexical scope in emacs lisp gnu.org/software/emacs/emacs-paper.html#SEC17Sil
S
12

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'.

Sexpot answered 5/8, 2011 at 12:3 Comment(2)
Thanks for the info. I'm really curious if painless transition from dynamic-binding to lexical-binding could be possible. But it's great to know that emacs is still evolving. And I'm really looking forward to devote some effort to help when my skill is good enough.Norward
Dynamic binding is one of the key reasons that Emacs is so easily extensible. It's certainly nice to have the alternative available, but I hope that dynamic binding will always be the standard for most elisp code.Imperator
R
2

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

Rockett answered 10/9, 2011 at 17:46 Comment(0)
N
1

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
Norward answered 12/12, 2011 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.