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

Idiot's guide to special variables take 2

204 views
Skip to first unread message

Erann Gat

unread,
Nov 9, 2002, 8:03:50 PM11/9/02
to

Edi Weitz asked me to update my "Idiot's guide to special variables" for
his Common Lisp Cookbook page. Before I sent him my draft I thought I'd
solicit some comments. I'm particularly interested in hearing from
non-Lisp-experts (who are the target audience) to see if this makes any
sense to them.

Thanks,
Erann

Please send comments by email if possible to g...@jpl.nasa.gov.

--------

The Complete Idiot's Guide to Special Variables and Lexical Closures

By Erann Gat
November 2002

Variables

The intuitive concept of a variable is very straighforward: it's a
NAME that is associated with a VALUE. The value of a variable can be
changed by ASSIGNING a new value to the variable, e.g.:

{
int x = 1; Create a new variable named X with value 1
x = 2; Change the value of the variable named X to 2
}

This is about as much as the typical C programmer knows about variables
because creating variables and assigning them are the only two things
you can do with variables in C. But in Lisp, variables are a much richer
and more powerful concept. And more complicated.

In C the name of a variable is not a first-class data object. Because
of this, one usually does not distinguish in C between the name of a
variable and its value. "X" usually means the same thing as "the value
of the variable named 'X'" because the value is all there is. So pointing
out that "the value of the variable named 'X'" also means the same thing
as "the contents of the memory location associated with the name 'X'"
sounds unnecessarily pedantic.

In Lisp the value is not all there is. The NAMES of variables are
first-class data objects called SYMBOLS, and the MEMORY LOCATIONS where
the values of variables are stored are pseudo-first-class entities
called BINDINGS. (I call them pseudo-first-class because unlike true
first-class entities, bindings cannot be directly passed as arguments or
returned as values.) Symbols and bindings actually exist in C too, but
they are hidden in the deep recesses of the compiler where most programmers
never see them. In Lisp, symbols and bindings are made available to the
programmer as part of the language. The result is flexibility and power
that most C programmers never dream of. And, unfortunately, the result
is also often a great deal of confusion. Hence this guide.

Symbols

