Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

newbie got confused about let and defparameter

306 views
Skip to first unread message

Seven Hong

unread,
Jul 6, 2012, 8:32:45 PM7/6/12
to
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?

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?

Thanks!

Pascal J. Bourguignon

unread,
Jul 6, 2012, 9:11:01 PM7/6/12
to
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 {}.

Seven Hong

unread,
Jul 6, 2012, 9:34:26 PM7/6/12
to
Wow! That is really a systematic explanation! Thanks Pascal!

So in order to fully understand what are you saying, I think I need to go check out what are special lexcical variables first, maybe my book will eventually mention those later though.. But with your code I still can get the sense from your explanation, I appreciate that :-)

On Friday, July 6, 2012 9:11:01 PM UTC-4, pjb wrote:

drlat

unread,
Jul 7, 2012, 3:22:59 AM7/7/12
to
Hi Pascal,

I try to read all your posts. I really think that you should write a
book on Lisp. Have you given any thought to that?

drl
drlat


Pascal J. Bourguignon

unread,
Jul 7, 2012, 3:35:29 AM7/7/12
to
drlat <l...@dayspringpublisher.com> writes:

> I try to read all your posts. I really think that you should write a
> book on Lisp. Have you given any thought to that?

Yes. That would be a lot of work, and I'm still wondering if there'd be
a market for it. Well, it looks like PCL had some success.

ccc31807

unread,
Jul 11, 2012, 5:09:44 PM7/11/12
to
On Jul 7, 3:35 am, "Pascal J. Bourguignon" <p...@informatimago.com>
wrote:
> drlat <l...@dayspringpublisher.com> writes:
> > I try to read all your posts. I really think that you should write a
> > book on Lisp.  Have you given any thought to that?
>
> Yes.  That would be a lot of work, and I'm still wondering if there'd be
> a market for it.  Well, it looks like PCL had some success.

As Conrad Barski's 'Land of Lisp' although I'm not sure if either one
would think that the remuneration by itself would be worth the effort.

It seems that O'Reilly wanted a Lisp book, and Nick Levine was willing
to oblige. I've been hoping that someone (or someones) would develop
an interest in furthering that project.

If you're doing it for the money, you're doing it for the wrong
reason. I don't want to get into a philosophical or a moral
discussion, but in general and very broadly, people pay money to those
who engage in behavior that people find valuable, and behavior driven
by money tends to be less valuable to other people than behavior
driven by other motives. Max Weber discussed this problem at length in
'The Protestant Ethic and the Spirit of Capitalism'.

CC.
0 new messages