Seven Hong <
sir.sev...@gmail.com> writes:
> Hello all:
>
> I am currently learning Common Lisp, and I got confused with let and
> defparameter.
>
> In my book it says that let and defparameter are creating local and
> global variables, I went to my emacs and I used defparameter to creat
> a global variable called *globtest*, with value 8; then I typed (let
> ((*globtest* 9)) *globtest*) and it displayed 9. Could some one
> explain what was going on here?
LET can create both dynamic and lexical bindings. It depends on the
variable. If it is a special variable, then LET creates a dynamic
binding. If it is not, then LET creates a lexical binding. In both
cases, LET creates a new binding, which may shadow an "outer" binding of
a variable with the same name. Note that this "outer" binding shadowing
may be in effect in time (dynamic), or in space (lexical).
You can also have dynamic binding without a global variable.
Global Special Variable
=======================
First, a global special variable (dynamic binding):
(setf *print-case* :downcase)
(defvar *glob* 42)
(defun f ()
(format t "In ~S, ~S = ~S~%" 'f '*glob* *glob*))
(f)
In f, *glob* = 42
nil
Here, WHEN F is called, *GLOB* is bound to 42.
(let ((*glob* 'zz))
(f))
In f, *glob* = zz
nil
Here, when F is called, *GLOB* is bound to ZZ. Notice that the
binding established by LET covers lexically only the function call
(f), but NOT the body of the function F which is lexically in another
space (above). Here we have a special variable *GLOB*, which makes
LET create a dynamic (temporal) binding, and what matters, is WHEN F
is called. If it is called when *glob* is bound to 42, then it prints
42; if it is called when *glob* is bound to ZZ, then it prints ZZ.
Local Special Variable
======================
Now, a special variable (dynamic binding), but without a global declaration:
(setf *print-case* :downcase)
(defun g ()
(declare (special *local*))
(format t "In ~S, ~S = ~S~%" 'g '*local* *local*))
(g)
ERROR: Unbound variable: *local*
Here, WHEN F is called, *LOCAL* is not bound to anything.
(let ((*local* 'zz))
(g))
ERROR: Unbound variable: *local*
Here, LET creates a LEXICAL binding. Since no global declaration of
*LOCAL* as a special variable has been made, it's a lexical variable,
that is visible only in the body of LET. When G is called, we execute
the body of G, which is OUTSIDE of the lexical scope of that LET, and
the special variable *LOCAL* has no binding at that time.
(let ((*local* 'zz))
(declare (special *local*))
(g))
In g, *local* = zz
nil
Here, LET creates a DYNAMIC binding for *LOCAL*. During the execution
of the body of this LET, *LOCAL* will be bound to ZZ. So WHEN G is
called, the value of *LOCAL* is ZZ and G can print it.
Local Lexical Variable
======================
Finally, local lexical variables are only accessibly in the lexical
scope, ie. the SPACE where the variable is visible:
(defun h (thunk)
(funcall thunk))
(defvar *thunk-1*)
(defvar *thunk-2*)
(let ((local 42))
(format t "In ~S, ~S = ~S~%" 'outer 'local local) ; 1
(setf *thunk-1* (lambda () ; 1
(format t "In ~S, ~S = ~S~%" ; 1
'thunk-1 'local local))) ; 1
(h *thunk-1*) ; 1
(let ((local 'zz)) ; 1*
(format t "In ~S, ~S = ~S~%" 'inner 'local local) ; 2
(setf *thunk-2* (lambda () ; 2
(format t "In ~S, ~S = ~S~%" ; 2
'thunk-2 'local local))) ; 2
(h *thunk-2*) ; 2
(format t "In ~S, ~S = ~S~%" 'inner 'local local)) ; 2
(format t "In ~S, ~S = ~S~%" 'outer 'local local)) ; 1
In outer, local = 42
In thunk-1, local = 42
In inner, local = zz
In thunk-2, local = zz
In inner, local = zz
In outer, local = 42
nil
Here, we have two lexical variables named LOCAL, in two different
lexical scopes created by the two LET. Each scope is marked,
SPACIALLY, by the comments "; 1" or "; 2". To know what variable is
referenced by a symbol in a lexical scope, you only need to know WHERE
the variable reference is situated, not WHEN it is executed. (That's
the big advantage of lexical binding over dynamic binding: it allows
to understand the code much more easily, by just looking at the text
of the source code, without having to think about how it behave in
time). Now, the body of the function H is way OUTSIDE of those
lexical scope. There is no way for H to refer (directly) the lexical
variables outside of its scope such has the variables named LOCAL.
But the anonymous functions we assign to *thunk-1* and *thunk-2* are
in those lexical scopes, and therefore can see those lexical
variables. The function bound to *thunk-1* is in the first lexical
scope, so it sees the first variable LOCAL. The function bound to
*thunk-2* is in the second lexical scope, so it sees the second
variable LOCAL. It doesn't matter WHEN they are called:
(h *thunk-1*)
In thunk-1, local = 42
nil
(h *thunk-2*)
In thunk-2, local = zz
nil
If we call them AFTER (time) we get out of the lexical scope where
they were defined, they still return the value of their lexical
variable. It just doesn't matter WHEN (time) they're called, but only
WHERE (space) they are defined.
Notice I marked with a "1*" the binding list of the second LET. This
is because the initialization expressions of a LET are evaluated in
the outer lexical scope, not in the new scope created by that LET.
This would allow you to create a new lexical variable, using the outer
lexical variable to initialize it:
(let ((i 0))
(let ((i (1+ i)))
(print i))
i)
prints 1 and returns 0
> And then I assumed, well maybe in LISP one gloabl variable and one
> local variable can have same name, who knows, so I typed *globtest*
> again and it displayed 8. So does this tell my assumption is correct?
There are two dimensions: global/local and special/lexical.
CL doesn't provide global lexical variables, but symbol macros can be
bound in a global lexical scope, so we can implement global lexical
variables using global symbol macros. Search for macros such as
deflexical, defglobal, etc.
--
__Pascal Bourguignon__
http://www.informatimago.com/
A bad day in () is better than a good day in {}.