We get into terminological trouble right away because the word "NAME"
is used in two different ways when discussing variables. In Lisp, the
name of a variable is a symbol, and a symbol is a first-class data
object that has, among other things, a name which is a string of
characters. So the name of a variable is a symbol, and the name of
a symbol is a string. (And strings don't have names.)

Symbols are referred to by their names, but they are distinguished
from their names by omitting the double-quotes that are traditionally
used to denote strings. So, for example, we refer to a symbol whose
name is "FOO" by writing FOO.

There is a Lisp function for creating symbols called MAKE-SYMBOL. For
example, (MAKE-SYMBOL "FOO") returns a symbol whose name is the string
"FOO". (There is also a function, SYMBOL-NAME, which is sort of the
opposite of make-symbol: given a symbol it returns the string that is
the symbol's name.)

If you try (make-symbol "FOO") you may be surprised to find that the
result is not FOO but #:FOO. #:FOO is indeed a symbol whose name is
"FOO" so I haven't really lied to you, but clearly there is more going
on here than meets the eye. To understand the difference between the
symbol FOO and the symbol #:FOO we have to take a brief digression from
our discussion of variables and talk about packages.

Packages

Different symbols can have the same name. If you call (make-symbol
"FOO") twice you will get two distinct symbols both of which have the
name "FOO". (In fact, it's possible to have two distinct symbols
whose names are EQ.) Having two symbols that look identical but are
in fact different can be confusing, and so symbols are usually
collected together in aggregations called PACKAGES, which have the
useful property that they may not contain distinct symbols with the
same name.

Adding a symbol to a package is called INTERNING the symbol in the
package, and it's done with a function called INTERN. INTERN works
kind of like MAKE-SYMBOL in that it takes a string as an argument and
returns a symbol whose name is that string. But unlike MAKE-SYMBOL,
two different calls to INTERN with the same name will return the SAME
symbol, not two different symbols with the same name. That is:

(eq (make-symbol "FOO") (make-symbol "FOO")) --> NIL
(eq (intern "FOO") (intern "FOO")) --> T

A symbol can only be interned in one package at a time. Symbols that
are not interned in any package are printed with a leading "#:" to
alert you to the fact that two of them may not be the same symbol even
though they look alike.

You can now forget most of this and just remember that whenever you
see FOO it means a symbol named "FOO", and that any time you see FOO
it's the same symbol.


Bindings

A BINDING is an association between a symbol and some other object.
(Strictly speaking, a binding is an associating between a *name*
and some other object. Names in Common Lisp are usually symbols,
but in some circumstances can be strings.)

Common Lisp symbols can have many different kinds of bindings.
Strictly speaking, the association between a symbol and its name is a
binding, although it's not usually spoken of that way. In addition to
its name (which must be a string) a symbol can be associated with a
VALUE (which can be any object) and a FUNCTION (which must be a
function object) and a PROPERTY LIST. That is, a symbol has a value
binding, and a function binding, and a property list binding (and a
name binding). Actually, symbols can have two different kinds of
value bindings. But we're getting ahead of ourselves.

(N.B. One of the major differences between Common Lisp and Scheme is
that Common Lisp symbols have all these bindings simultaneously, while
Scheme symbols only have one binding at a time: the value binding.)

If all this is too complicated and esoteric, just think of a binding
as a memory location where the value of a variable is stored. The
important thing is that the same variable can have different bindings
at different times, which is to say, the value of a variable can be
stored in different memory locations at different times. The phrase
"creating a binding for a variable" means the same thing as "allocating
a memory location in which to store the value of that variable."

The crucial thing to keep in mind is that there is a distinction
between a BINDING (the memory location where the value of a variable
is stored) and its CONTENTS (the value stored in that memory location).
The contents of a binding is often referred to as the "value" of the
binding (or the value of the variable), which can be confusing because
the "value of a binding" is a completely different thing from the "value
binding". The standard uses the term "that which the binding denotes"
in order to avoid this confusion, but that's a bit pedantic for my
tastes.

Fortunately, the concept of special variables (which is the topic at hand
in case you'd forgotten) deals only with value bindings, so we can forget
about all the other bindings that exist in Common Lisp and just use the
term "binding" from here on out to mean "value binding". The "value of
a binding" then means the "value of the value binding", that is, the
contents of the memory location where the value of the variable is stored.

To illustrate the difference between values and bindings, consider
the following code:

(let ((x 1)) ; Establish a binding for the symbol X
(print x)
(let ((x 2)) ; Establish a second binding for X
(print x)
(setq x 3) ; Change the value of the second binding
(print x))
(print x)) ; The value of the first binding is unchanged

This will print "1 2 3 1". The SETQ changes the value of the second
(or inner) binding of X, not the first (or outer) binding.

Because talking about multiple bindings for the same symbol can get
confusing, I'm going to adopt the following notation: X*n means the
nth binding of symbol X. Using this notation we can describe the
above code as follows: the first LET form establishes binding X*1.
The second LET form established binding X*2. The SETQ changes the
value of X*2 but not X*1.

(Actually, LET establishes new bindings every time it is run, so
the first time you run the above code you get X*1 and X*2. The second
time you get X*3 and X*4, and so on. Some forms establish bindings at
compile time, not run time, so you get the same binding every time the
code is run.)

Scope

The SCOPE of a binding is the parts of the program from which a
binding is VISIBLE, that is, from which the value of the binding
can be accessed by referring to the symbol. For example, the scope
of a binding established by a LET is the body of the LET, e.g.:

(defun foo()
(let ((x 1) (y 2)) ; Establish binding X*1 and Y*1
(foo x y) ; X refers to binding X*1, Y refers to Y*1
(let ((y 2) (z 3)) ; Establish binding Y*2 and Z*1
(baz x y z)) ; Refers to X*1, Y*2 and Z*1. Y*1 cannot be
; accessed here. It is SHADOWED by Y*2.
z) ; This does NOT refer to Z*1. Z*1 is out of scope.

What about Z? Z is what is referred to as a FREE VARIABLE. It is a
variable which has no LEXICALLY APPARENT BINDING, that is, it has no binding
established by its surrounding code. Normally this would mean that when
we call FOO we would get an error:

(foo) --> ERROR: Z is unbound

But we can create a binding for Z using, for example, the DEFVAR special
form:

(defvar z 3) ; Establish binding Z*D1

Now FOO no longer generates an error:

(foo) --> 3 ; Refers to the value of Z*D1

Note that the binding established by DEFVAR seems to be of a fundamentally
different nature than a binding established by LET. Bindings established
by LET go away when the LET form returns. By constrast, a binding established
by DEFVAR continues to exist after the DEFVAR returns. Also, whether
a particular reference to Z refers to the binding established by DEFVAR
depends on the order in which the code runs: if the reference to Z
happens before the defvar then it's a error. If it happens afterwards,
then it refers to the binding established by the DEFVAR.

DEFVAR does in fact establish a different sort of binding, known as
a DYNAMIC binding, which is why I referred to it as Z*D1 instead of just
Z*1. But we're getting ahead of ourselves again.


Lexical versus dynamic scope

Now consider the following code:

(defvar z 1)
(defun foo () z) ; Establish binding Z*D1
(defun baz ()
(let ((z 2)) ; Establish binding Z*2
(foo)))

What does (BAZ) return? Well, it returns the result of calling FOO, which
returns the value of Z, but which one? There are two different bindings
of Z at this point - one established by the DEFVAR (Z*D1) and one
established by the LET (Z*2). Which binding is in scope when FOO is
called from inside BAZ? Does Z*2 shadow Z*D1 in the same way that Y*2
shadowed Y*1?

The rule for LET bindings is that their scope is the body of the
LET, but that can mean two different things. It can mean the body of
the LET as defined by the CODE, or the body of the LET as defined by
the EXECUTION PATH. The reference to Z is inside the body of the LET
according to the execution path, but not according to the structure of
the code (since the code for FOO is outside the code for BAZ).

(Re-read the preceding paragraph until you're sure you understand it.
It's the key to understanding everything else.)

It turns out that you have a choice. Common Lisp provides both
scoping disciplines. If the scope is defined by the execution path
that is known as DYNAMIC SCOPE. If the scope is defined by the
structure of the code that is known as LEXICAL SCOPE.

(Note that the lexical scope of a binding can always be determined at
compile time, while the dynamic scope cannot in general be determined
until the program runs. If that is not obvious to you at this point,
go back and re-read this section again.)

How do you choose? Unfortunately, this is yet another point where things get
a little complicated. In order to ease into the explanation I'm going to
first illustrate with a hypothetical language that doesn't really exist
(though you can implement it in Common Lisp). In this hypothetical language,
there are two LET forms, LLET and DLET. LLET always introduced lexical
bindings (i.e. bindings whose scope is the lexical body of the LLET) and
DLET always introduces dynamic bindings (that is, bindings whose scope is
*any* code that runs inside the body of the DLET regardless of where it is
defined). For example:

(defvar z 1) ; Establish binding Z*D1
(defun foo () z) ; Return the current dynamic binding of Z
(llet ((z 2)) ; Create Z*1, a lexical binding
(foo)) --> 1 ; which does not shadow Z*D1
(dlet ((z 2)) ; Create Z*D2
(foo)) --> 2 ; which does shadow Z*D1

Now consider:

(dlet ((z 1))
(llet ((z 2))
z))

or

(llet ((z 1))
(dlet ((z 2))
z))

Now we have *two* bindings for Z, one lexical and one dynamic, in scope at the
same time. Which one are we referring to? Well, we could allow ourselves
to refer to both with hypothetical LVAL and DVAL constructs that allow us to
refer to the values of the lexical and dynamic bindings respectively:

(defvar z 1) ; Establish binding Z*D1
(defun foo () z) ; Z must refer to the current dynamic binding of Z because
; there is no lexical binding
(d-let ((z 2))
(llet ((z 3))
; Simply referring to Z here would be ambiguous
(list (lval 'z) ; The value of the current lexical binding of Z
(dval 'z) ; The value of the current dynamic binding of Z
(foo) ; and our old friend for good measure
))) --> (3 2 2)

Now the reality.

Common Lisp's LET combines the functionality of both LLET and DLET. Variable
references can be either lexical or dynamic depending on the context. And
there is a DVAR (called SYMBOL-VALUE) but no LVAR.

By default, LET creates lexical bindings (i.e. bindings whose scope are
defined by the lexical structure of the code, not by the runtime execution).
To create a dynamic binding you have to use a special declaration:

(let ( (x 1) (y 2) ) ; Lexical bindings by default
(declare (special x)) ; unless you say otherwise
...)

In Common Lisp, SPECIAL and dynamic mean the same thing.

So, for example:

(defun baz ()
(let ( (x 2) )
(list x (symbol-value 'x)))) ; Same as (list (lval 'x) (dval 'x))

(defun foo ()
(let ( (x 1) ) ; Bind X
(declare (special x)) ; ... as a dynamic binding
(baz)))

(foo) --> (2 1)

What happens when we call FOO is that we establish a dynamic binding
for X with value 1. We then call BAZ, which establishes a lexical binding
for X with value 2. The reference to X by itself returns the value of
the lexical binding, while SYMBOL-VALUE gives us access to the dynamic
binding.

The evils of DEFVAR

There is one more wrinkle. Consider:

(defvar x 1)
(defun baz () x)
(defun foo ()
(let ((x 2)) ; Bind X, no special declaration means it's lexical, but...
(baz)))

Based on what I've told you so far you should expect (foo) to return 1. But
in fact (foo) returns 2. Why? Becase DEFVAR does more than just establish
a dynamic binding for X. It pervasively declares all references to X and
all subsequent bindings for X to be dynamic (or special -- same thing). In
other words, DEFVAR turns X (permanently and pervasively) into a special
variable.

In fact, it is actually impossible on a strict reading of the standard
to create a dynamic binding for a symbol without turning it into a (globally)
special variable. This is why in many Lisp implementations if you type
(SETQ X 1) without a DEFVAR you will get a warning. Strictly speaking,
SETQ does assignment, that is, it modifies a binding (a symbol's value binding
to be precise). But at the top level a symbol doesn't *have* a value
binding until you create one, e.g. with DEFVAR.

Most implementations assume that since there are no lexically apparent
bindings at the top level, that any top-level assignment is intended to
modify the dynamic binding, and so they will create one for you automatically
if you do a SETQ without a DEFVAR. But at least one implementation (CMUCL)
goes further: if you do a SETQ at the top level it will not only create a
dynamic binding for that symbol, but it will also globally declare that
symbol to be special just as if you had done a DEFVAR. This can lead to
very surprising behavior if you don't have a deep understanding of what is
going on. Once a symbol has been DEFVARd it is no longer possible to
create a lexical binding for it.

Some people consider this a feature. Others (myself included) think it's
a bug. Regardless, there is universal agreement that it can cause
confusion, and so there is a convention that is invariably followed: all
special variables should have names that are preceded and followed by
asterisks, e.g. *X*.

(Editorial comment: IMO, if you're going to have the concept of
a pervasively special variable and acknowledges that a typographical
convention is necessary in order to avoid confusion, then you ought
to build that typographical convention into the language design. It
should be the case that all variables whose names start with an asterisk
are automatically declared special, and all names that don't start with
an asterisk are automatically lexical.)

By the way, it is also possible to have top-level (or global) lexical
bindings for symbols. This is what Scheme does. Scheme gets away with
this because *all* bindings in Scheme are lexical; there are no dynamic
bindings. Top-level lexicals could in theory be added to Common Lisp,
but you'd have to figure out how to make them co-exist with dynamic
bindings. (There have been designs proposed in the past.)

Lexical closures

Since we've now covered everything you need to know to understand
lexical closures we might as well go ahead and talk about them.

Consider:

(defun foo ()
(let ((x 1)) ; Create a (lexical) binding for X
x ; X is in scope here
)) ; X goes out of scope here

FOO returns the value of X, not the binding. It is not possible to
return a binding because bindings are not first-class entities.
However, it is possible to "capture" a binding inside of a function
object and return *that* instead! Consider:

(defun baz ()
(let ((x 1)) ; Create a (lexical) binding for X
(lambda () (setq x (+ x 1))) ; X is in scope here
))

Now when we call (baz) we get back a function object (created by the
LAMBDA special form). This function object has a reference to X inside
it which refers to the lexical binding created by the LET.

Note that I haven't followed my usual pattern and given this binding
the name X*1. This is because a new binding is created every time BAZ
is called:

(setq *x1* (baz)) ; Returns a closure over binding X*1
(setq *x2* (baz)) ; Returns a closure over binding X*2
(funcall *x1*) --> 2 ; Increment X*1
(funcall *x1*) --> 3 ; again
(funcall *x1*) --> 4 ; one more time
(funcall *x2*) --> 2 ; Increment X*2

One last example:

(defun up-n-down ()
(let ((x 0))
(list (lambda () (setq x (+ x 1)))
(lambda () (setq x (- x 1))))))

(setq *l1* (up-n-down)) ; X bound to X*1
(setq *l2* (up-n-down)) ; X bound to X*2
(funcall (first *l1*)) --> 1
(funcall (first *l1*)) --> 2
(funcall (first *l1*)) --> 3
(funcall (second *l1*)) --> 2
(funcall (first *l2*)) --> 1
(funcall (first *l2*)) --> 2
(funcall (first *l2*)) --> 3
(funcall (second *l2*)) --> 2

By now this should all make perfect sense. When we call up-n-down we
get a new binding for X (established by the LET). This binding is then
captured by the LAMBDA forms. Both lambdas in the list capture the
*same* binding every time up-n-down is called, and every time we call
up-n-down we get a (one) new binding.

Notice how much the list returned by up-n-down resembles an object with
one slot and two methods. That is in fact precisely what it is. This is
why when a Lisp programmer learns a new programming language one of the
first questions they will ask is, "does it have closures?" Because if
you have closures you can build an OO system (and just about anything
else you need) out of them. It is, alas, much harder to go the other
way.

Nils Goesche

unread,
Nov 9, 2002, 9:36:47 PM11/9/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> Edi Weitz asked me to update my "Idiot's guide to special
> variables" for his Common Lisp Cookbook page. Before I sent
> him my draft I thought I'd solicit some comments. I'm
> particularly interested in hearing from non-Lisp-experts (who
> are the target audience) to see if this makes any sense to
> them.

I don't know if I still qualify as a non-Lisp-expert, but I'll
answer anyway :-) Very nice text -- just a few points:

> Lexical versus dynamic scope
>
> Now consider the following code:
>
> (defvar z 1)
> (defun foo () z) ; Establish binding Z*D1
> (defun baz ()
> (let ((z 2)) ; Establish binding Z*2
> (foo)))
>
> What does (BAZ) return? Well, it returns the result of calling
> FOO, which returns the value of Z, but which one? There are
> two different bindings of Z at this point - one established by
> the DEFVAR (Z*D1) and one established by the LET (Z*2). Which
> binding is in scope when FOO is called from inside BAZ? Does
> Z*2 shadow Z*D1 in the same way that Y*2 shadowed Y*1?
>
> The rule for LET bindings is that their scope is the body of
> the LET, but that can mean two different things. It can mean
> the body of the LET as defined by the CODE, or the body of the
> LET as defined by the EXECUTION PATH. The reference to Z is
> inside the body of the LET according to the execution path, but
> not according to the structure of the code (since the code for
> FOO is outside the code for BAZ).
>
> (Re-read the preceding paragraph until you're sure you
> understand it. It's the key to understanding everything else.)

You are right, it is a bit hard to understand. I think it would
be much easier to explain if you introduced the usual terms
``lexical and dynamical environment´´. A closure (and a
function) is always called with two environments, the (current)
dynamical environment and the lexical environment at creation
time (of the closure) (which can still be updated because what
gets closed over is a set of bindings, not a set of values). The
only thing left to understand is which is used for lookup, then.

> In fact, it is actually impossible on a strict reading of the
> standard to create a dynamic binding for a symbol without
> turning it into a (globally) special variable.

Hmmm. How would you call this:

CL-USER 50 > (defun foo (n)
(declare (special x))
(+ x n))
FOO

CL-USER 51 > (defun blark (x)
(declare (special x))
(foo 42))
BLARK

CL-USER 52 > (blark 7)
49

CL-USER 53 > (defun bimbo (x)
(foo 42))
BIMBO

CL-USER 54 > (bimbo 13)

Error: The variable X is unbound.
1 (continue) Try evaluating X again.
2 Return the value of :X instead.
3 Specify a value to use this time instead of evaluating X.
4 Specify a value to set X to.
5 (abort) Return to level 0.
6 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed, or :? for other options

CL-USER 55 : 1 >

> Now when we call (baz) we get back a function object (created
> by the LAMBDA special form).

LAMBDA is actually not a special form in Common Lisp.

Regards,
--
Nils Gösche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID #xD26EF2A0

Erann Gat

unread,
Nov 9, 2002, 9:56:14 PM11/9/02
to
In article <873cqar...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

> > In fact, it is actually impossible on a strict reading of the
> > standard to create a dynamic binding for a symbol without
> > turning it into a (globally) special variable.
>
> Hmmm. How would you call this:

Doh! I meant to say "global binding" (or maybe "top-level binding").

Actually, I'm not really sure even that is true any more. The standard
specifically says (parenthetically) that you can do (setf symbol-value) on
an unbound symbol without raising an exception (though the standard is
silent on what the effect of this ought to be).

E.

Nils Goesche

unread,
Nov 10, 2002, 1:53:46 AM11/10/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

It is explicitly undefined behavior by 1.4.4.3: If you read
carefully the dictionary entry of (SETF SYMBOL-VALUE), you'll
notice a little restriction:

# Arguments and Values:

# symbol---a symbol that must have a value.

This refers to (SETF SYMBOL-FUNCTION), too.

As for the question whether we can ``create a global binding
without turning it into a (globally) special variable´´ -- the
answer is yes: DEFCONSTANT :-) Otherwise there is simply no
defined way to create such a global binding without making it
dynamic:

``3.1.2.1.1 Symbols as Forms´´ says that when a symbol that is
not a symbol-macro is evaluated, then it names a variable, which
is either lexical, dynamic or constant. We are not interested in
a constant or dynamic binding, which leaves only a ``lexical
global´´ binding as a possibility. There is no such thing,
though, by definition: Lexical scope is always restricted to an
establishing form.

If you /do/ set the SYMBOL-VALUE of a symbol that is not yet in
the global environment, you can probably evaluate it afterwards,
so it must be a dynamic variable now, as we have just seen. So,
now, for this to make sense, (SETF SYMBOL-VALUE) would have to
check, every time it is called, whether our symbol names a
variable in the global environment, and if not, put it in there.
If nobody kept track of what in the global environment is,
/every/ symbol would be part of the global environment, and,
because we don't want them all to be constants, /every/ symbol
would be the name of a dynamic variable!

I guess this is why it's undefined behavior. Hm, still a lot of
food for thought :-)

Nils Goesche

unread,
Nov 10, 2002, 2:08:33 AM11/10/02
to
I <n...@cartan.de> wrote:

> This refers to (SETF SYMBOL-FUNCTION), too.

Err, actually it refers to (SETF SYMBOL-VALUE), too.

Sorry,

Nils Goesche

unread,
Nov 10, 2002, 1:40:44 PM11/10/02
to
After a hint by Paul Foley, I changed my mind...

I <n...@cartan.de> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
>
> > > > In fact, it is actually impossible on a strict reading of the
> > > > standard to create a dynamic binding for a symbol without
> > > > turning it into a (globally) special variable.

> > I meant to say "global binding" (or maybe "top-level
> > binding").

> > Actually, I'm not really sure even that is true any more.
> > The standard specifically says (parenthetically) that you can
> > do (setf symbol-value) on an unbound symbol without raising
> > an exception (though the standard is silent on what the
> > effect of this ought to be).
>
> It is explicitly undefined behavior by 1.4.4.3: If you read
> carefully the dictionary entry of (SETF SYMBOL-VALUE), you'll
> notice a little restriction:
>
> # Arguments and Values:
>
> # symbol---a symbol that must have a value.
>

> This refers to (SETF SYMBOL-[VALUE]), too.

Which appears to be just an oversight (see SET).

> As for the question whether we can ``create a global binding
> without turning it into a (globally) special variable´´ -- the
> answer is yes: DEFCONSTANT :-) Otherwise there is simply no
> defined way to create such a global binding without making it
> dynamic:
>
> ``3.1.2.1.1 Symbols as Forms´´ says that when a symbol that is
> not a symbol-macro is evaluated, then it names a variable, which
> is either lexical, dynamic or constant. We are not interested in
> a constant or dynamic binding, which leaves only a ``lexical
> global´´ binding as a possibility. There is no such thing,
> though, by definition: Lexical scope is always restricted to an
> establishing form.

And here is where I erred: There /is/ a global lexical
environment; it is called the null lexical environment, and it is
here where the binding is established. This is not exactly made
explicit somewhere but there seems to be no other possible
interpretation. Comments in Notes sections like ``set cannot
change the value of a lexical variable.´´ notwithstanding.

Harald Hanche-Olsen

unread,
Nov 10, 2002, 1:36:42 PM11/10/02
to
+ g...@jpl.nasa.gov (Erann Gat):

| Edi Weitz asked me to update my "Idiot's guide to special variables" for
| his Common Lisp Cookbook page. Before I sent him my draft I thought I'd
| solicit some comments. I'm particularly interested in hearing from
| non-Lisp-experts (who are the target audience) to see if this makes any
| sense to them.

Well, I consider myself a non-Lisp-expert, but hopefully not the
complete idiot that you're targeting (if I can take your title at face
value).

| Please send comments by email if possible to g...@jpl.nasa.gov.

I'm afraid I will have to decline, partly because I read news off-line
(and responding by email is therefore somewhat painful) but more
importantly, because I think it would be useful if some /real/ experts
were to comment on my comments.

I have only two brief comments really:

Firstly, I think the discussion of symbols and packages belongs
elsewhere. It really doesn't help understanding to get that mixed in
with the whole lexical vs dynamic issue. In other words, make this
guide into two separate guides, and it will work much better.

Secondly, aren't you falling into the common trap of confusing scope
and extent? To my limited understanding, the scope of a variable is
the part of the source code in which the variable is visible. A
lexical variable is visible only within the block in which it is
bound, whereas a special variable is visible everywhere, except where
it is shadowed by a lexical variable (and you can get around even that
restriction by using symbol-value). On the other hand, the extent of
a special variable (or binding) is the set of times during the
execution when the binding is in effect, which is all the time from
the time it is first bound until execution leaves the binding form,
with the exception of the times when this binding is shadowed by other
bindings.

It seems that the Glossary section of the CLHS agrees with me on this
point. Maybe it is difficult for beginners to make this distinction,
but I think it should not be that hard to explain: A set of points in
source code really is a very different concept from a set of times,
and I think you are doing your readers a disservice by mixing the two
together.

--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?

bru...@mail.dotcom.fr

unread,
Nov 14, 2002, 7:44:25 AM11/14/02
to
g...@jpl.nasa.gov (Erann Gat) writes:
> Edi Weitz asked me to update my "Idiot's guide to special variables" for
> his Common Lisp Cookbook page. Before I sent him my draft I thought I'd
> solicit some comments. I'm particularly interested in hearing from
> non-Lisp-experts (who are the target audience) to see if this makes any
> sense to them.

It's a good paper. I've always been confused with special variables,
now it's clear.

Thanx.

--
Frederic Brunel
(brunel @ mail.dotcom dot fr)
"You can't rush art."

thelifter

unread,
Nov 14, 2002, 7:37:16 PM11/14/02
to
g...@jpl.nasa.gov (Erann Gat) wrote in message news:<gat-091102...@192.168.1.51>...

> Symbols

I'm still a bit confused about the meaning of "NAME", it would be good
if you could produce a concise definition.

Quotes from you:

1. In Lisp the value is not all there is. The NAMES of variables are


first-class data objects called SYMBOLS, and the MEMORY LOCATIONS
where

2. So the name of a variable is a symbol, and the name of


a symbol is a string. (And strings don't have names.)

3. Symbols are referred to by their names

4. A BINDING is an association between a symbol and some other object.


(Strictly speaking, a binding is an associating between a *name*
and some other object. Names in Common Lisp are usually symbols,
but in some circumstances can be strings.)

Especially quote 4 is confusing. If I combine 4 and 2, I can construct
the following sentence:
the name of a symbol is a string and names in CL are usually
symbols!???!?

I think you can avoid the whole complication in the following way:

A) In Lisp variables are called Symbols.

B) Each Symbol has an associated String, which is also used to refer
to it. This is called the symbols name, accessible trought the
function symbol-name.

C) A BINDING is an association between a symbol and some other object.

I think this eliminated the confusion which was caused by defining a
symbol as the "name" of a variable.

> Now consider:
>
> (dlet ((z 1))
> (llet ((z 2))
> z))
>
> or
>
> (llet ((z 1))
> (dlet ((z 2))
> z))


My first reaction when I saw this code, was that the inner binding
would always overshadow the outer one. This is because from the
viewpoint of an idiot a symbol can only have ONE value binding. I
think you should make clear that a symbol can have TWO(or maybe more?)
value bindings. Then the examples become immediately clear.

> Common Lisp's LET combines the functionality of both LLET and DLET. Variable
> references can be either lexical or dynamic depending on the context. And
> there is a DVAR (called SYMBOL-VALUE) but no LVAR.

I think you misspelled: you mean DVAL and LVAL, right?
As an idiot I don't know the exact function definition of
SYMBOL-VALUE, so I had to look it up in the language specification. It
helped me to read its definition where it explicitly says that "it
returns the current value of the dynamic variable named by symbol".
After that I could understand your examples much better. General rule
of thumb: always define something before making use of it.

> Most implementations assume that since there are no lexically apparent
> bindings at the top level, that any top-level assignment is intended to
> modify the dynamic binding, and so they will create one for you automatically
> if you do a SETQ without a DEFVAR.

So that means in the following example:

(setq x 1)


(defun baz () x)
(defun foo ()
(let ((x 2)) ; Bind X, no special declaration means it's lexical,
but...
(baz)))

If I call (foo) it will return 1 on most Lisps, but if I use CMUCL it
will return 2 right?

Hope I could help you to improve the writing... I have also learned a
lot by reading it, thank you!

Erik Naggum

unread,
Nov 14, 2002, 7:44:33 PM11/14/02
to
* thel...@gmx.net (thelifter)

| A) In Lisp variables are called Symbols.

This is in fact wrong.

| I think this eliminated the confusion which was caused by defining a
| symbol as the "name" of a variable.

You have reintroduced the confusion.

| Hope I could help you to improve the writing... I have also learned a
| lot by reading it, thank you!

I fail to see what was wrong or lacking in the description in CLtL 1 or 2
or in the standard. In my view, Erann's confused expression can only
make things worse if you are already confused. As has been shown.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.

Erann Gat

unread,
Nov 14, 2002, 8:21:02 PM11/14/02
to
In article <32463098...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> I fail to see what was wrong or lacking in the description in CLtL 1 or 2
> or in the standard.

Some of the standard's text is less than illuminating for beginners. For
example, if you look up "dynamic variable" you will find this:

dynamic variable n. a variable the binding for which is in the dynamic
environment.

dynamic binding n. a binding in a dynamic environment.

dynamic environment n. that part of an environment that contains bindings
with dynamic extent. A dynamic environment contains, among other things:
exit points
established by unwind-protect, and bindings of dynamic variables, exit
points established by catch, condition handlers, and restarts.

dynamic extent n. an extent whose duration is bounded by points of
establishment and disestablishment within the execution of a particular
form. See indefinite extent. ``Dynamic variable bindings have dynamic
extent.''

If you think this is all perfectly clear then more power to you. My guide
is not for you.

E.

Erann Gat

unread,
Nov 14, 2002, 8:40:44 PM11/14/02
to
In article <b295356a.02111...@posting.google.com>,
thel...@gmx.net (thelifter) wrote:

> Especially quote 4 is confusing. If I combine 4 and 2, I can construct
> the following sentence:
> the name of a symbol is a string and names in CL are usually
> symbols!???!?

Yes, that's how it is. The word "name" is used in two different ways in
the Common Lisp spec:

binding n. an association between a name and that which the name denotes.

symbol-name returns the name of symbol. (symbol-name 'temp) => "TEMP"

Maybe I should refer to the name of a variable (which is a symbol) and the
symbol-name of a symbol (which is a string)? I'm not sure that makes it
any less confusing.

> I think you can avoid the whole complication in the following way:
>
> A) In Lisp variables are called Symbols.

But they aren't. Variables and symbols are two different things.

E.

Erik Naggum

unread,
Nov 14, 2002, 9:55:30 PM11/14/02
to
* Erann Gat

| If you think this is all perfectly clear then more power to you. My
| guide is not for you.

Understanding is an emergent property. If you seek to understand, reading
the whole standard with the express purpose of listening to someone else
and their ideas, is not foreign to you. If you do not seek to understand,
a very good way to avoid it is to expect to have everything explained just
for you.

Your "guide" is not for people who seek to understand, but for those who
seek to avoid the effort it takes. In this regard, it succeeds.

Nils Goesche

unread,
Nov 14, 2002, 10:03:04 PM11/14/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> Maybe I should refer to the name of a variable (which is a
> symbol) and the symbol-name of a symbol (which is a string)?
> I'm not sure that makes it any less confusing.

Certainly not :->

You are in a situation all teachers experience every now and
then: Either you continue telling your students a nice fairy tale
about the world, or you give up and tell them the whole story.
It is hard to tell which is the right way -- for some people one
way is better, for some people the other. People like Erik, for
instance, (and me, too, at that), would be seriously offended if
they found out that you simplified things for them just for
pedagogical reasons. You never know beforehand. I still think
your text is good (and will be even better if you mention
environments as I proposed), but it should be clear that it is
only meant as a ``ladder´´ to the /real/ thing -- I think reading
standards is simply easier if you already know more or less what
they are trying to tell you. (But, of course, this presupposes
that you are aware of the fact that your knowledge is incomplete
and you'll have to change your mind about a few things).

Matthew Danish

unread,
Nov 14, 2002, 11:33:11 PM11/14/02
to
On Thu, Nov 14, 2002 at 04:37:16PM -0800, thelifter wrote:
> A) In Lisp variables are called Symbols.

Incorrect. Symbols are objects which have a name string, among other
properties. Symbols are commonly, but not always, gathered into a table
which is keyed by the symbol's name. The purpose of doing this (called
``interning'') is so that every successive use of the symbol's name
refers to the same exact (EQ) object.

Compare (eq (make-symbol "FOO") (make-symbol "FOO"))
and (eq (intern "BAR") (intern "BAR"))

MAKE-SYMBOL creates a symbol object without interning it.

However, symbols are used as the /names/ of lexical variables. Consider
the following example:

(let ((a 1)) a)

Here the symbol A is used as the /name/ of a lexical variable. This is
orthogonal to the matter of symbols having associated values. For
example:

(intern "A")
(setf (symbol-value 'a) 0)
(let ((a 1)) (values a (symbol-value 'a)))

==> 1 0

As you can see, the value of the lexical variable A has nothing to do
with the symbol-value of the symbol A.

When the lexical variable A is evaluated, its binding is looked up in
the lexical environment by name. The lexical environment is a table of
bindings, a table of names associated to values, that are visible in the
current lexical scope.

> [...]


> So that means in the following example:
>
> (setq x 1)
> (defun baz () x)
> (defun foo ()
> (let ((x 2)) ; Bind X, no special declaration means it's lexical,
> but...
> (baz)))
>
> If I call (foo) it will return 1 on most Lisps, but if I use CMUCL it
> will return 2 right?

If a top-level SETQ of an unbound variable is treated like a DEFVAR of
that variable, then that variable will be globally SPECIAL. So using
LET will always establish a dynamic binding with such a variable.

Consider typical SPECIAL variables such as *PRINT-BASE*. You do not
have to declare them SPECIAL every time you bind them.

This is why there is an established convention for SPECIAL variable
names, using the *'s.

--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."

Erann Gat

unread,
Nov 15, 2002, 2:53:38 AM11/15/02
to
In article <32463177...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> Your "guide" is not for people who seek to understand, but for those who
> seek to avoid the effort it takes.

My guide is for people who understand and appreciate the difference
between a reference and a tutorial. At the risk of stating the painfully
obvious, my writing of "The Idiot's Guide..." should in no way be
construed as my advocating against reading the standard, or any other
work.

And another thing:

"A 'critic' is a man who creates nothing and thereby feels qualified to
judge the work of creative men. There is a logic in this; he is unbiased -
he hates all creative people equally. "

-- Robert Heinlein

My guide, flawed as it may, has one siginficant advantage over yours: mine
exists.

E.

thelifter

unread,
Nov 15, 2002, 3:00:52 AM11/15/02
to
g...@jpl.nasa.gov (Erann Gat) wrote in message news:<gat-141102...@k-137-79-50-101.jpl.nasa.gov>...

> > I think you can avoid the whole complication in the following way:
> >
> > A) In Lisp variables are called Symbols.
>
> But they aren't. Variables and symbols are two different things.

That's one of the things I don't understand, can you explain me the
difference please or give a good pointer(Sorry, I'm just an idiot)?

You also said that names are mostly symbols but sometimes can be
strings also. Can you make clear which cases you mean? If I understood
you correctly the only case where a name is a string is when you are
referring to the name of the symbol correct?

Best regards...theIdiot

PS: I'm ignoring Erik Naggums comments. They are negative as always, I
spare my time to answer the constructive posts.

Alain Picard

unread,
Nov 15, 2002, 6:48:53 AM11/15/02
to
thel...@gmx.net (thelifter) writes:

> g...@jpl.nasa.gov (Erann Gat) wrote in message news:<gat-141102...@k-137-79-50-101.jpl.nasa.gov>...
>

> > But they aren't. Variables and symbols are two different things.
>
> That's one of the things I don't understand, can you explain me the
> difference please or give a good pointer(Sorry, I'm just an idiot)?

Ok, try this. Forget the word "variable" for a moment. There ARE no
"variables". There are only symbols and values. When you evaluate an
expression, and that expression happens to be a symbol, you need to
fetch the value currently _bound_ to that symbol. Values are bound to
symbols using, funnily enough, binding establishing forms [the most
common of which is LET].

Bindings are looked up either lexically or dynamically, depending on
whether the symbol being looked up is known to be _special_ in the
context for which the evaluation is proceeding.

Now, does that help, or merely confuse even more?

Kent M Pitman

unread,
Nov 15, 2002, 9:36:18 AM11/15/02
to
Alain Picard <apicard+die...@optushome.com.au> writes:

It just confuses things more.

The evaluation of an expression is best understood in two steps:
identification of variables from among the symbols, and then
operation on variables.

The fact that symbols have values is a red herring that is best
ignored for the purpose of understanding symbols, since those values
might or might not relate to the value of the variable which the symbol
might or might not denote.

Only variables have [lexical] values. Symbols do not.

Some symbols are used as identifiers to denote variables, but not all
symbols are identifiers denoting variables. Not even all symbols in
evaluable positions are. (Consider symbol macros.)

I think the best way to think about evaluation is to think in terms of
classifying each of the "objects" in the surface syntax into programmatic
meta structures such as "forms". This is why the distinction is made
in the stnadard between "expressions" (which are data with no applied
semantics) and "forms" (which are data, a subset of the data that are
expressions, intended to be viewed specifically as programs).

The classification phase is something the compiler does as part of
compilation, while the association of variables with values is
something that is done by the runtime/execution phase of the system.
Describing variables by appealing to the original structures seems
wrong to me becuase it appears to suggest that the language processor
will repeatedly revert to an understanding of the symbols that is
pre-classification; while it is free to use such a technique, most
compilers do not and I believe even most interpreters do not. EVAL is
confusing to people because it potentially interleaves these two
processes (though in more extant implementations I believe it just
calls the two processes in rapid succession, that is, it funcalls the
result of a quick compilation).

After classification, it is variables that have [lexical] values, and not
symbols. Even for dynamic variables, which are classified as well, it
is pure coincidence that
(symbol-value '*identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*)
happens to return the same value as
*identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*
and no great harm (other than a loss of backward compatibility) would come
if we simply removed SYMBOL-VALUE from the language. We leave SYMBOL-VALUE
in place because [a] we think backward compatibility is good and
[b] there is some cool punning to be done BY PEOPLE WHO HAVE A FIRM GRASP
OF THE PUNNING THEY ARE DOING.

Punning means that two UNRELATED facilities are being overlapped out of
"felicity", that is, a coincidence is being exploited. This happens to be
coincidence-by-design, but it certainly does not appear in other languages
that have notions of specialness and so is not a necessary part of the
specification of specialness.

Because the symbol-valueness is only entirely coincidental, many of us in the
community cringe any time anyone describes a "variable" as having any relation
to a symbol.

I once [in a rejected early design document for the T language] proposed a
special form VAR which allowed one to write

(LAMBDA (1 2) (+ (VAR 1) (VAR 2)))

In this notation, anything, not just a symbol could be a variable name.
In this notation, you can clearly see that the symbolness of variables
is just a convenient accident and that

(LAMBDA (X Y) (+ X Y))

is just shorthand for

(LAMBDA (X Y) (+ (VAR X) (VAR Y)))

or more precisely in the proposal I'd made, which used all special [compound]
forms and no atomic forms at all [other than shorthands]:

(LAMBDA (X Y) (CALL (VAR +) (VAR X) (VAR Y)))

to distinguish from what I imagined would be CL's

(LAMBDA (X Y) (CALL (VAR + FUNCTION) (VAR X VALUE) (VAR Y VALUE)))

If you understand the language in this way, you will better understand
why symbols have nothing to do with lexical variables, since you could quite
easily find yourself without symbols and with no panic over why none of the
symbol operations are available. Lexical variable values are managed at
a level of processing in the interpreter, they are not managed in the data
structure that syntactically identified the variable to the system.

Indeed, if you have this mechanism clear in your head it makes it easier
to see why it's ok to do DEFUN on non-symbols like (SETF FOO), so that

(FUNCALL #'(SETF FILLER) NEW X Y)

is seen as meaning

(CALL (VAR (SETF FILLER) FUNCTION)
(VAR NEW VALUE)
(VAR X VALUE)
(VAR Y VALUE))

and in this way you just see that (SETF FILLER) just has to be a valid
key to the namespace whose key is FUNCTION, and you don't find yourself
obsessing about whether it has a SYMBOL-VALUE. [Indeed, you find yourself
with a different and more rational set of concerns like whether the name
is compared by EQ or EQL or EQUAL or EQUALP, hopefully deciding on EQUAL
because that makes the Lisp universe appear most rational, IMO.]

This notation is part of a project I have half-completed for unifying the
Lisp and Scheme worlds by eliminating the messy business of fighting over
the car of the "form". That's such a syntactic matter, and again gets
back to the issue of why programming language semantics is not well
explained by appealing back to the syntax; the language definition of
Scheme always should have been in terms of special forms only, and it's quite
bizarre that the two most-used special forms [CALL and VAR] have no name
but rather are expressed only in terms of program shape. That's great
shorthand for a particular notational processor, just like it's handy to
have 7 mean the same as (QUOTE 7), but such syntactic cutenesses have no
business wending their way down to the semantics.

Lieven Marchand

unread,
Nov 15, 2002, 8:15:11 AM11/15/02
to
thel...@gmx.net (thelifter) writes:

> PS: I'm ignoring Erik Naggums comments. They are negative as always, I
> spare my time to answer the constructive posts.

And that's of course a very positive and constructive aside. If you
want to ignore Erik, that's your right and prerogative, but don't make
a public production out of it.

--
When they ran out of ships, they used guns. When they ran out of guns,
they used knives and sticks and bare hands. They did this for two
years. They never ran out of courage. But in the end, they ran out of
time. B5 --- In the Beginning

thelifter

unread,
Nov 15, 2002, 12:25:46 PM11/15/02
to
Alain Picard <apicard+die...@optushome.com.au> wrote in message news:<87r8dno...@optushome.com.au>...

> Ok, try this. Forget the word "variable" for a moment. There ARE no
> "variables". There are only symbols and values. When you evaluate an

I just took a look at the language specification. It seems that the
main problem is, that there is no definition for variable:

<quote>
5.1.2. Variables

Symbols are used as names of variables in Common Lisp programs.
</quote>

This is in accordance with what Eran Gatt wrote. So what is a variable
now?
Can someone provide the answer for me? Maybe we should start a new
thread on it?

There are always problems if we use things that we haven't defined.

Best regards,

theIdiot

Erann Gat

unread,
Nov 15, 2002, 12:04:47 PM11/15/02
to
In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
<pit...@world.std.com> wrote:

> Because the symbol-valueness is only entirely coincidental, many of us in the
> community cringe any time anyone describes a "variable" as having any relation
> to a symbol.

You must cringe when you read the hyperspec (which is supremely ironic
considering that you wrote it!) Here's what the spec has to say about
variables:

<quote>

variable n. a binding in the ``variable'' namespace. See Section 3.1.2.1.1
(Symbols as Forms).

...

3.1.2.1.1 Symbols as Forms

If a form is a symbol, then it is either a symbol macro or a variable.

...

If a form is a symbol that is not a symbol macro, then it is the name of a
variable, and the value of that variable is returned.

</quote>

So the spec is quite clear that a variable has some relation to a symbol.
That relationship is in fact precisely what I say in my guide: symbols are
the names of variables.

E.

Erann Gat

unread,
Nov 15, 2002, 12:47:35 PM11/15/02
to

> g...@jpl.nasa.gov (Erann Gat) wrote in message
news:<gat-141102...@k-137-79-50-101.jpl.nasa.gov>...
>
> > > I think you can avoid the whole complication in the following way:
> > >
> > > A) In Lisp variables are called Symbols.
> >
> > But they aren't. Variables and symbols are two different things.
>
> That's one of the things I don't understand, can you explain me the
> difference please or give a good pointer(Sorry, I'm just an idiot)?

Well, I thought I'd given it a pretty good shot in the "idiot's guide" but
I guess not.

Do you understand that there is a difference between a thing and its
name? For example, there is a difference between "Erik" (which is a
string of characters) and Erik (which is a person). The name "Erik"
refers to the person Erik, but the name and the person are not the same
thing.

The problem is that the only tool we have for talking about these things
are names. Its hard to talk about Erik without using his name.

Likewise, it's hard to talk about a variable named "X" without using its name.

In the case of C programs we can distinguish between variables and their
names in the same way we distinguish between people and their names, by
putting the names in double quotes. So in C there is a difference between
"X" (which is a name) and X (which is a variable). With me so far?

In Common Lisp we can't do that because there are *three* concepts that we
have to distinguish between, not just two, because in Common Lisp, unlike
C, the names of variables are first-class data items (called symbols). A
symbol is just an object pretty much like any other, except that 1)
symbols have names and 2) there is a convenient typographical convention
for distinguishing between a symbol and its name. We write FOO (without
quotes) to mean 'the symbol named "FOO"' just like we write Erik (without
quotes) to mean 'the person named "Erik"'.

The problem is we've now run out of typographical conventions. We've got
the string "FOO" and the symbol FOO, but no notation left to talk about
the variable whose name is (the symbol) FOO, except to write out that very
phrase ("the variable whose name is FOO"). So we have to invent a new
notation out of whole cloth. The notation I invented for the guide was
FOO*n, where n is a number.

I could have used a different convention, and used a single-quote to
denote symbols. So I could have talked about the string "FOO" being the
name of the symbol 'FOO which is the name of the variable FOO. The
problem with that is that there can be more than one variable named FOO
(just like there can be more than one person named Erik), and so I
invented the *n notation to distinguish between multiple variables with
the same name.

Did that help?

E.

Erann Gat

unread,
Nov 15, 2002, 1:21:14 PM11/15/02
to

> Alain Picard <apicard+die...@optushome.com.au> wrote in message
news:<87r8dno...@optushome.com.au>...
> > Ok, try this. Forget the word "variable" for a moment. There ARE no
> > "variables". There are only symbols and values. When you evaluate an
>
> I just took a look at the language specification. It seems that the
> main problem is, that there is no definition for variable:

Sure there is. Look in the glossary.

E.

Pekka P. Pirinen

unread,
Nov 15, 2002, 2:01:55 PM11/15/02
to
> > g...@jpl.nasa.gov (Erann Gat) writes:
> > > > > In fact, it is actually impossible on a strict reading of the
> > > > > standard to create a dynamic binding for a symbol without
> > > > > turning it into a (globally) special variable.
> > >
> > > I meant to say "global binding" (or maybe "top-level
> > > binding").

I'm not sure what you intend by that "globally" in parentheses.
Ignoring it, it's saying global bindings must be dynamic; As Nils
Gösche pointed out, this ignored constant variables, but it's true
otherwise. Reading that as "globally special", it's not true: you can
have a global binding without the variable being globally special:

(locally
(declare (special x))
(setq x 1))

You might say that can't be called a top-level binding, since the form
that refers to it is not a top-level form, but OTOH, it's certainly
the top binding, there can't be another one outside it.

Nils Gösche <n...@cartan.de> writes:
> > ``3.1.2.1.1 Symbols as Forms´´ says that when a symbol that is
> > not a symbol-macro is evaluated, then it names a variable, which
> > is either lexical, dynamic or constant. We are not interested in
> > a constant or dynamic binding, which leaves only a ``lexical
> > global´´ binding as a possibility. There is no such thing,
> > though, by definition: Lexical scope is always restricted to an
> > establishing form.
>
> And here is where I erred: There /is/ a global lexical
> environment; it is called the null lexical environment, and it is
> here where the binding is established.

I think "the null lexical environment" is a descriptive phrase, not a
definite reference; it doesn't mean there's just one such environment.
See remarks in the glossary entry for "null" (just above the entry for
"null lexical environment") about how "the null string" is used in
preference to the technically more correct "a null string".

Furthermore, "null" means there aren't any in it, so one can hardly
say a binding is established there.

There are no global lexical bindings. Even granting the possibility,
you'd need a way to establish one, and none is provided.
--
Pekka P. Pirinen
Mail should be private, whether on paper or on disk. Public gatherings
should be a right, whether virtual or in person.

Kalle Olavi Niemitalo

unread,
Nov 15, 2002, 2:32:12 PM11/15/02
to
Kent M Pitman <pit...@world.std.com> writes:

> or more precisely in the proposal I'd made, which used all special
> [compound] forms and no atomic forms at all [other than shorthands]:
>
> (LAMBDA (X Y) (CALL (VAR +) (VAR X) (VAR Y)))

How did you propose to handle macros?

- (MACRO-CALL (VAR AND) (VAR X) (VAR Y)): seems good enough.

- (CALL (VAR AND) (VAR X) (VAR Y)): requires further analysis at
compile time to find out which VARs refer to macros, but the
compiler has to locate the binding forms anyway, so perhaps
it's easy.

- (AND (VAR X) (VAR Y)): it would then be difficult to have
macros with names like CALL, and your proposal already made
(VAR CALL) unambiguous so I assume you wanted to give the same
freedom with macros.

- with a separate macro processor that translates to this syntax
from something else.

Erik Naggum

unread,
Nov 15, 2002, 2:58:53 PM11/15/02
to
* Erann Gat

| My guide is for people who understand and appreciate the difference
| between a reference and a tutorial.

You contradict yourself, or you try one of your annoying backhand insults,
again. Please try to stay on topic and be constructive. Getting approval
from me should not be your primary purpose, and hence lack thereof should
not cause you to fight for it, which is extremely unlikely to produce it.

| And another thing:
|
| "A 'critic' is a man who creates nothing and thereby feels qualified to
| judge the work of creative men. There is a logic in this; he is unbiased -
| he hates all creative people equally. "
|
| -- Robert Heinlein

Poor little Erann. So hurt. So unable to think, for what does that quote
say about a person who calls another person a critic when he is not?

| My guide, flawed as it may, has one siginficant advantage over yours: mine
| exists.

You amaze me, Erann. So hateful, so destructive, so emotional, so blind.
I have suggested people actually go read books on Common Lisp, such as
CLtL and CLtL2, and also the standard. In a pathetic display of your
emotional dysfunction, you now argue that these books and the standard do
not /exist/? What kind of idiocy is that? What do you gain by hammering
on what you perceive as your critics when all you should do was to make
your own work better? Wasting time on attacking me means that your whole
purpose is /not/ to explain special variables, but to have people approve
of you as a person. That is extremely unlikely to happen when you act the
way you have chosen now. So get back to the text and get it right, and
you may have a chance of such approval.

Normally, with a title like the one you have chosen, the intention is to
make the audience to feel at ease when they are mortally afraid of experts
-- it is not intended to describe the author. You may wish to make the
former intention clearer.

Erik Naggum

unread,
Nov 15, 2002, 3:00:14 PM11/15/02
to
* thel...@gmx.net (thelifter)

| PS: I'm ignoring Erik Naggums comments. They are negative as always, I
| spare my time to answer the constructive posts.

Ever wondered /why/ they are negative towards people like you? Sheesh.

But that you have to mention it is actually quite amusing.

Erik Naggum

unread,
Nov 15, 2002, 3:02:58 PM11/15/02
to
* Erann Gat -> Kent Pitman

| You must cringe when you read the hyperspec (which is supremely ironic
| considering that you wrote it!)

Gee, that was constructive.

sv0f

unread,
Nov 15, 2002, 4:29:09 PM11/15/02
to
In article <87vg2zt...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

>I still think
>your text is good (and will be even better if you mention
>environments as I proposed), but it should be clear that it is
>only meant as a ``ladder´´ to the /real/ thing -- I think reading
>standards is simply easier if you already know more or less what
>they are trying to tell you.

"My propositions serve as elucidations in the following way:
anyone who understand me eventually recognizes them as
nonsensical, when he has used them ­ as steps ­ to climb beyond
them. (He must, so to speak, throw away the ladder after he has
climbed up it.)"

( 6.54 of Wittgenstein¹s Tractatus.)

Nils Goesche

unread,
Nov 15, 2002, 5:06:06 PM11/15/02
to
no...@vanderbilt.edu (sv0f) writes:

Yes, I was thinking of exactly that paragraph :-) The tractatus makes
for a lot of nice quotes -- but unfortunately I don't own an English
translation. I think I'll go to Amazon right now...

Regards,
--
Nils Gösche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0

Kent M Pitman

unread,
Nov 15, 2002, 5:11:29 PM11/15/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> <quote>
>
> variable n. a binding in the ``variable'' namespace. See Section 3.1.2.1.1
> (Symbols as Forms).
>
> ...
>
> 3.1.2.1.1 Symbols as Forms
>
> If a form is a symbol, then it is either a symbol macro or a variable.
>
> ...
>
> If a form is a symbol that is not a symbol macro, then it is the name of a
> variable, and the value of that variable is returned.
>
> </quote>
>
> So the spec is quite clear that a variable has some relation to a symbol.
> That relationship is in fact precisely what I say in my guide: symbols are
> the names of variables.

No, the names of variables are symbols.

Symbols are either variables or symbol macros.

Nils Goesche

unread,
Nov 15, 2002, 5:17:24 PM11/15/02
to
Pekka.P...@globalgraphics.com (Pekka P. Pirinen) writes:

> Nils Gösche <n...@cartan.de> writes:

> > > ``3.1.2.1.1 Symbols as Forms´´ says that when a symbol that is
> > > not a symbol-macro is evaluated, then it names a variable, which
> > > is either lexical, dynamic or constant. We are not interested
> > > in a constant or dynamic binding, which leaves only a ``lexical
> > > global´´ binding as a possibility. There is no such thing,
> > > though, by definition: Lexical scope is always restricted to an
> > > establishing form.

> > And here is where I erred: There /is/ a global lexical
> > environment; it is called the null lexical environment, and it is
> > here where the binding is established.

> I think "the null lexical environment" is a descriptive phrase, not
> a definite reference; it doesn't mean there's just one such
> environment.

I think its meaning is given by

3.1.1.3.1 The Null Lexical Environment

and

3.1.1.1 The Global Environment

> See remarks in the glossary entry for "null" (just above the entry
> for "null lexical environment") about how "the null string" is used
> in preference to the technically more correct "a null string".
>
> Furthermore, "null" means there aren't any in it, so one can hardly
> say a binding is established there.

Heh. Well, we are talking about evaluation contexts; ``null´´ might
mean ``no more bindings than usual (in the global environment)´´.

> There are no global lexical bindings. Even granting the
> possibility, you'd need a way to establish one, and none is
> provided.

How about (setf (symbol-value 'foo) 42)? :-)

Kent M Pitman

unread,
Nov 15, 2002, 5:17:35 PM11/15/02
to
Kalle Olavi Niemitalo <k...@iki.fi> writes:

> Kent M Pitman <pit...@world.std.com> writes:
>
> > or more precisely in the proposal I'd made, which used all special
> > [compound] forms and no atomic forms at all [other than shorthands]:
> >
> > (LAMBDA (X Y) (CALL (VAR +) (VAR X) (VAR Y)))
>
> How did you propose to handle macros?

Substitute "syntactic shorthand" for "macro" and it will be easier to see.

(+ x y) is a syntactic shorthand.

So is a macro form.

> - (MACRO-CALL (VAR AND) (VAR X) (VAR Y)): seems good enough.

No, it's not needed. Simply

(AND X Y)

or

(AND (VAR X) (VAR Y))

is appropriate. You actually don't need to represent the macro call in
the execution semantics because the execution semantics should have macros
removed.


> - (CALL (VAR AND) (VAR X) (VAR Y)): requires further analysis at
> compile time to find out which VARs refer to macros, but the
> compiler has to locate the binding forms anyway, so perhaps
> it's easy.

No, no in my analysis. This would be the way of saying to funcall whatever
was in the variable AND, whether or not that was a macro or special form
(which might or might not be funcallable).



> - (AND (VAR X) (VAR Y)): it would then be difficult to have
> macros with names like CALL, and your proposal already made
> (VAR CALL) unambiguous so I assume you wanted to give the same
> freedom with macros.

You're confusing yourself by assuming there is no namespacing system.
I didn't outline the complete proposal and don't plan to. It's quite
complicated to do this in full form and I don't want to go into why here.
I do havea partly worked through implementation and namespacing either
by symbols or by lexical bindings is not a problem. But it involves
additional primitives. I only specified the primitives needed to make a
specific point in this conversation--you don't have enough foundation to
either approve or disapprove my full proposal here and I don't have enough
time to really present/defend it.

> - with a separate macro processor that translates to this syntax
> from something else.

This is the same as the previous bullet item, as far as I'm concerned, and
both work.

Erann Gat

unread,
Nov 15, 2002, 5:12:19 PM11/15/02
to
In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
<pit...@world.std.com> wrote:

> Even for dynamic variables, which are classified as well, it
> is pure coincidence that
> (symbol-value
'*identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*)
> happens to return the same value as
>
*identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*

No, it's not a coincidence, it's required by the standard:

Accessor SYMBOL-VALUE
...
Accesses the symbol's value cell.

value cell n. Trad. (of a symbol) The place which holds the value, if any,
of the dynamic variable named by that symbol, and which is accessed by
symbol-value.

> and no great harm (other than a loss of backward compatibility) would come
> if we simply removed SYMBOL-VALUE from the language.

Really? How would you obtain the value of symbols whose identities were
not known until run-time?

[Long argument snipped]

This is a pedagogical argument, and I actually agree with you that things
would be clearer if they were explained this way. Unfortunately, that is
not the way things are. The CL standard unambiguously identifies
variables with symbols. That this causes confusion I do not dispute; that
was, in fact, one of the motivations for writing "The idiot's guide..."

This is one of many areas where, IMO, CL would do well to clean house.

E.

Erann Gat

unread,
Nov 15, 2002, 5:21:44 PM11/15/02
to
In article <32463791...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> Poor little Erann. So hurt. So unable to think, for what does that quote
> say about a person who calls another person a critic when he is not?

Your comment about my guide not being "for people who seek to understand"
sounded like criticism to me. (In fact, it sounded like more than
criticism. It sounded like an insult.)

> | My guide, flawed as it may, has one siginficant advantage over yours: mine
> | exists.
>
> You amaze me, Erann. So hateful, so destructive, so emotional, so blind.
> I have suggested people actually go read books on Common Lisp, such as
> CLtL and CLtL2, and also the standard. In a pathetic display of your
> emotional dysfunction, you now argue that these books and the standard do
> not /exist/? What kind of idiocy is that?

Obviously I did not mean to claim that CLTLN and the standard don't
exist. What I meant (again at the risk of stating the painfully obvious)
was that you didn't write them.

> What do you gain by hammering
> on what you perceive as your critics when all you should do was to make
> your own work better?

I would like very much to improve the Guide, but I find absolutely nothing
in anything you've written that's going to (or even intended to) help me
do that.

> Normally, with a title like the one you have chosen, the intention is to
> make the audience to feel at ease when they are mortally afraid of experts
> -- it is not intended to describe the author. You may wish to make the
> former intention clearer.

Actually, the title is intentionally ambiguous on that point, an attempt
at self-deprecating humor. This has been the case since the first edition
of the guide, where I made this explicit. See

http://groups.google.com/groups?selm=gat-0203001548330001%40milo.jpl.nasa.gov

E.

thelifter

unread,
Nov 15, 2002, 5:57:17 PM11/15/02
to
Kent M Pitman <pit...@world.std.com> wrote in message news:<sfwheei...@shell01.TheWorld.com>...

> After classification, it is variables that have [lexical] values, and not
> symbols. Even for dynamic variables, which are classified as well, it
> is pure coincidence that
> (symbol-value '*identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*)
> happens to return the same value as
> *identifier-that-originally-named-the-variable-that-is-now-seen-to-have-been-a-special-variable*

Well, according to the language specification this is no coincidence
but intended:
"symbol-value returns the current value of the dynamic (special)
variable named by symbol."

> and no great harm (other than a loss of backward compatibility) would come
> if we simply removed SYMBOL-VALUE from the language. We leave SYMBOL-VALUE
> in place because [a] we think backward compatibility is good and
> [b] there is some cool punning to be done BY PEOPLE WHO HAVE A FIRM GRASP
> OF THE PUNNING THEY ARE DOING.

According to the language specification symbol-value is useful:

"This function is particularly useful for implementing interpreters
for languages embedded in Lisp. The corresponding assignment primitive
is set; alternatively, symbol-value may be used with setf. "

Sorry to say this, but your text couldn't diminish my confusion. Don't
worry, it's not your fault, remember that Eran Gatt wanted to write a
text for IDIOTS...

:))

Nils Goesche

unread,
Nov 15, 2002, 6:11:09 PM11/15/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
> <pit...@world.std.com> wrote:
>
> > and no great harm (other than a loss of backward
> > compatibility) would come if we simply removed SYMBOL-VALUE
> > from the language.
>
> Really? How would you obtain the value of symbols whose identities were
> not known until run-time?

My magic: Evaluate them.

Harald Hanche-Olsen

unread,
Nov 15, 2002, 6:34:45 PM11/15/02
to
+ g...@jpl.nasa.gov (Erann Gat):

And even more importantly, follow the advice in the glossary entry:
See Section 3.1.2.1.1 (Symbols as Forms) - where you find this crucial
piece of information:

A variable can store one object. The main operations on a variable
are to read[1] and to write[1] its value.

I think it's important to stop obsessing about what a variable /is/.
It's what you can /do/ with it that counts. In a very real sense, the
variable is what it does, neither more nor less.

Here is an analogy from mathematics. What is a number? Well, who
cares? Those who are concerned with the foundations of mathematics
care, that's who. The rest of us just /use/ the bloody things. Peano
understood this very well, so he listed a basic set of axioms for the
natural numbers, such as: 0 is a number; every number has a unique
successor; every number other than 0 is the successor of some unique
number. Add the induction principle, and voila, you have the natural
numbers (modulo some nasty surprises concerning non-standard models
and such). Only if you worry about such esoterica as how to construct
the natural numbers given nothing more than set theory do you dream up
seemingly crazy schemes such as 0={} (the empty set), 1={0}, 2={0,1},
etc.

Just like you only need to know how to compute with numbers, even if
you don't know what they are, so do you only need to know what to do
with variables: You can /read/ and /write/ them. That is, a variable
is a certain place which will hold a value. You put a value there,
and it remains until you put a different value in the same place by
assignment. And you can look at the variable at any time (so long as
it's accessible) and find out what that value is. And that's it, she
wrote.

Except there are other kinds of places: The fifth entry of a vector or
the CAR of a CONS are places too, but they are not variables.
Variables have another feature: They have /names/, and they are
accessible /only/ via their name. That is why the HyperSpec says a
variable is a special kind of binding, which in its turn is an
association of a name with something: You can think of that something
as the /place/ which holds the variable's value, but really the only
important thing to know about it is its ability to remember a value
for later access.

In this example there are two variables, both named x:

(let ((x :outer)) ; creates a new binding
(format t "~&(1) x=~A~%" x)
(setf x 42) ; same binding, new value
(format t "~&(2) x=~A~%" x)
(let ((x :inner)) ; new binding, shadowing the old
(format t "~&(3) x=~A~%" x))
;; The new binding is gone, leaving the old one visible once more
(format t "~&(4) x=~A~%" x))

One variable has the values :OUTER and then 42. The other one only
ever has the value :INNER.

In summary, then, a variable is a named place. It is accessible only
through its name, and all you can do with it is set and look at its
value. Since an object is defined by what it can do, this defines
variables. The fact that a single name can denote different variables
at different times does not change this simple fact.

Gee, I set out to make a simple point (what you do is what you are)
and ended up writing a minor lecture. It's an occupational hazard
with us academic types, I guess. We get carried away by hearing
ourselves talk. (In this case, it must be the sound of the keyboard
that has some hypnotic effect.)

--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?

JP Massar

unread,
Nov 15, 2002, 6:54:22 PM11/15/02
to
On Thu, 14 Nov 2002 17:40:44 -0800, g...@jpl.nasa.gov (Erann Gat)
wrote:

>In article <b295356a.02111...@posting.google.com>,
>thel...@gmx.net (thelifter) wrote:
>

>> Especially quote 4 is confusing. If I combine 4 and 2, I can construct
>> the following sentence:
>> the name of a symbol is a string and names in CL are usually
>> symbols!???!?
>
>Yes, that's how it is. The word "name" is used in two different ways in
>the Common Lisp spec:
>
> binding n. an association between a name and that which the name denotes.
>
> symbol-name returns the name of symbol. (symbol-name 'temp) => "TEMP"
>
>Maybe I should refer to the name of a variable (which is a symbol) and the
>symbol-name of a symbol (which is a string)? I'm not sure that makes it
>any less confusing.
>

Maybe you should quote the White Knight and be done with it.

:-)


Nils Goesche

unread,
Nov 15, 2002, 7:10:01 PM11/15/02
to
Harald Hanche-Olsen <han...@math.ntnu.no> writes:

> I think it's important to stop obsessing about what a variable
> /is/. It's what you can /do/ with it that counts. In a very
> real sense, the variable is what it does, neither more nor
> less.
>
> Here is an analogy from mathematics. What is a number? Well,
> who cares? Those who are concerned with the foundations of
> mathematics care, that's who. The rest of us just /use/ the
> bloody things. Peano understood this very well, so he listed a
> basic set of axioms for the natural numbers, such as: 0 is a
> number; every number has a unique successor; every number other
> than 0 is the successor of some unique number. Add the
> induction principle, and voila, you have the natural numbers
> (modulo some nasty surprises concerning non-standard models and
> such).

And some more real surprises, too:

http://mathworld.wolfram.com/GoodsteinsTheorem.html

The Peano axioms are actually not enough do properly reflect our
notion of natural numbers, surprising as it seems.

> Only if you worry about such esoterica as how to construct the
> natural numbers given nothing more than set theory do you dream
> up seemingly crazy schemes such as 0={} (the empty set), 1={0},
> 2={0,1}, etc.

I don't see what's crazy about that. It is nice that we can
define natural numbers like this and then prove the Peano axioms.
It is also very natural, rather than crazy: Every natural number
n defined in this way is a set with exactly n elements. I like
that.

The question ``What /is/ a variable, after all?´´ is likewise
interesting. However, I agree that one shouldn't put so much
emphasis to it when it confuses somebody.

Erik Naggum

unread,
Nov 15, 2002, 7:51:54 PM11/15/02
to
* Erann Gat

| Your comment about my guide not being "for people who seek to understand"
| sounded like criticism to me. (In fact, it sounded like more than
| criticism. It sounded like an insult.)

And since it sounded like that to you, you take it upon yourself to
revenge it, is that it? Some primitive cultures, notably in the Middle
East, have a concept of "honor" that makes it impossible to say anything
to them that could conceivably cause them to lose their fragile self-image
of their honor. I have no intention whatsoever of catering to primitive
cultures, wherever they may have been exported or imported or whoever
suffers from their anti-intellectual notions that turn a statement of
fact into an insult that turns these rabidly irrational people into hate
machines that believe they revenge an attack that was never there, and
therefore prevent them from understanding that they in fact attack first
and thus do not even grasp that their openly hostile acts are unfair and
provide legitimate reason for rebuttal and rejection, if not defense.

| Obviously I did not mean to claim that CLTLN and the standard don't
| exist. What I meant (again at the risk of stating the painfully obvious)
| was that you didn't write them.

The relevance of which being ...? This is so stupid a line of argument
that you should be happy that I do not call you on it further. Drop it.

| I would like very much to improve the Guide, but I find absolutely
| nothing in anything you've written that's going to (or even intended to)
| help me do that.

I think it would be improved by being removed. I think you would be
improved by being removed, too, since you are such an annoying, hostile
person who never seem to be able to read anything I write without seeing
an insult that you have to attack me for. Realize that your perception
of what I write is mainly in your own head. You should have learned by
now that because you feel a certain way does not mean that there was any
intention to make you feel that way. Some people here on c.l.l seize any
and all opportunity to be insulted and therefore attack me regardless of
what I actually say, and you are one of them. You are broken, Erann Gat.
Repair yourself and stop inflicting your malfunction on me. Thank you.

Erik Naggum

unread,
Nov 15, 2002, 7:56:17 PM11/15/02
to
* thel...@gmx.net (thelifter)

| Well, according to the language specification this is no coincidence
| but intended:
| "symbol-value returns the current value of the dynamic (special)
| variable named by symbol."

Would you guys please try to /listen/ to what Kent says and not argue
against it without understanding it?

What you assume without due cause is that there has been a `special´
declaration for the symbol. This is the assumption that you have to
understand does not always hold.

My God, how annoying it is to try to explain something to people who are
unwilling to listen because they believe they already understand things
better than their teachers.

Erann Gat

unread,
Nov 15, 2002, 7:25:51 PM11/15/02
to
In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
<pit...@world.std.com> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
> > symbols are the names of variables.
>
> No, the names of variables are symbols.

Seems like splitting hairs to me.

> Symbols are either variables or symbol macros.

Sure, but that doesn't change the fact that symbols are (sometimes - in
fact usually, but not always) the names of variables.

E.

Erann Gat

unread,
Nov 15, 2002, 7:39:50 PM11/15/02
to
In article <87u1iic...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
>
> > In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
> > <pit...@world.std.com> wrote:
> >
> > > and no great harm (other than a loss of backward
> > > compatibility) would come if we simply removed SYMBOL-VALUE
> > > from the language.
> >
> > Really? How would you obtain the value of symbols whose identities were
> > not known until run-time?
>
> My magic: Evaluate them.

There are two interpretations of the claim that "no great harm ... would
come if we simply remove symbol-value from the language."

The first interpretation is that removing symbol-value would cause no
great harm because it can simply be added back again thusly:

(defun symbol-value (symbol)
(if (symbolp symbol) (eval symbol) (error "~S is not a symbol" symbol)))

but that seemed like a pretty uninintersting observation to me, so I
assumed that this was not Kent's intention (particularly since the claim
was made in the context of a discussion of how associating variables and
symbols is just wrong).

I assumed he meant something deeper: no great harm would come if we
eliminated the functionality that symbol-value provides, under whatever
guises that functionality exists in the language (including the ability to
evaluate symbols at run time).

E.

Adam Warner

unread,
Nov 15, 2002, 8:12:35 PM11/15/02
to
Hi Erann Gat,

> In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
> <pit...@world.std.com> wrote:
>
>> g...@jpl.nasa.gov (Erann Gat) writes:
>> > symbols are the names of variables.
>>
>> No, the names of variables are symbols.
>
> Seems like splitting hairs to me.

There is no splitting hairs. It is logic/set theory. You stated
"...precisely what I say in my guide: symbols are the names of variables."
This reasonably reads that all symbols are the names of variables. Kent
switched this around so that all names of variables are symbols. All names
of variables are symbols but not all symbols are not names of variables.

>> Symbols are either variables or symbol macros.
>
> Sure, but that doesn't change the fact that symbols are (sometimes - in
> fact usually, but not always) the names of variables.

Please express this as the names of variables are symbols. You just wrote
that symbols are or are not the names of variables. That's not very
useful.

Regards,
Adam

Erann Gat

unread,
Nov 15, 2002, 8:11:27 PM11/15/02
to
In article <32463967...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> | Obviously I did not mean to claim that CLTLN and the standard don't
> | exist. What I meant (again at the risk of stating the painfully obvious)
> | was that you didn't write them.
>
> The relevance of which being ...?

Good grief, are you really that daft? The relevance of which being that I
wrote a tutorial and you didn't. So either you think tutorials have no
value, in which case we'll have to agree to disagree on that. Or you do,
in which case I respond to your non-constructive criticism of my tutorial
by simply saying once again that, bad as it is, it's better than yours.

> I think it would be improved by being removed.

Your opinion is noted. Now buzz off.

E.

Nils Goesche

unread,
Nov 15, 2002, 10:46:05 PM11/15/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> In article <87u1iic...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:
>
> > g...@jpl.nasa.gov (Erann Gat) writes:
> >
> > > In article <sfwheei...@shell01.TheWorld.com>, Kent M Pitman
> > > <pit...@world.std.com> wrote:
> > >
> > > > and no great harm (other than a loss of backward
> > > > compatibility) would come if we simply removed SYMBOL-VALUE
> > > > from the language.
> > >
> > > Really? How would you obtain the value of symbols whose identities were
> > > not known until run-time?
> >
> > My magic: Evaluate them.
>
> There are two interpretations of the claim that "no great harm ... would
> come if we simply remove symbol-value from the language."
>
> The first interpretation is that removing symbol-value would cause no
> great harm because it can simply be added back again thusly:
>
> (defun symbol-value (symbol)
> (if (symbolp symbol) (eval symbol) (error "~S is not a symbol" symbol)))

Sure, but the more interesting case is how you would bring
(SETF SYMBOL-VALUE) back. Remember that much of this discussion
came from the confusion about when or when not (setq x y) and
(setf (symbol-value 'x) y) can be used interchangably.

> but that seemed like a pretty uninintersting observation to me,
> so I assumed that this was not Kent's intention (particularly
> since the claim was made in the context of a discussion of how
> associating variables and symbols is just wrong).

It is interesting insofar as it emphasizes that you don't need
SYMBOL-VALUE to understand variables in Common Lisp, I think.

> I assumed he meant something deeper: no great harm would come
> if we eliminated the functionality that symbol-value provides,
> under whatever guises that functionality exists in the language
> (including the ability to evaluate symbols at run time).

It would very surprise me if that was what he meant.

Erik Naggum

unread,
Nov 16, 2002, 12:11:55 AM11/16/02
to
* Nils Goesche

| And here is where I erred: There /is/ a global lexical environment; it is
| called the null lexical environment, and it is here where the binding is
| established.

This is very confused. The "null lexical environment" communicates to
the alert reader that there are no lexically apparent bindings, not that
any new bindings are established in it. That `eval´ is evaluated in the
null lexical environment means that it cannot access lexically apparent
bindings, which `eval´ does not attempt to capture bindings when it
receives a form.

This is going off on a tangent, but assume you have a lexical environment
with variables named `foo´ and `bar´, and wish to evaluate an expression
that references these bindings via the obvious mechanism, the symbols
`foo´ and `bar´, respectively -- how would you do that? The association
between symbol and variable is a compile-time-only notion for lexical
bindings, and the lexical environment does not survive compilation. If
certain bindings have been captured by a closure, the association between
symbol and variable is still lost and have to re-established explicitly.

This is why, for instance, macro-expanding functions accept an environment
and `eval´ does not, and more importantly, could not, and why environments
are not first-class objects but rather compile-time-only notions that have
to be constructed and used opaquely. The ability for macros to access the
lexical environment of the caller therefore must be of a very different
nature than the accessability of and to the global environment via special
variables and value slots in symbols.

Erann Gat

unread,
Nov 16, 2002, 12:29:52 AM11/16/02
to
In article <87heeic...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

> Sure, but the more interesting case is how you would bring
> (SETF SYMBOL-VALUE) back.

<shrug>

(defun (setf symbol-value) (value symbol)
(set symbol value))

or if that was too cute

(defun (setf symbol-value) (value symbol)
(eval `(locally (declare (special ,symbol)) (setq ,symbol ,value))))

> It is interesting insofar as it emphasizes that you don't need
> SYMBOL-VALUE to understand variables in Common Lisp, I think.

You don't need the symbol-value function, but I don't see how you can
understand variables in CL without the *concept* of a symbol's value (or
its dynamic binding or whatever you want to call it).

BTW, a number of people have written to me to say that symbols have
nothing to do with lexical bindings. This is false. The semantics of
lexical bindings in Common Lisp are defined in such a way that a compiler
*may* optimize away the symbols, but the semantics of lexical variables
are defined in the standard in terms of symbols. (Also, most
implementations keep the symbols around for debugging.)

E.

Erann Gat

unread,
Nov 16, 2002, 12:32:34 AM11/16/02
to
In article <pan.2002.11.16....@consulting.net.nz>, "Adam
Warner" <use...@consulting.net.nz> wrote:

> There is no splitting hairs. It is logic/set theory.

Are you kidding? That's the very definition of splitting hairs!

E.

Alain Picard

unread,
Nov 16, 2002, 12:55:01 AM11/16/02
to
thel...@gmx.net (thelifter) writes:

> Alain Picard <apicard+die...@optushome.com.au> wrote in message news:<87r8dno...@optushome.com.au>...
> > Ok, try this. Forget the word "variable" for a moment. There ARE no
> > "variables". There are only symbols and values. When you evaluate an


>
> I just took a look at the language specification. It seems that the
> main problem is, that there is no definition for variable:

Please understand that I offered this explanation in the context
of a guide "for idiots" (God I hate that term). Of course there
_are_ variables, both in execution and in the spec---refer to Kent's
reply to my previous post to see what that's all about.

But if you want to get a temporary mental model for how things
work, I offered you one. It's, by design, incomplete and inaccurate.


Nils Goesche

unread,
Nov 16, 2002, 1:31:18 AM11/16/02
to
Erik Naggum <er...@naggum.no> writes:

> * Nils Goesche
> | And here is where I erred: There /is/ a global lexical
> | environment; it is called the null lexical environment, and
> | it is here where the binding is established.
>
> This is very confused. The "null lexical environment"
> communicates to the alert reader that there are no lexically
> apparent bindings, not that any new bindings are established
> in it.

Well, yes. Maybe I shouldn't use the term ``null lexical
environment´´ when talking about it.

> That `eval´ is evaluated in the null lexical environment
> means that it cannot access lexically apparent bindings,
> which `eval´ does not attempt to capture bindings when it
> receives a form.

Sure. What I am trying to understand is the following:

CL-USER 30 > (eval 'most-positive-double-float)
1.7976931348623165E308

CL-USER 31 > (setf (symbol-value 'x) 42)
42

CL-USER 32 > (eval 'x)
42

There is indeed no lexically apparent binding for those two
symbols. But their values are looked up somewhere, in an
environment. Which is it?

The global environment, obviously, which is also called ``null
lexical environment´´ to emphasize that it contains no lexically
apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).
Neither MOST-POSITIVE-DOUBLE-FLOAT nor X have been declaimed
special, however.

Now, MOST-POSITIVE-DOUBLE-FLOAT is a constant, which is not so
interesting, but X is not. I can do

CL-USER 33 > (setf (symbol-value 'x) 17)
17

CL-USER 34 > (eval 'x)
17

anytime I want. I can also do

CL-USER 35 > (let ((x 13))
(+ x 5))
18

I would also like to try the following:

(defun test (y)
(+ x y))

(let ((x 20))
(test 7))

Now, 3.2.2.3 Semantic Constraints says:

# Special proclamations for dynamic variables must be made in the
# compilation environment. Any binding for which there is no
# special declaration or proclamation in the compilation
# environment is treated by the compiler as a lexical binding.

But I might snottily claim that I don't want X to be special,
anyway :-)

But what the heck, let's do it anyway:

CL-USER 36 > (defun test (y)
(+ x y))
Warning: Syntactic warning for form X:
X assumed special.
TEST

CL-USER 37 > (let ((x 20))
(test 7))
24

as expected.

Whether this is legal code or not is not so interesting at the
moment; what I like is that we can explain everything that
happened in the above experiments without resorting to
implementation issues if we simply say that X is part of such a
thing as a ``global lexical environment´´. While this sounds a
bit like an oxymoron because lexical bindings are usually
lexically restricted to establishing forms and have dynamic
extent, it is well possible to give the term a reasonable
meaning.

Now, what happens if we do

CL-USER 38 > (declaim (special x))
NIL

CL-USER 39 > (let ((x 20))
(test 7))
27

By globally declaring X special, we instruct the system to
perform the last binding in the dynamic environment, instead. It
is rather puzzling that TEST already behaves accordingly, too!
So, now X is also part of the (global) dynamic environment,
obviously. And it has kept its value :-)

Christian Queinnec writes in ``Lisp in Small Pieces´´ (p. 50):

# In addition, if we do not find the dynamic value, then we go
# back to the global lexical environment, since it also serves as
# the global dynamic environment in Common Lisp.

> [split explanations]

Thank you for those, but I think I already understood this. The
above is the point I am a bit confused about :-)

Note that my problem does not stem from confusing symbols with
variables. My (SETF SYMBOL-VALUE) actions are one thing, not
very interesting; the interesting part is explaining the
evaluations, semantically.

All these considerations are certainly rather esoteric, idle
speculation. What /really/ goes on under the hood in the
implementation is perfectly clear, anyway; but I find it
interesting, anyway.

Nils Goesche

unread,
Nov 16, 2002, 1:47:57 AM11/16/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> In article <87heeic...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:
>
> > Sure, but the more interesting case is how you would bring
> > (SETF SYMBOL-VALUE) back.
>
> <shrug>
>
> (defun (setf symbol-value) (value symbol)
> (set symbol value))
>
> or if that was too cute
>
> (defun (setf symbol-value) (value symbol)
> (eval `(locally (declare (special ,symbol)) (setq ,symbol ,value))))

Ok, and the interesting part is that your code does not look like
it manipulates a data structure, anymore. You are using only
abstract operators for setting variables. I can achieve the same
thing in bash:

#!/bin/bash

set_symbol_value () {
eval "$1=$2"
}

x=2

set_symbol_value x 4

echo $x

will output 4. The values don't come from a symbol data
structure anymore but have to be explained purely semantically.

> > It is interesting insofar as it emphasizes that you don't
> > need SYMBOL-VALUE to understand variables in Common Lisp, I
> > think.
>
> You don't need the symbol-value function, but I don't see how
> you can understand variables in CL without the *concept* of a
> symbol's value (or its dynamic binding or whatever you want to
> call it).

By not calling it the ``symbol's´´ value. Variables have values;
a symbol is just some arbitrary data structure. Sure, Lisp code
is made up of conses and symbols, but as soon as it is
/evaluated/, it doesn't matter anymore what kind of thing a
symbol actually is and if it has something like a value slot or
not. That's an implementation issue. As soon as a symbol is
evaluated (and it is not a symbol macro ;-), it is used to denote
the /name/ of a /variable/. The level of abstraction is higher.

> BTW, a number of people have written to me to say that symbols
> have nothing to do with lexical bindings. This is false. The
> semantics of lexical bindings in Common Lisp are defined in
> such a way that a compiler *may* optimize away the symbols, but
> the semantics of lexical variables are defined in the standard
> in terms of symbols. (Also, most implementations keep the
> symbols around for debugging.)

This is just a variation of the above.

Erann Gat

unread,
Nov 16, 2002, 3:47:08 AM11/16/02
to
In article <87vg2ya...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

> The values don't come from a symbol data structure anymore

But they never did. Who said anything about a symbol data structure?

Here's another implementation of symbol-value:

(let ((env (make-hash-table)))
(defun symbol-value (s) (gethash env s))
(defun (setf symbol-value) (value s)
(setf (gethash env s) value))))

Using this implementation you can set the symbol-value of any Lisp object,
not just symbols.

E.

Harald Hanche-Olsen

unread,
Nov 16, 2002, 7:50:26 AM11/16/02
to
+ Erik Naggum <er...@naggum.no>:

| My God, how annoying it is to try to explain something to people who
| are unwilling to listen because they believe they already understand
| things better than their teachers.

Yeah, but I still prefer the student who tells me I am wrong, as long
as he gives a reason for thinking so. It is only if he persists after
his mistake has been pointed out to him that he becomes annoying.

I am not denying that this often happens on Usenet, of course.

Harald Hanche-Olsen

unread,
Nov 16, 2002, 7:42:28 AM11/16/02
to
+ Nils Goesche <n...@cartan.de>:

| Harald Hanche-Olsen <han...@math.ntnu.no> writes:
|
| > Only if you worry about such esoterica as how to construct the
| > natural numbers given nothing more than set theory do you dream
| > up seemingly crazy schemes such as 0={} (the empty set), 1={0},
| > 2={0,1}, etc.
|
| I don't see what's crazy about that.

Neither do I, which is why I wrote "seemingly". But when I was first
exposed to the idea, way back in the mists of time, I did think it was
crazy, at least until the idea began to sink in and I realized the
elegance of it all (as you describe so eloquently).

| The question ``What /is/ a variable, after all?创 is likewise
| interesting.

Even more so in mathematics than in computing, methinks. I have never
understood why the induction principle seems to be so difficult to
grasp, but it is an observable fact that many students fail to get
it. Actually, I think it is not the induction principle /per se/ that
confuses people, but that they have a more fundamental problem in
understanding what mathematics is all about, and in particular in
grasping the notion of a variable. If you haven't got a firm grip on
that, a proof by induction really seems circular, and so the students
are left wondering why they are told not to employ circular reasoning,
and yet, within the framework of induction, it is OK to do so?

I think the situation is very similar with respect to the notion of
variables in Lisp. Once you get it, it is blindingly obvious, but
when you try to explain this insight, you're still groping for words.
(And personally, I find I still struggle with the terminology, as
evidenced by an earlier posting of mine in this thread.)

Nils Goesche

unread,
Nov 16, 2002, 11:39:07 AM11/16/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

Sure. But the very notations (symbol-value 'x) or (setf
(symbol-value 'x) 42) look exactly as if somebody did a
(defstruct symbol ((value ...) ...) before. We are talking about
conceptual models for describing the semantics of Lisp variables.
If you avoid, for the moment, the SYMBOL-VALUE way of accessing a
(dynamic) variable's value it becomes clearer, for beginners,
that this is about evaluation, scope and environments of
variables and that you can perfectly understand their behavior
without thinking of a symbol as a data structure with a slot that
contains the value of the variable it denotes (which would give
you the wrong idea for lexical variables, anyway). As I said,
Lisp code is made up of symbols and conses (and other atoms!),
but as soon as we are trying to describe the semantics of the
/code/ this tree structure of objects /represents/, it is better
to get away as far as possible from the physical representation
of our code when we describe its /meaning/. Once this has been
understood, and only then, we can get to the additional cutie
that we can /also/ access the /semantic/ value of a dynamic
variable by accessing a physical ``value´´ slot of the symbol,
the data structure, that is used to represent it.

Erann Gat

unread,
Nov 16, 2002, 11:51:33 AM11/16/02
to
In article <87ptt6c...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:

> The question ``What /is/ a variable, after all?创 is likewise
> interesting.

Indeed.

The standard says:

A variable is a binding in the variable namespace.
A binding is an association between a name and that which the name denotes.
A namespace is [a set of] bindings whose denotations are restricted to a
particular kind.


My latest attempt to distill this for a revised version of TIG2SV:

A variable is a storage location that has a name. (Or a variant suggested
by Len Charest: a variable is a storage location that is identified by an
identifier.)

E.


---

<tangent>

On a challenge from Crispin Sartwell's website I once took a stab at
trying to define the word "seven". Here's what I came up with FWIW:


ZERO is a description of the non-existence of things. It is usually
applied to a particular kind of thing defined by a particular set of
properties within a particular context. "There are zero cows in my
office" means that within the context of my office there does not exist a
thing with the set of properties for which we use the shorthand notation
"cow".

ONE is a description of a particular kind of existence characterized by
the following property: there exists ONE (thing) if and only if it is not
possible to partition it into a subset and its complement such that both
the subset and its complement have the properties that define it. If you
have ONE cow then it is not possible to partition that cow into a subset
and its complement such that both the subset and its complement are cows.

Note that this partitioning is a *mental* partitioning, not a physical
one. This allows us to, for example, take a collection of cows and call
it ONE herd of cows by stipulating that one of the essential properties
that defines a herd is that it have a boundary beyond which there are no
cows.

TWO is a description of a particular kind of existence characterized by
the following property: there exist TWO (things) if and only if it is
possible to partition the context within which they exist into a subset
and its complement such that there is ONE in the subset and ONE in the
complement.

Note that there is an asymmetry here. To decide whether there is ONE of
something you have to partition the THING, but to decide whether there is
TWO of something you have to partition the CONTEXT. Thus, for some
collections of cows, it can be correct to say that there is both ONE and
TWO herds of cows depending on exactly how you choose to define a herd.

In general, if it is possible to partition a context such that there are X
in the subset and Y in the complement then we say that there exist X PLUS
Y. Thus, TWO is ONE PLUS ONE. THREE is TWO PLUS ONE (which is the same
as ONE PLUS ONE PLUS ONE) etc. Seven is three plus two plus two.

Nils Goesche

unread,
Nov 16, 2002, 12:55:54 PM11/16/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> In article <87ptt6c...@darkstar.cartan>, Nils Goesche <n...@cartan.de> wrote:
>

> > The question ``What /is/ a variable, after all?´´ is likewise


> > interesting.
>
> Indeed.
>
> The standard says:
>
> A variable is a binding in the variable namespace.
> A binding is an association between a name and that which the name denotes.
> A namespace is [a set of] bindings whose denotations are restricted to a
> particular kind.
>
>
> My latest attempt to distill this for a revised version of TIG2SV:
>
> A variable is a storage location that has a name. (Or a
> variant suggested by Len Charest: a variable is a storage
> location that is identified by an identifier.)

Quite good. I would like to be able to say ``A binding is an
association between a name and a storage location.´´ This takes
into account that the same name can denote different locations in
different contexts. A variable would simply be a name, then, I
guess.

> <tangent>
>
> On a challenge from Crispin Sartwell's website I once took a
> stab at trying to define the word "seven". Here's what I came
> up with FWIW:

Heh, nice. Call me weird, but I think that nothing can beat the
poetic beauty of the correct answer, though:

(defun define (n)
(labels ((pprint-k (n)
(pprint-logical-block (nil nil :prefix "{" :suffix "}")
(dotimes (i n)
(pprint-k i)
(when (< i (1- n))
(write-string ", ")
(pprint-newline :fill))))))
(let ((*print-pretty* t)
(*print-right-margin* 72))
(pprint-k n))
(values)))

CL-USER 15 > (define 7)
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
{{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}}}}

:-)

Nils Goesche

unread,
Nov 16, 2002, 1:59:07 PM11/16/02
to
I <n...@cartan.de> wrote:

> While this sounds a bit like an oxymoron because lexical
> bindings are usually lexically restricted to establishing forms

> and have dynamic extent, [...]

Oops, scratch that dynamic extent thing.

Sorry,

Erik Naggum

unread,
Nov 16, 2002, 2:23:15 PM11/16/02
to
* Nils Goesche

| The global environment, obviously, which is also called ``null
| lexical environmentดด to emphasize that it contains no lexically

| apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).

No, this is not right. That two things are the same in one respect does
not make them the same in all respects, which they would have to be to be
interchangeable. It is like `notด and `nullด.

| Whether this is legal code or not is not so interesting at the moment;
| what I like is that we can explain everything that happened in the above
| experiments without resorting to implementation issues if we simply say

| that X is part of such a thing as a ``global lexical environmentดด.

But there is no such thing. The whole point is that it is /not/ lexical.

| Christian Queinnec writes in ``Lisp in Small Piecesดด (p. 50):


|
| # In addition, if we do not find the dynamic value, then we go
| # back to the global lexical environment, since it also serves as
| # the global dynamic environment in Common Lisp.

I believe this is more accurate for Scheme.

| What /really/ goes on under the hood in the implementation is perfectly
| clear, anyway; but I find it interesting, anyway.

When the implementation is clear and the concepts are not, the conceptual
model is wrong.

Nils Goesche

unread,
Nov 16, 2002, 2:37:48 PM11/16/02
to
Erik Naggum <er...@naggum.no> writes:

> * Nils Goesche

> | Christian Queinnec writes in ``Lisp in Small Pieces´´ (p. 50):


> |
> | # In addition, if we do not find the dynamic value, then we go
> | # back to the global lexical environment, since it also serves as
> | # the global dynamic environment in Common Lisp.
>
> I believe this is more accurate for Scheme.

Yes, probably.

> | What /really/ goes on under the hood in the implementation is
> | perfectly clear, anyway; but I find it interesting, anyway.
>
> When the implementation is clear and the concepts are not,
> the conceptual model is wrong.

Heh, quite right. I'll go think about it some more.

Gareth McCaughan

unread,
Nov 16, 2002, 11:33:04 PM11/16/02
to
Nils Goesche wrote:

> Heh, nice. Call me weird, but I think that nothing can beat the
> poetic beauty of the correct answer, though:
>
> (defun define (n)
> (labels ((pprint-k (n)
> (pprint-logical-block (nil nil :prefix "{" :suffix "}")
> (dotimes (i n)
> (pprint-k i)
> (when (< i (1- n))
> (write-string ", ")
> (pprint-newline :fill))))))
> (let ((*print-pretty* t)
> (*print-right-margin* 72))
> (pprint-k n))
> (values)))
>
> CL-USER 15 > (define 7)
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}}}}

That's not "the correct answer", any more than the correct
answer to "What is a symbol?" is something like

struct Symbol {
LispObject * package;
LispObject * name;
LispObject * value;
};

In other words, it's one implementation of the number 7
(better: it's the number 7 in one implementation of the
natural numbers). There are others, such as {{{{{{{{}}}}}}}}
and { x : |x| = 7 } (er, obviously the latter won't do as it
stands; it also won't work in ZF set theory, but it's fine
in something like NF).

ObLisp:

(defstruct box x0 y0 x1 y1 children bordered)

(defun box-size (b)
(values (- (box-x1 b) (box-x0 b))
(- (box-y1 b) (box-y0 b))))

(defun box-translate (b dx dy)
(make-box :x0 (+ (box-x0 b) dx)
:y0 (+ (box-y0 b) dy)
:x1 (+ (box-x1 b) dx)
:y1 (+ (box-y1 b) dy)
:children (loop for child in (box-children b)
collect (box-translate child dx dy))
:bordered (box-bordered b)))

(defun box-translate-to (b x y)
(box-translate b (- x (box-x0 b)) (- y (box-y0 b))))

(defun box-surround (b delta)
(make-box :x0 (- (box-x0 b) delta)
:y0 (- (box-y0 b) delta)
:x1 (+ (box-x1 b) delta)
:y1 (+ (box-y1 b) delta)
:children (list b)
:bordered nil))

(defun bordered (b) (setf (box-bordered b) t) b)

(defun box-adjoin (b1 b2 delta direction)
(multiple-value-bind (x1 y1) (box-size b1)
(multiple-value-bind (x2 y2) (box-size b2)
(ecase direction
((:h)
(make-box :x0 0 :y0 0
:x1 (+ x1 x2 (* 3 delta))
:y1 (+ (max y1 y2) (* 2 delta))
:children (list (box-translate-to b1 delta delta)
(box-translate-to b2 (+ x1 (* 2 delta)) delta))
:bordered nil))
((:v)
(make-box :x0 0 :y0 0
:x1 (+ (max x1 x2) (* 2 delta))
:y1 (+ y1 y2 (* 3 delta))
:children (list (box-translate-to b1 delta delta)
(box-translate-to b2 delta (+ y1 (* 2 delta))))
:bordered nil))))))

(defun flip (direction)
(ecase direction
((:h) :v)
((:v) :h)))

(defun numerals (n size delta direction)
(if (zerop n)
(box-surround (make-box :x0 0 :y0 0 :x1 size :y1 size :bordered t) delta)
(box-adjoin (numeral n size delta (flip direction))
(numerals (1- n) size delta (flip direction))
delta
direction)))

(defun numeral (n size delta direction)
(if (zerop n)
(make-box :x0 0 :y0 0 :x1 size :y1 size :bordered t)
(bordered (numerals (1- n) size delta direction))))

(defun flatten (b)
(let ((rest (loop for child in (box-children b) nconc (flatten child))))
(if (box-bordered b)
(cons (list (box-x0 b) (box-y0 b) (box-x1 b) (box-y1 b)) rest)
rest)))

(defun show-flattened (boxes dx dy &optional (stream t))
(princ "%!PS
/box { /y1 exch def /x1 exch def /y0 exch def /x0 exch def
x0 y0 moveto x1 y0 lineto x1 y1 lineto x0 y1 lineto closepath stroke }
bind def
" stream)
(loop for (x0 y0 x1 y1) in boxes do
(format stream "~A ~A ~A ~A box~%" (+ x0 dx) (+ y0 dy) (+ x1 dx) (+ y1 dy)))
(princ "showpage
" stream))

(with-open-file (f "10.ps" :direction :output)
(show-flattened (flatten (numeral 10 3 3 :v)) 30 30 f))

This is rather nasty code in several ways, but its output is
rather lovely.

--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc

Nils Goesche

unread,
Nov 16, 2002, 11:52:36 PM11/16/02
to
Gareth McCaughan <Gareth.M...@pobox.com> writes:

> Nils Goesche wrote:
>
> > Heh, nice. Call me weird, but I think that nothing can beat the
> > poetic beauty of the correct answer, though:
> >

> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}},
> > {{}, {{}}, {{}, {{}}}, {{}, {{}}, {{}, {{}}}}}}}}
>
> That's not "the correct answer", any more than the correct
> answer to "What is a symbol?" is something like
>
> struct Symbol {
> LispObject * package;
> LispObject * name;
> LispObject * value;
> };
>
> In other words, it's one implementation of the number 7
> (better: it's the number 7 in one implementation of the
> natural numbers). There are others, such as {{{{{{{{}}}}}}}}
> and { x : |x| = 7 } (er, obviously the latter won't do as it
> stands; it also won't work in ZF set theory, but it's fine
> in something like NF).

I know. I meant it is my favorite among the correct answers.
And it is certainly the most poetic ;-)

> (with-open-file (f "10.ps" :direction :output)
> (show-flattened (flatten (numeral 10 3 3 :v)) 30 30 f))
>
> This is rather nasty code in several ways, but its output is
> rather lovely.

Very cool indeed. Thanks for this!

Aleksandr Skobelev

unread,
Nov 17, 2002, 4:46:50 AM11/17/02
to
Erik Naggum <er...@naggum.no> writes:

> * Nils Goesche
> | The global environment, obviously, which is also called ``null

> | lexical environment´´ to emphasize that it contains no lexically


> | apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).
>
> No, this is not right. That two things are the same in one respect does
> not make them the same in all respects, which they would have to be to be

> interchangeable. It is like `not´ and `null´.

Speaking frankly, I don't understand clearly what this phrase in
`3.1.1.3.1 The Null Lexical Environment' means:

"The null lexical environment is equivalent to the global
environment."

What the equivalence do they speak about? Do they mean that, like the
global environment, the null lexical environment contains no lexical
bindings? Or it might be that they speak about an equivalency in a sense
of bindings for functions and macros and proclamations/declarations? I'm
confused. :(

Kent M Pitman

unread,
Nov 17, 2002, 11:51:03 AM11/17/02
to
g...@jpl.nasa.gov (Erann Gat) writes:

> I assumed he meant something deeper: no great harm would come if we
> eliminated the functionality that symbol-value provides, under whatever
> guises that functionality exists in the language (including the ability to
> evaluate symbols at run time).

(eval '*foo*) would still exist.

Nils Goesche

unread,
Nov 17, 2002, 1:56:50 PM11/17/02
to
Aleksandr Skobelev <publi...@list.ru> writes:

> Erik Naggum <er...@naggum.no> writes:
>
> > * Nils Goesche
> > | The global environment, obviously, which is also called ``null
> > | lexical environment´´ to emphasize that it contains no lexically
> > | apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).
> >
> > No, this is not right. That two things are the same in one
> > respect does not make them the same in all respects, which
> > they would have to be to be interchangeable. It is like
> > `not´ and `null´.
>
> Speaking frankly, I don't understand clearly what this phrase in
> `3.1.1.3.1 The Null Lexical Environment' means:
>
> "The null lexical environment is equivalent to the global
> environment."
>
> What the equivalence do they speak about?

As I understand it, it means that whenever it says that a form is
evaluated in the null lexical environment, like the argument to
EVAL, for instance, it cannot access any lexically apparent
bindings. The only bindings it /can/ access are those in the
global environment and the current dynamic environment, but /no/
lexical ones.

> Do they mean that, like the global environment, the null
> lexical environment contains no lexical bindings?

Yes. I was only wondering about if it would make sense to
/introduce/ a notion of a global lexical binding when speaking
about Common Lisp to make it easier to explain some freaky code
snippets of questionable legal status. But whatever it was I was
talking about it wasn't Common Lisp as defined by the HyperSpec.

> I'm confused. :(

I hope it wasn't me who caused that :-)

Erik Naggum

unread,
Nov 17, 2002, 7:59:33 PM11/17/02
to
* Aleksandr Skobelev

| What the equivalence do they speak about?

Sigh. It means that when somebody says the "null lexical environment",
the expressin contains relevant information about (at least) two things:
(1) the perspective and (2) the object. The same holds for "the global
environment", of course, in which case the object is the same as for the
previous expression, but the /perspective/ is not.

| Do they mean that, like the global environment, the null lexical
| environment contains no lexical bindings?

The global environment is what you get when you have no lexical bindings.

The point here is that the lexical environment shadows the global. When
you have an empty/null lexical environment, you have nothing that could
shadow the global environment, therefore the consequence of viewing your
environment through the now empty/transparent lexical environment is that
you see only the background global environment. But it is possible to
look at the global environment /without/ looking through a transparent
lexical environment that shadows nothing, hence the two perspectives have
different names.

Think of bindings as squares on a blackboard. You can flip overlays over
the blackboard from both sides, and the overlays can have opaque squares
that shadow any other bindings but otherwise be transparent. Now, the
overlays attached to one side holds overlays for special bindings while
the other side holds lexical overlays, so you can flip them in from both
sides. A `special´ proclamation means that you cut a whole in all the
lexical overlays so that you will always see the dynamic bindings. When
you make a special binding, you make an opaque square on an overlay you
have flipped in from the special side and scribble on it. When you make a
lexical binding, you make an opaque square on an overlay you have flipped
in from the lexical side and scribble on it. When you call a function,
you temporarily remove all your lexical overlays, but the special overlays
remain, and you use a fresh set of lexical overlays. Now, if you make no
lexical bindings on this fresh set of overlays, you have the null lexical
environment. This is what `eval´ starts out with, just like any other
function before it makes its own lexical bindings, such as for incoming
arguments (which may also cause special bindings, btw).

Did that make the issue opaque or transparent?

And, please, there is no global lexical environment. While some evidently
think it is descriptive of something, it is an oxymoron that only confuses
people who do not understand what is going on.

Rob Warnock

unread,
Nov 18, 2002, 3:34:29 AM11/18/02
to
Nils Goesche <n...@cartan.de> wrote:
+---------------

| As I understand it, it means that whenever it says that a form is
| evaluated in the null lexical environment, like the argument to
| EVAL, for instance, it cannot access any lexically apparent
| bindings. The only bindings it /can/ access are those in the
| global environment and the current dynamic environment, but /no/
| lexical ones.
+---------------

Well, it *can*, of course, access any new lexical bindings introduced
in the expression being EVAL'd, as well as any lexical bindings
previously closed over by functions called by the EVAL'd code. You
didn't really mean to exclude those when you said "/no/ lexical ones",
did you?

To me, to say that "a form is evaluated in the null lexical environment"
means that the *current* lexical environment is not accessible.


-Rob

-----
Rob Warnock, PP-ASEL-IA <rp...@rpw3.org>
627 26th Avenue <URL:http://www.rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Aleksandr Skobelev

unread,
Nov 18, 2002, 9:12:39 AM11/18/02
to
Nils Goesche <n...@cartan.de> writes:

> Aleksandr Skobelev <publi...@list.ru> writes:

> > "The null lexical environment is equivalent to the global
> > environment."
> >
> > What the equivalence do they speak about?
>
> As I understand it, it means that whenever it says that a form is
> evaluated in the null lexical environment, like the argument to
> EVAL, for instance, it cannot access any lexically apparent
> bindings. The only bindings it /can/ access are those in the
> global environment and the current dynamic environment, but /no/
> lexical ones.

Yes, but there is nothing about the current dynamic environment in that
statement. So, it looks like we give some free interpretation for it.

>
> > Do they mean that, like the global environment, the null
> > lexical environment contains no lexical bindings?
>
> Yes. I was only wondering about if it would make sense to
> /introduce/ a notion of a global lexical binding when speaking
> about Common Lisp to make it easier to explain some freaky code
> snippets of questionable legal status.

Hmm, I'm not sure about how such a notion could be useful. It might be
that some examples of such freaky code (if you can find some easily)
could clear it.

> > I'm confused. :(
>
> I hope it wasn't me who caused that :-)

I'm afraid, I do it myself. :)

Aleksandr Skobelev

unread,
Nov 18, 2002, 8:45:54 AM11/18/02
to
Erik Naggum <er...@naggum.no> writes:

> * Aleksandr Skobelev
> | What the equivalence do they speak about?
>
> Sigh. It means that when somebody says the "null lexical environment",
> the expressin contains relevant information about (at least) two things:
> (1) the perspective and (2) the object. The same holds for "the global
> environment", of course, in which case the object is the same as for the
> previous expression, but the /perspective/ is not.
>
> | Do they mean that, like the global environment, the null lexical
> | environment contains no lexical bindings?
>
> The global environment is what you get when you have no lexical bindings.
>
> The point here is that the lexical environment shadows the global. When
> you have an empty/null lexical environment, you have nothing that could
> shadow the global environment, therefore the consequence of viewing your
> environment through the now empty/transparent lexical environment is that
> you see only the background global environment. But it is possible to
> look at the global environment /without/ looking through a transparent
> lexical environment that shadows nothing, hence the two perspectives have
> different names.

Hmm. It might be there is a mess in my poor head, but how about dynamic
environments?

----------
* (setf x 10)
Warning: This variable is undefined:
X

10
* (let ((x 20))
(declare (special x))
(let ((x 30))
(print x)
(eval 'x)))
30
20
*
----------

Here the lexical binding to 30 shadows the dynamic binding to 20, which
is in dynamic, but not the global environment. But eval sees 20, not 10.
So, isn't null lexical environment equivalent to a some dynamic + the
global environment?

>
> Think of bindings as squares on a blackboard. You can flip overlays over
> the blackboard from both sides, and the overlays can have opaque squares
> that shadow any other bindings but otherwise be transparent. Now, the
> overlays attached to one side holds overlays for special bindings while
> the other side holds lexical overlays, so you can flip them in from both
> sides. A `special´ proclamation means that you cut a whole in all the
> lexical overlays so that you will always see the dynamic bindings. When
> you make a special binding, you make an opaque square on an overlay you
> have flipped in from the special side and scribble on it. When you make a
> lexical binding, you make an opaque square on an overlay you have flipped
> in from the lexical side and scribble on it. When you call a function,
> you temporarily remove all your lexical overlays, but the special overlays
> remain, and you use a fresh set of lexical overlays. Now, if you make no
> lexical bindings on this fresh set of overlays, you have the null lexical
> environment. This is what `eval´ starts out with, just like any other
> function before it makes its own lexical bindings, such as for incoming
> arguments (which may also cause special bindings, btw).
>
> Did that make the issue opaque or transparent?

Sorry, I'm afraid I became enmeshed who has been overlaid by whom here. :)

Thank you. I think (well, I hope) I understand how fresh lexical/dynamic
bindings shadow each other and bindings in the global environment. What I
don't understand clear (and what I wrote about in my previous message) is
the usage of 'equivalent' word in the standard. Does it have the strict
technical or just some free, descriptive meaning? Just now it looks for
me like it is just descriptive and not absolutly full (if remember about
bindings in dynamic environments). But I suspect, that it might be
something wrong in my reasoning. :(

>
> And, please, there is no global lexical environment. While some evidently
> think it is descriptive of something, it is an oxymoron that only confuses
> people who do not understand what is going on.

Hear!

Nils Goesche

unread,
Nov 18, 2002, 9:21:47 AM11/18/02
to
rp...@rpw3.org (Rob Warnock) writes:

> Nils Goesche <n...@cartan.de> wrote:
> +---------------
> | As I understand it, it means that whenever it says that a form is
> | evaluated in the null lexical environment, like the argument to
> | EVAL, for instance, it cannot access any lexically apparent
> | bindings. The only bindings it /can/ access are those in the
> | global environment and the current dynamic environment, but /no/
> | lexical ones.
> +---------------
>
> Well, it *can*, of course, access any new lexical bindings
> introduced in the expression being EVAL'd, as well as any lexical
> bindings previously closed over by functions called by the EVAL'd
> code. You didn't really mean to exclude those when you said "/no/
> lexical ones", did you?

Of course not. Maybe I should say ``any bindings lexically apparent
to EVAL where it is called´´.

> To me, to say that "a form is evaluated in the null lexical
> environment" means that the *current* lexical environment is not
> accessible.

Of course.

Regards,
--
Nils Gösche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0

Nils Goesche

unread,
Nov 18, 2002, 9:30:22 AM11/18/02
to
Aleksandr Skobelev <publi...@list.ru> writes:

> Nils Goesche <n...@cartan.de> writes:
>
> > Aleksandr Skobelev <publi...@list.ru> writes:
>
> > > "The null lexical environment is equivalent to the global
> > > environment."
> > >
> > > What the equivalence do they speak about?
> >
> > As I understand it, it means that whenever it says that a form is
> > evaluated in the null lexical environment, like the argument to
> > EVAL, for instance, it cannot access any lexically apparent
> > bindings. The only bindings it /can/ access are those in the
> > global environment and the current dynamic environment, but /no/
> > lexical ones.
>
> Yes, but there is nothing about the current dynamic environment in
> that statement. So, it looks like we give some free interpretation
> for it.

I added ``the current dynamic environment´´ because EVALed forms can
access it (see dictionary entry for EVAL) /and/ the null lexical
environment:

CL-USER 133 > (defvar *foo* 42)
*FOO*

CL-USER 134 > *foo*
42

CL-USER 135 > (let ((*foo* 40))
(eval '(+ *foo* 2)))
42

works as well (*FOO* coming from the current dynamic environment) as

CL-USER 136 > (eval '(logand #xFF most-positive-fixnum))
255

(MOST-POSITIVE-FIXNUM available in the null lexical environment,
because it is part of the global environment).

> > > Do they mean that, like the global environment, the null
> > > lexical environment contains no lexical bindings?
> >
> > Yes. I was only wondering about if it would make sense to
> > /introduce/ a notion of a global lexical binding when speaking
> > about Common Lisp to make it easier to explain some freaky code
> > snippets of questionable legal status.
>
> Hmm, I'm not sure about how such a notion could be useful. It might
> be that some examples of such freaky code (if you can find some
> easily) could clear it.

I doubt it, but I posted some earlier in this thread.

Nils Goesche

unread,
Nov 18, 2002, 9:40:02 AM11/18/02
to
Aleksandr Skobelev <publi...@list.ru> writes:

> ----------
> * (setf x 10)
> Warning: This variable is undefined:
> X
>
> 10
> * (let ((x 20))
> (declare (special x))
> (let ((x 30))
> (print x)
> (eval 'x)))
> 30
> 20
> *
> ----------

Nice example, actually. Although you should somehow globally declare
X special, maybe by using DEFPARAMETER instead of just SETF, to clear
all doubt.

> Here the lexical binding to 30 shadows the dynamic binding to 20,
> which is in dynamic, but not the global environment. But eval sees
> 20, not 10. So, isn't null lexical environment equivalent to a some
> dynamic + the global environment?

No. EVAL can access /both/ a null lexical environment (meaning the
lexically apparent binding of x to 30 isn't visible) /and/ the current
dynamic environment. This is a specialty of EVAL (see its dictionary
entry) but has nothing to do with the term ``null lexical
environment´´ in itself.

Nils Goesche

unread,
Nov 18, 2002, 9:59:02 AM11/18/02
to
I <car...@cartan.de> wrote:

> Aleksandr Skobelev <publi...@list.ru> writes:
>
> > Here the lexical binding to 30 shadows the dynamic binding to 20,
> > which is in dynamic, but not the global environment. But eval sees
> > 20, not 10. So, isn't null lexical environment equivalent to a some
> > dynamic + the global environment?
>
> No. EVAL can access /both/ a null lexical environment (meaning the
> lexically apparent binding of x to 30 isn't visible) /and/ the current
> dynamic environment.

Aargh, this sounds dumb. We say ``null lexical environment´´ only to
emphasize that no lexically apparent binding is visible. That implies
that evaluating a form in a null lexical environment is ``equivalent´´
to evaluating it in the global environment -- but the bindings of
dynamic variables are /part/ of the global environment! So it isn't
really necessary to say ``some dynamic + the global environment´´
because the latter contains the former, anyway. But understanding
your example is made easier if one emphasizes that the current dynamic
environment is indeed visible.

Sorry,

Joe Marshall

unread,
Nov 18, 2002, 12:55:52 PM11/18/02
to
Nils Goesche <n...@cartan.de> writes:

> Sure. What I am trying to understand is the following:
>
> CL-USER 30 > (eval 'most-positive-double-float)
> 1.7976931348623165E308
>
> CL-USER 31 > (setf (symbol-value 'x) 42)
> 42
>
> CL-USER 32 > (eval 'x)
> 42
>
> There is indeed no lexically apparent binding for those two
> symbols. But their values are looked up somewhere, in an
> environment. Which is it?

Let me be pedantic here. The examples you are giving are fragments of
lisp code. Within these fragments are `identifiers' (symbolic tokens
with names such as "let", "x", and "declare") and `literals' (things
like 17). Some of the identifiers refer to `variables', some refer to
special syntactic forms. An identifier may refer to a `bound'
variable, or it may be a `free' variable. There are two rules for
evaluating a bound variable: If the variable is not `special', use
the binding in the closest lexical context. If the variable *is*
`special', look in the `value cell' of the symbol with the same name
as the variable.

There is a special evaluation rule for free variables: always look in
the `value cell' of the symbol with the same name as the variable.

> Neither MOST-POSITIVE-DOUBLE-FLOAT nor X have been declaimed
> special, however.

So in these cases:

> CL-USER 30 > (eval 'most-positive-double-float)
> 1.7976931348623165E308

> CL-USER 32 > (eval 'x)
> 42

the variables `most-positive-double-float' and `x' are free variables,
so the rule for free variables applies and the value cell is used.
(The rule for lexical variables does *not* apply because there is no
lexical binding.)

> The global environment, obviously, which is also called ``null

> lexical environment创 to emphasize that it contains no lexically


> apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).
>

> Now, MOST-POSITIVE-DOUBLE-FLOAT is a constant, which is not so
> interesting, but X is not. I can do
>
> CL-USER 33 > (setf (symbol-value 'x) 17)
> 17
>
> CL-USER 34 > (eval 'x)
> 17
>
> anytime I want. I can also do

This uses the free variable rule.


> CL-USER 35 > (let ((x 13))
> (+ x 5))
> 18

This uses the lexical variable rule.

> I would also like to try the following:
>
> (defun test (y)
> (+ x y))

Note that in the function TEST, the variable `x' is free, so the free
variable rule is used: the value cell of the symbol X will be used.

> (let ((x 20))
> (test 7))

But in this fragment, `x' is lexically bound. There is no way that
the function TEST (or any other function) can refer to this binding.

> Now, 3.2.2.3 Semantic Constraints says:
>
> # Special proclamations for dynamic variables must be made in the
> # compilation environment. Any binding for which there is no
> # special declaration or proclamation in the compilation
> # environment is treated by the compiler as a lexical binding.

In other words, if `x' is not special, then (let ((x 22)) ...)
establishes a lexical binding for `x', not a special binding.

> But I might snottily claim that I don't want X to be special,
> anyway :-)
>
> But what the heck, let's do it anyway:
>
> CL-USER 36 > (defun test (y)
> (+ x y))
> Warning: Syntactic warning for form X:
> X assumed special.
> TEST
>
> CL-USER 37 > (let ((x 20))
> (test 7))
> 24
>
> as expected.
>
> Whether this is legal code or not is not so interesting at the
> moment; what I like is that we can explain everything that
> happened in the above experiments without resorting to
> implementation issues if we simply say that X is part of such a

> thing as a ``global lexical environment创.

Well, I suppose you can call the collection of all value cells the
`global lexical environment', but I wouldn't.

> While this sounds a bit like an oxymoron because lexical bindings
> are usually lexically restricted to establishing forms and have
> dynamic extent, it is well possible to give the term a reasonable
> meaning.

Lexical variables have indefinite extent (you might close over them).


> Now, what happens if we do
>
> CL-USER 38 > (declaim (special x))
> NIL
>
> CL-USER 39 > (let ((x 20))
> (test 7))
> 27
>
> By globally declaring X special, we instruct the system to
> perform the last binding in the dynamic environment, instead. It
> is rather puzzling that TEST already behaves accordingly, too!

It shouldn't be puzzling. When you declaim X to be special, you
explicitly tell the compiler that when X is bound (as in the LET
statement that follows) the value cell of the symbol X should hold the
binding.

> So, now X is also part of the (global) dynamic environment,
> obviously. And it has kept its value :-)

I wouldn't say it quite that way. By declaiming X to be special, you
have changed the binding discipline for that variable. It keeps its
value in either case, it is just a matter of where that value is
stored (and of course the dynamic extent of the binding).

Erik Naggum

unread,
Nov 18, 2002, 1:14:48 PM11/18/02
to
* Aleksandr Skobelev <publi...@list.ru>

| So, isn't null lexical environment equivalent to a some dynamic + the
| global environment?

No.

Erik Naggum

unread,
Nov 18, 2002, 1:19:14 PM11/18/02
to
* Rob Warnock

| Well, it *can*, of course, access any new lexical bindings introduced in
| the expression being EVAL'd, as well as any lexical bindings previously
| closed over by functions called by the EVAL'd code. You didn't really
| mean to exclude those when you said "/no/ lexical ones", did you?

I fail to grasp what the problem is. The function `eval´ is no different
from any other function. That is the key. No other function can access
the caller's lexical environment, either. WTF is so special about `eval´
that it needs all this bogus attention? Yes, you call a function that
has captured some lexical bindings, but that does not change the fact
that function /calls/ in Common Lisp do not, cannot, know anything about
the caller's lexical environment.

Nils Goesche

unread,
Nov 18, 2002, 1:23:55 PM11/18/02
to
Joe Marshall <j...@ccs.neu.edu> writes:

> Nils Goesche <n...@cartan.de> writes:
>
> > Sure. What I am trying to understand is the following:
> >
> > CL-USER 30 > (eval 'most-positive-double-float)
> > 1.7976931348623165E308
> >
> > CL-USER 31 > (setf (symbol-value 'x) 42)
> > 42
> >
> > CL-USER 32 > (eval 'x)
> > 42
> >
> > There is indeed no lexically apparent binding for those two
> > symbols. But their values are looked up somewhere, in an
> > environment. Which is it?

[snip]

> There is a special evaluation rule for free variables: always look
> in the `value cell' of the symbol with the same name as the
> variable.

Yes, that this is what's actually done has been clear all the time. I
had been trying to explain all those evaluations /without/ referring
to this technique, I called that ``referring to the implementation´´,
rather than pure semantics. But maybe that was my mistake: This
lookup technique is actually part of the abstract semantics of the
language (at least if all the snippets are legal). The ease with
which you can explain everything now is certainly compelling,
especially when compared to my clumsy attempts of doing everything
with types of environments that don't even exist in the first place :-)

> > While this sounds a bit like an oxymoron because lexical bindings
> > are usually lexically restricted to establishing forms and have
> > dynamic extent, it is well possible to give the term a reasonable
> > meaning.
>
> Lexical variables have indefinite extent (you might close over
> them).

Yes, sorry again about this typo/thinko.

> > So, now X is also part of the (global) dynamic environment,
> > obviously. And it has kept its value :-)
>
> I wouldn't say it quite that way. By declaiming X to be special,
> you have changed the binding discipline for that variable. It keeps
> its value in either case, it is just a matter of where that value is
> stored (and of course the dynamic extent of the binding).

Sounds much better, indeed. Thanks for your patience.

Regards,

Aleksandr Skobelev

unread,
Nov 18, 2002, 12:40:37 PM11/18/02
to
Nils Goesche <car...@cartan.de> writes:

> Aleksandr Skobelev <publi...@list.ru> writes:
>
> > ----------
> > * (setf x 10)
> > Warning: This variable is undefined:
> > X
> >
> > 10
> > * (let ((x 20))
> > (declare (special x))
> > (let ((x 30))
> > (print x)
> > (eval 'x)))
> > 30
> > 20
> > *
> > ----------
>
> Nice example, actually. Although you should somehow globally declare
> X special, maybe by using DEFPARAMETER instead of just SETF, to clear
> all doubt.

Thanks. :) But it'd be an error to claim X special globally, because it'd
make all bindings for X dynamic. Whereas we need both dynamic and lexical
bindings here. (This example was produced under CMUCL with
'(setf *top-level-auto-declare* nil)' that switched off autodeclaration
of free global variables to be special.)

Aleksandr Skobelev

unread,
Nov 18, 2002, 1:51:37 PM11/18/02
to
Nils Goesche <car...@cartan.de> writes:

> I <car...@cartan.de> wrote:
>
> > No. EVAL can access /both/ a null lexical environment (meaning the
> > lexically apparent binding of x to 30 isn't visible) /and/ the current
> > dynamic environment.
>
> Aargh, this sounds dumb. We say ``null lexical environment´´ only to
> emphasize that no lexically apparent binding is visible. That implies
> that evaluating a form in a null lexical environment is ``equivalent´´
> to evaluating it in the global environment -- but the bindings of
> dynamic variables are /part/ of the global environment!

I'm not sure. For the global environment contains bindings with
indefinite scope and indefinite extent, while dynamic binding in LET form
has dynamic extent (limited inside the form).

> So it isn't
> really necessary to say ``some dynamic + the global environment´´
> because the latter contains the former, anyway.

I inclined to consider them as different notions. The global environment
is an object of environment class that "contains, among other things, the
following:

* bindings of dynamic variables and constant variables.
* bindings of functions, macros, and special operators.
* bindings of compiler macros.
* bindings of type and class names
* information about proclamations."

There is only one such object.

A dynamic environment is a class of environment that "contains, among
other things, the following:

* bindings for dynamic variables.
* information about active catch tags.
* information about exit points established by unwind-protect.
* information about active handlers and restarts."

So I see that each class contains information that is not in other. And
because of that I don't able to say that one class include other.

If consider model where several Lisp processes run there are only one
global environment and several dynamic environments simultaneously
(one per process).

That are my reasonings. But they of course might have some, still
undisclosed for me, deficiencies.


Nils Goesche

unread,
Nov 18, 2002, 2:07:52 PM11/18/02
to
Aleksandr Skobelev <publi...@list.ru> writes:

> Nils Goesche <car...@cartan.de> writes:
>
> > Aleksandr Skobelev <publi...@list.ru> writes:
> >
> > > ----------
> > > * (setf x 10)
> > > Warning: This variable is undefined:
> > > X
> > >
> > > 10
> > > * (let ((x 20))
> > > (declare (special x))
> > > (let ((x 30))
> > > (print x)
> > > (eval 'x)))
> > > 30
> > > 20
> > > *
> > > ----------
> >
> > Nice example, actually. Although you should somehow globally
> > declare X special, maybe by using DEFPARAMETER instead of just
> > SETF, to clear all doubt.
>
> Thanks. :) But it'd be an error to claim X special globally, because
> it'd make all bindings for X dynamic. Whereas we need both dynamic
> and lexical bindings here.

Duh! Correct, sorry. I guess I am too tired today. I'll go home and
have some sleep now.

Nils Goesche

unread,
Nov 18, 2002, 2:18:53 PM11/18/02
to
Aleksandr Skobelev <publi...@list.ru> writes:

> Nils Goesche <car...@cartan.de> writes:

> > We say ``null lexical environment´´ only to emphasize that no
> > lexically apparent binding is visible. That implies that
> > evaluating a form in a null lexical environment is ``equivalent´´
> > to evaluating it in the global environment -- but the bindings of
> > dynamic variables are /part/ of the global environment!
>
> I'm not sure. For the global environment contains bindings with
> indefinite scope and indefinite extent, while dynamic binding in LET
> form has dynamic extent (limited inside the form).

I don't think it makes much of a difference whether you define it one
way or the other. For instance, we have

# 3.1.2.1.1.2 Dynamic Variables

# At any given time, all dynamic variables with a given name refer to
# exactly one binding, either in the dynamic environment or in the
# global environment.

> > So it isn't really necessary to say ``some dynamic + the global
> > environment´´ because the latter contains the former, anyway.

Ok, this seems to be imprecise (or even wrong).

> I inclined to consider them as different notions. The global
> environment is an object of environment class that "contains, among
> other things, the following:

[snip]

> So I see that each class contains information that is not in
> other. And because of that I don't able to say that one class
> include other.

Ok.

> That are my reasonings. But they of course might have some, still
> undisclosed for me, deficiencies.

Sounds good to me.

Regards,

Kurt B. Kaiser

unread,
Nov 18, 2002, 3:17:09 PM11/18/02
to
Erik Naggum <er...@naggum.no> writes:

> The function `eval´ is no different from any other function. That
> is the key. No other function can access the caller's lexical
> environment, either. WTF is so special about `eval´ that it needs
> all this bogus attention? Yes, you call a function that has
> captured some lexical bindings, but that does not change the fact
> that function /calls/ in Common Lisp do not, cannot, know anything
> about the caller's lexical environment.

So the necessary parts of the calling function's environment must be
explicitly passed to the callee. Hm. Not your father's dynamic Lisp.

Do people who are up to speed in CL use flet and labels when they can,
or do they tend to define everything at top level?

Is there an advantage to using flet instead of labels when the code
doesn't require using labels?

KBK

Kurt B. Kaiser

unread,
Nov 18, 2002, 3:20:26 PM11/18/02
to
Erik Naggum <er...@naggum.no> writes:

> Did that make the issue opaque or transparent?

Very nice. When do you write your introductory Lisp text?

Followed, hopefully, by the Lisp 101 text.

KBK

Tim Bradshaw

unread,
Nov 18, 2002, 5:47:05 PM11/18/02
to
* Kurt B Kaiser wrote:

> Do people who are up to speed in CL use flet and labels when they can,
> or do they tend to define everything at top level?

I use both quite a lot. I often write (large) functions which are
actually a bundle of local functions which do the work. They may (but
may not) use lexical bindings from the parent, but in any case all
those functions are only needed in one place, why define them
globally?

But my style is probably quite idiosyncratic - the resulting 50-300
line functions might make people queasy until they realise that they
are actually complete little worlds, like cheap packages...

> Is there an advantage to using flet instead of labels when the code
> doesn't require using labels?

Sometimes (not often) it requires FLET, for instance shadowing a
global (non-CL-defined) function (there are good uses for this,
honest!)

--tim (this article makes me sound like the worst kind of hacker...)

Kurt B. Kaiser

unread,
Nov 18, 2002, 8:32:11 PM11/18/02
to
Nils Goesche <car...@cartan.de> writes:

> > > So it isn't really necessary to say ``some dynamic + the global

> > > environment创 because the latter contains the former, anyway.


>
> Ok, this seems to be imprecise (or even wrong).

In threaded code, I take it that each thread has its own dynamic
environment, but shares the global environment.

KBK

Kurt B. Kaiser

unread,
Nov 18, 2002, 8:52:43 PM11/18/02
to
Erik Naggum <er...@naggum.no> writes:

> WTF is so special about `eval´ that it needs all this bogus
> attention? Yes, you call a function that has captured some
> lexical bindings, but that does not change the fact that function
> /calls/ in Common Lisp do not, cannot, know anything about the
> caller's lexical environment.

Actually, it is surprising to me (not being that familiar with CL)
that eval did not do its thing in the environment of the let. I
looked it up, and now understand that it uses the global environment.
Why would it be designed that way?

KBK

Thomas F. Burdick

unread,
Nov 18, 2002, 9:02:46 PM11/18/02
to

Rather, ask why it wouldn't. EVAL is just a function like any other.
It takes its argument, which it then interprets as CL code[*]. A
complete CL interpreter in CL only takes a few hundred lines of code,
after all, so there's no need for any magic.

If you could capture the current runtime lexical environment as an
object, then you could write a two-argument EVAL. But that would have
horrible performance implications, for very little real benefit.

[*] It can "interpret" it by compiling, of course.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Kenny Tilton

unread,
Nov 18, 2002, 10:21:17 PM11/18/02
to

Kurt B. Kaiser wrote:
> Actually, it is surprising to me (not being that familiar with CL)
> that eval did not do its thing in the environment of the let. I
> looked it up, and now understand that it uses the global environment.
> Why would it be designed that way?

From the spec (3.8.4 eval):

"Examples:

(setq form '(1+ a) a 999) 999
(eval form) 1000
(eval 'form) (1+ A)
(let ((a '(this would break if eval used local value))) (eval form))
1000"

ie, dont think of eval as only being used for a literal form (if I am
guessing correctly the source of your surprise).

--

kenny tilton
clinisys, inc
---------------------------------------------------------------
""Well, I've wrestled with reality for thirty-five years, Doctor,
and I'm happy to state I finally won out over it.""
Elwood P. Dowd

Kurt B. Kaiser

unread,
Nov 18, 2002, 11:05:44 PM11/18/02
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> Kurt B. Kaiser wrote:
> > Actually, it is surprising to me (not being that familiar with CL)
> > that eval did not do its thing in the environment of the let. I
> > looked it up, and now understand that it uses the global environment.
> > Why would it be designed that way?
>
> From the spec (3.8.4 eval):
>
> "Examples:
>
> (setq form '(1+ a) a 999) 999
> (eval form) 1000
> (eval 'form) (1+ A)
> (let ((a '(this would break if eval used local value))) (eval form))
> 1000"
>
> ie, dont think of eval as only being used for a literal form (if I am
> guessing correctly the source of your surprise).

Hyperspec:

"Evaluates form in the current dynamic environment and the null
[i.e. empty] lexical environment."

ANSI CL (Graham):
"(eval expression) Evaluates expression in the global environment."

I was using the latter until I read your post. To me, there is a
difference, e.g. threads.

Hm. Using the dynamic environment makes more sense to me.

No, what surprised me was that the "lexical" x in the let didn't
shadow the prior dynamic x.

KBK

Erik Naggum

unread,
Nov 18, 2002, 11:24:04 PM11/18/02
to
* Kurt B. Kaiser

| In threaded code, I take it that each thread has its own dynamic
| environment, but shares the global environment.

Good observation. This is normally the case.

Erik Naggum

unread,
Nov 18, 2002, 11:25:24 PM11/18/02
to
* Kurt B. Kaiser

| Actually, it is surprising to me (not being that familiar with CL) that
| eval did not do its thing in the environment of the let. I looked it up,
| and now understand that it uses the global environment. Why would it be
| designed that way?

Because it is an ordinary function.

I am genuinely puzzled: Why is this so hard to grasp?

Kurt B. Kaiser

unread,
Nov 19, 2002, 12:57:27 AM11/19/02
to
Erik Naggum <er...@naggum.no> writes:

> * Kurt B. Kaiser
> | Actually, it is surprising to me (not being that familiar with CL) that
> | eval did not do its thing in the environment of the let. I looked it up,
> | and now understand that it uses the global environment. Why would it be
> | designed that way?
>
> Because it is an ordinary function.
>
> I am genuinely puzzled: Why is this so hard to grasp?

HyperSpec:
"Note that an eval form involves two levels of evaluation for its
argument. First, form is evaluated by the normal argument evaluation
mechanism as would occur with any call. The object that results from
this normal argument evaluation becomes the value of the form
parameter, and is then evaluated as part of the eval form. "

In light of this (especially the second sentence), and using
Skobelev's example from the other side of this thread,

----------
* (setf x 10)
Warning: This variable is undefined:
X

10
* (let ((x 20))
(declare (special x))
(let ((x 30))
(print x)
(eval 'x)))
30
20
*
----------

I would have expected eval to evaluate its argument in the lexical
environment of the let block. Other functions, like print, have their
arguments evaluated in that lexical environment before being passed.

However, the _effect_ of eval seems to be not quite like other
functions because when it evaluates its argument it does so in the
current dynamic environment, and that is definitely not what I was
expecting. Maybe if it was called dynamic-eval I would have caught on
immediately.

* Eric Naggum


> "Now, if you make no lexical bindings on this fresh set of overlays,
> you have the null lexical environment. This is what `eval starts
> out with, just like any other function before it makes its own
> lexical bindings, such as for incoming arguments (which may also
> cause special bindings, btw)."

You can think of it that way but isn't "null lexical environment" just
a fancy way of saying (and emphasizing) "no lexical environment?" So,
attempting to extend your example for the case of eval, can one say the
dynamic overlay is flipped into place and the lexical overlay is not?
Can eval write on the "lexical overlay"?

On a slightly different, but closely related, subject, I find it
confusing that the `special declaration also "punches holes" in those
parts of the lexical overlay which were created after the last dynamic
binding, as in the example. In this case, my intuition expected the x
in the let to shadow the dynamic binding, but clearly I'm getting an
intuition upgrade.

KBK

Erik Naggum

unread,
Nov 19, 2002, 1:07:14 AM11/19/02
to
* Kurt B. Kaiser

| I would have expected eval to evaluate its argument in the lexical
| environment of the let block.

But /why/? When you quote x, you explicitly request that it /not/ be
evaluated. You pass `eval´ a symbol, not a value from the lexical
environment. If you want the latter effect, do not quote x.

| Other functions, like print, have their arguments evaluated in that
| lexical environment before being passed.

If you try `(print 'x)´, it will print `x´, not the value thereof.

| However, the _effect_ of eval seems to be not quite like other functions
| because when it evaluates its argument it does so in the current dynamic
| environment, and that is definitely not what I was expecting.

All other functions do the same. This is how function evaluation works.
This is how the dynamic environment works.

| On a slightly different, but closely related, subject, I find it
| confusing that the `special declaration also "punches holes" in those
| parts of the lexical overlay which were created after the last dynamic
| binding, as in the example.

I have no idea what this means.

I believe you still think in a different language and are unwilling to
let go of what you believe you understand. Like perhaps `eval´ in Perl.

Kenny Tilton

unread,
Nov 19, 2002, 1:20:51 AM11/19/02
to

Kurt B. Kaiser wrote:
> However, the _effect_ of eval seems to be not quite like other
> functions because when it evaluates its argument it does so in the
> current dynamic environment, and that is definitely not what I was
> expecting.

(defun interpret-this (some-code)
(let ((a 1) (b 2) (c :whatever))
(eval some-code)))

I am no expert on eval or anything else for that matter, but when I look
at the above, I would be appalled if the evaluation of some-code were
affected by the lexical bindings of a, b, and c.

But dynamic bindings (to my way of thinking) are inescapable, hence
some-code "seeing" those.

Like everything else about Lisp, it works exactly as I need, want, and
would expect it to work since the value held by the parameter some-code
was born lexically elsewhere and seen originally by the compiler as
literal, symbolic data only /later/ to be promoted to runnable code by
eval.

Erik Naggum

unread,
Nov 19, 2002, 1:31:36 AM11/19/02
to
* Kenny Tilton

| (defun interpret-this (some-code)
| (let ((a 1) (b 2) (c :whatever))
| (eval some-code)))
|
| I am no expert on eval or anything else for that matter, but when I look
| at the above, I would be appalled if the evaluation of some-code were
| affected by the lexical bindings of a, b, and c.

Do not forget `some-code´ in this list.

Your example is instructive for quite another reason. Do those who think
that `eval´ should "work" in the lexical environment of the caller, also
think this should hold for calls to `interpret-this´? If not, why not?

Lars Magne Ingebrigtsen

unread,
Nov 19, 2002, 1:34:38 AM11/19/02
to
Erik Naggum <er...@naggum.no> writes:

> I am genuinely puzzled: Why is this so hard to grasp?

I certainly was surprised the first time I used `eval' in Common Lisp.
I was used to `eval'-ing things in Emacs Lisp, and Emacs Lisp doesn't
have lexical bindings. I didn't consider the implications on lexical
bindings on `eval'.

--
(domestic pets only, the antidote for overdose, milk.)
la...@gnus.org * Lars Magne Ingebrigtsen

Coby Beck

unread,
Nov 19, 2002, 1:43:28 AM11/19/02
to

"Kurt B. Kaiser" <k...@shore.net> wrote in message
news:m3isyug...@float.attbi.com...

> * (let ((x 20))
> (declare (special x))
> (let ((x 30))
> (print x)
> (eval 'x)))
> 30
> 20
> *
> ----------
>
> I would have expected eval to evaluate its argument in the lexical
> environment of the let block. Other functions, like print, have their
> arguments evaluated in that lexical environment before being passed.

eval is the same, consider this:


(let ((x 20))
(declare (special x))
(let ((x 30))
(print 'x)

(print x)
(values
(eval 'x)
(eval x))))

X
30
20
30


--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")


It is loading more messages.
0 new messages