Reputation: 999
I'm tring to apply closure in emacs lisp.And I find a post here: How do I do closures in Emacs Lisp?
with some code like:
(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))
But following the emacs documentation lambda should be formated like '(lambda () x) ==> using this format ,I got an ERROR :Symbol's value as variable is void: x
When " , " is add betwenn "()" and "x" ,everything goes right .
Why?
Upvotes: 1
Views: 637
Reputation: 30708
This answer gives a bit of detail behind the first part of @Daimrod's correct answer.
Your question is why this works:
(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))
and this doesn't work:
(defun foo (x) '(lambda () x)) (message (string (funcall (foo 66))))
First, the quote ('
) is unnecessary in the second, because in Emacs Lisp lambda forms are self-evaluating. That is, '(lambda (...) ...)
generally acts the same as (lambda (...) ...)
.
But what does the backquote (`
), instead of quote ('
), do?
Inside a backquoted expression, a comma (,
) means replace the next expression by its value, that is, evaluate it. So this:
`(lambda () ,x)
means create and return a list whose first element is the symbol lambda
(that's not evaluated), whose second element is ()
(that's not evaluated), and whose third element is the value of variable x
. It's equivalent to evaluating this code, which uses function list
:
(list 'lambda '() x)
That's what you want: replace x
by its current value (in this case, its value inside the function foo
, that is, the value of foo
's argument).
But this:
'(lambda () x)
(and likewise, because a lambda form is self-evaluating, (lambda () x)
) returns this list: (lambda () x)
. And when that's evaluated using dynamic scoping (the default scoping regime in Emacs Lisp), x
is unbound - it has no value. So a void-variable error is raised.
Upvotes: 0
Reputation: 5030
This happens because Emacs Lisp is dynamically scoped thus foo
returns a lambda where x
is free. That's what the error tells you.
To do a closure in Emacs Lisp you have to use lexical-let
which simulates a lexical binding and therefore allows you to make a real closure.
(defun foo (x)
(lexical-let ((x x))
(lambda () x)))
(message (string (funcall (foo 66))))
Here are some links from the Emacs Wiki:
Note that you could have defined x
with a let like this:
(defun foo (x)
(lambda () x))
(message (string (let ((x 66)) (funcall
(foo 'i-dont-care)))))
Upvotes: 3