Next: Obsolete Macros, Up: Obsolete Features [Contents][Index]
The following macros are extensions to Common Lisp, where all bindings are lexical unless declared otherwise. These features are likewise obsolete since the introduction of true lexical binding in Emacs 24.1.
This form is exactly like let
except that the bindings it
establishes are purely lexical.
Lexical bindings are similar to local variables in a language like C:
Only the code physically within the body of the lexical-let
(after macro expansion) may refer to the bound variables.
(setq a 5) (defun foo (b) (+ a b)) (let ((a 2)) (foo a)) ⇒ 4 (lexical-let ((a 2)) (foo a)) ⇒ 7
In this example, a regular let
binding of a
actually
makes a temporary change to the global variable a
, so foo
is able to see the binding of a
to 2. But lexical-let
actually creates a distinct local variable a
for use within its
body, without any effect on the global variable of the same name.
The most important use of lexical bindings is to create closures. A closure is a function object that refers to an outside lexical variable (see Closures in GNU Emacs Lisp Reference Manual). For example:
(defun make-adder (n) (lexical-let ((n n)) (lambda (m) (+ n m)))) (setq add17 (make-adder 17)) (funcall add17 4) ⇒ 21
The call (make-adder 17)
returns a function object which adds
17 to its argument. If let
had been used instead of
lexical-let
, the function object would have referred to the
global n
, which would have been bound to 17 only during the
call to make-adder
itself.
(defun make-counter () (lexical-let ((n 0)) (cl-function (lambda (&optional (m 1)) (cl-incf n m))))) (setq count-1 (make-counter)) (funcall count-1 3) ⇒ 3 (funcall count-1 14) ⇒ 17 (setq count-2 (make-counter)) (funcall count-2 5) ⇒ 5 (funcall count-1 2) ⇒ 19 (funcall count-2) ⇒ 6
Here we see that each call to make-counter
creates a distinct
local variable n
, which serves as a private counter for the
function object that is returned.
Closed-over lexical variables persist until the last reference to
them goes away, just like all other Lisp objects. For example,
count-2
refers to a function object which refers to an
instance of the variable n
; this is the only reference
to that variable, so after (setq count-2 nil)
the garbage
collector would be able to delete this instance of n
.
Of course, if a lexical-let
does not actually create any
closures, then the lexical variables are free as soon as the
lexical-let
returns.
Many closures are used only during the extent of the bindings they
refer to; these are known as “downward funargs” in Lisp parlance.
When a closure is used in this way, regular Emacs Lisp dynamic
bindings suffice and will be more efficient than lexical-let
closures:
(defun add-to-list (x list) (mapcar (lambda (y) (+ x y))) list) (add-to-list 7 '(1 2 5)) ⇒ (8 9 12)
Since this lambda is only used while x
is still bound,
it is not necessary to make a true closure out of it.
You can use defun
or flet
inside a lexical-let
to create a named closure. If several closures are created in the
body of a single lexical-let
, they all close over the same
instance of the lexical variable.
This form is just like lexical-let
, except that the bindings
are made sequentially in the manner of let*
.
Next: Obsolete Macros, Up: Obsolete Features [Contents][Index]