Newbie asking for help

30 views
Skip to first unread message

The Glauber

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
Allright... i've almost finished my second reading of Winston&Horn,
i've skimmed through some web-available tutorials, i'm a professional
programmer, i should be able to do this Lisp thing now, right? wrong.

I'm having trouble going from the tutorials to the real world. For
example, a lot of what i do is related to processing text files. So, i
though i'd write a simple/stupid program to count the number of lines
in a file. Here it is:

;; count number of lines in file key.html
(with-open-file (ifile "key.html" :direction :input)
(setf nlines 0)
(loop
(if (read-line ifile nil)
(setf nlines (+ 1 nlines))
(return nlines))))


It doesn't work (it just hangs, so i think it's stuck in the loop). I
thought it would read lines until the end of the file, when the read-
line would return nil, and that would trigger the second form inside
the if (a return, to get out of the loop).

I'm sorry for posting something so stupid, but why doesn't this work?

--
Glauber Ribeiro
thegl...@my-deja.com
"Opinions stated are my own and not representative of Experian"


Sent via Deja.com http://www.deja.com/
Before you buy.

The Glauber

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
In article <8iti9v$d19$1...@nnrp1.deja.com>, glauber wrote:

[...]


> ;; count number of lines in file key.html
> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil)
> (setf nlines (+ 1 nlines))
> (return nlines))))
>
> It doesn't work (it just hangs, so i think it's stuck in the loop). I

[...]


OK. Using TRACE, i found that read-line wasn't returning nil, but
something like #<END-OF-FILE>. So i added the third optional parameter,
the one that tells it what to return at end of file. This made me do
the (IF) backwards:

;; count lines


(with-open-file (ifile "key.html" :direction :input)
(setf nlines 0)
(loop

(if (eql 'eof (read-line ifile nil 'eof))
(return (print nlines))
(setf nlines (+ 1 nlines)))))


And it works...

And, of course, this works too:

(with-open-file (ifile "key.html" :direction :input)
(setf nlines 0)
(loop

(if (read-line ifile nil nil)


(setf nlines (+ 1 nlines))

(return (print nlines)))))

So, i plod along, undaunted...
I'm pretty sure this is an ugly program, and i appreciate suggestions.

Jochen Schmidt

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
The Glauber wrote:

> ;; count number of lines in file key.html
> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil)
> (setf nlines (+ 1 nlines))
> (return nlines))))
>
> It doesn't work (it just hangs, so i think it's stuck in the loop). I

> thought it would read lines until the end of the file, when the read-
> line would return nil, and that would trigger the second form inside
> the if (a return, to get out of the loop).
>
> I'm sorry for posting something so stupid, but why doesn't this work?

It works for me in cmucl (warning on the nondefined variable "nlines")
It works in Allegro Trial Edition 5.0.1 for Linux (without warnings)
It works in Lispworks Personal Edition 4.1.18 (without warnings)
But it seems NOT to work with clisp !!! (as the former author noted, it
blocks)

have not looked further into it, but I found this interesting enough to
post it.

--
sincerely Yours,
Jochen Schmidt
j...@dataheaven.de
http://www.dataheaven.de

Erik Naggum

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
* The Glauber <thegl...@my-deja.com>

| I'm having trouble going from the tutorials to the real world. For
| example, a lot of what i do is related to processing text files.
| So, i though i'd write a simple/stupid program to count the number
| of lines in a file. Here it is:
|
| ;; count number of lines in file key.html
| (with-open-file (ifile "key.html" :direction :input)
| (setf nlines 0)
| (loop
| (if (read-line ifile nil)
| (setf nlines (+ 1 nlines))
| (return nlines))))

You're using a free variable, nlines, in this code. You should not
use a free variable unless you have very specific need for it. This
does not affect the correctness of your code, however.

| It doesn't work (it just hangs, so i think it's stuck in the loop).

Try being explicit in the value of eof-value, i.e.

(read-line ifile nil nil)

| I thought it would read lines until the end of the file, when the
| read- line would return nil, and that would trigger the second form
| inside the if (a return, to get out of the loop).

I think it would be instructive to print the value from read-line:

(print (read-line ifile nil))

print returns its value.

| I'm sorry for posting something so stupid, but why doesn't this work?

Seems like a bug in your Common Lisp implementation. Which is it?

#:Erik
--
If this is not what you expected, please alter your expectations.

Erik Naggum

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
* Jochen Schmidt <kid_s...@gmx.de>

| But it seems NOT to work with clisp !!! (as the former author noted,
| it blocks)

Thanks for noting this. I'm waiting for a report from Bruno Haible
whether this was a typo in the standard or (gasp!) a bug in CLISP.

Thom Goodsell

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil nil)

> (setf nlines (+ 1 nlines))
> (return (print nlines)))))
>
> So, i plod along, undaunted...
> I'm pretty sure this is an ugly program, and i appreciate suggestions.

Ok, a few suggestions, then. As Erik mentioned, nlines is a free
variable. Use a let form. It's probably stylistic, but I prefer the
much-more-compact (incf) function to using (set x (+ 1 x)). Also, you
can replace the if construct with features of the loop facility -- use
while and finally. Some people may argue this stylistically, but I like
prefer it [1].

So, the revised, slightly cleaner code looks like this:

(with-open-file (ifile "key.html" :direction :input)

(let ((nlines 0))
(loop
while (read-line ifile nil nil)
do (incf nlines)
finally (return nlines))))

The even more compact version uses the for and from loop functionality:

(with-open-file (ifile "key.html" :direction :input)

(loop
for nlines from 0
while (read-line ifile nil nil)
finally (return nlines)))


Thom

[1] I learned my Lisp somewhat in a vacuum, so I sometimes find that
what I consider elegant or clean, other people consider ugly or unclear.

Thom Goodsell
Scientist t...@cra.com
Charles River Analytics (617) 491-3474 x574
Cambridge, MA, USA http://www.cra.com/

Lieven Marchand

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
The Glauber <thegl...@my-deja.com> writes:

> And, of course, this works too:
>

> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil nil)
> (setf nlines (+ 1 nlines))
> (return (print nlines)))))
>
> So, i plod along, undaunted...
> I'm pretty sure this is an ugly program, and i appreciate suggestions.

This isn't meant to reopen the great LOOP flame war but one way of
doing it is:

(with-open-file (ifile "key.html" :direction :input)

(loop for line = (read-line ifile nil)
while line
counting 1))

If the loop implementation of your CL system supports extending loop
paths you can even write a loop path that gives you each line in the
file. I have such a thing in my .clinit.

Then you can do:

(loop for line being each line of ifile
count 1)

If you use the simple loop, you might consider do:

(with-open-file (ifile "/etc/passwd" :direction :input)
(do ((line (read-line ifile nil) (read-line ifile nil))
(count 0))
((null line) count)
(incf count)))

--
Lieven Marchand <m...@bewoner.dma.be>
When C++ is your hammer, everything looks like a thumb. Steven M. Haflich

Pierre R. Mai

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
The Glauber <thegl...@my-deja.com> writes:

> In article <8iti9v$d19$1...@nnrp1.deja.com>, glauber wrote:
>
> [...]

> > ;; count number of lines in file key.html

> > (with-open-file (ifile "key.html" :direction :input)
> > (setf nlines 0)
> > (loop

> > (if (read-line ifile nil)


> > (setf nlines (+ 1 nlines))

> > (return nlines))))
> >
> > It doesn't work (it just hangs, so i think it's stuck in the loop). I
> [...]
>
>
> OK. Using TRACE, i found that read-line wasn't returning nil, but
> something like #<END-OF-FILE>. So i added the third optional parameter,
> the one that tells it what to return at end of file. This made me do
> the (IF) backwards:

I think you should report that as a bug to the implementors of CLISP.
The HyperSpec is quite clear in that the default value for eof-value
should be nil, and therefore (read-line stream nil) should always
return nil at the end of file. At least that is my reading of the
standard.

BTW: I very often supply the eof-value explicitly, for reasons of
clarity.

> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil nil)
> (setf nlines (+ 1 nlines))
> (return (print nlines)))))
>
> So, i plod along, undaunted...
> I'm pretty sure this is an ugly program, and i appreciate suggestions.

OK, you asked for it ;)

- The most obviously mistake lies in your use of setf to establish a
new variable. In the absence of any binding, this will be treated
as a reference to a global special variable, which you don't want.
Use let to introduce local lexical variables. Once such a binding
exists, you can alter the value of the binding via setf & friends,
if you want to.

- The variable names are distinctly unlispy: Since CL (and Scheme)
allows useful separator characters in symbols, and your environment
relieves you of the burden of retyping long names, you are free to
use long, self-descriptive names.

- Wrap your code fragment in a function definition, and you get a
ready made line-counting function for free...

- While working with low-level looping constructs can be instructive,
most programmers would use a higher-level looping construct to
more clearly express the intent of the code.

- Don't print the result yourself, since the surrounding code or the
top-level read-eval-print loop will already do this for you

- Use documentation strings to document your functions

Given all of the above, your function might be written like this

(defun count-lines-in-file (filename)
"Count the lines in the file indicated by `filename'."
(with-open-file (stream filename :direction :input)
(do ((line-count 0 (1+ line-count)))
((null (read-line stream nil nil)) line-count))))

Or, using the extended loop facility:

(defun count-lines-in-file (filename)
"Count the lines in the file indicated by `filename'."
(with-open-file (stream filename :direction :input)
(loop while (read-line stream nil nil)
sum 1)))

Or, using simple loop, like you did:

(defun count-lines-in-file (filename)
"Count the lines in the file indicated by `filename'."
(with-open-file (stream filename :direction :input)
(let ((line-count 0))
(loop
(if (read-line stream nil nil)
(incf line-count)
(return line-count))))))

Beware that all of the code is untested, though ;)

Regs, Pierre.

--
Pierre Mai <pm...@acm.org> PGP and GPG keys at your nearest Keyserver
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]

The Glauber

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
In article <31706874...@naggum.no>,
Erik Naggum <er...@naggum.no> wrote:
[...]

> Try being explicit in the value of eof-value, i.e.
>
> (read-line ifile nil nil)

Precisely!

[...]

>
> Seems like a bug in your Common Lisp implementation. Which is it?
>


CLISP on win32. It turns out, it was returning something like #<END-OF-
FILE> instead of a nil. Making it explicit fixed the problem.

Thanks!

glauber

The Glauber

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to Thom Goodsell
In article <39526DAF...@cra.com>,
Thom Goodsell <t...@cra.com> wrote:
[...]

> Ok, a few suggestions, then. As Erik mentioned, nlines is a free
[...]

Thanks!

The Glauber

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to pm...@acm.org
In article <87hfal3...@orion.dent.isdn.cs.tu-berlin.de>,
pm...@acm.org (Pierre R. Mai) wrote:
[...]

> OK, you asked for it ;)

s...@usa.net

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
In article <8iti9v$d19$1...@nnrp1.deja.com>,

The Glauber <thegl...@my-deja.com> wrote:
>
> ;; count number of lines in file key.html
> (with-open-file (ifile "key.html" :direction :input)
> (setf nlines 0)
> (loop
> (if (read-line ifile nil)
> (setf nlines (+ 1 nlines))
> (return nlines))))

this works fine for me in the current version of CLISP.
in older versions of CLISP, (read-line VAR nil) returned #<EOF> and
not NIL on eof.
you should add a third arg (read-line ifile nil nil) and it will work.
sorry about the bug.
You will get a faster response if you ask CLISP-specific questions on
the clisp-list mailing list (see http://clisp.cons.org)

Erik Naggum

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
* Lieven Marchand <m...@bewoner.dma.be>

| This isn't meant to reopen the great LOOP flame war but one way of
| doing it is:
|
| (with-open-file (ifile "key.html" :direction :input)
| (loop for line = (read-line ifile nil)
| while line
| counting 1))

Simply using while (read-line ifile nil nil) seems even more compact.

However, I have this negative gut reaction to wanton waste, as in
effectively allocating as many strings as there are lines for no
good reason, just exercising the garbage collector, so while we're
at it, how about

(loop for char = (read-char ifile nil nil)
while char
count (char= char #\newline))

Note that read-line will return nil on an empty file, but the data
leading up to the end-of-file if no newline intervened and then nil
on the next call, effectively counting a non-empty file containing
no newlines as having one line. This may be relevant.

| (loop for line being each line of ifile
| count 1)

Elegant.

Christopher Browne

unread,
Jun 23, 2000, 3:00:00 AM6/23/00
to
Centuries ago, Nostradamus foresaw a time when The Glauber would say:

>In article <8iti9v$d19$1...@nnrp1.deja.com>, glauber wrote:
>[...]
>> ;; count number of lines in file key.html
>> (with-open-file (ifile "key.html" :direction :input)
>> (setf nlines 0)
>> (loop
>> (if (read-line ifile nil)
>> (setf nlines (+ 1 nlines))
>> (return nlines))))
>>
>> It doesn't work (it just hangs, so i think it's stuck in the loop). I
>[...]
>
>OK. Using TRACE, i found that read-line wasn't returning nil, but
>something like #<END-OF-FILE>. So i added the third optional parameter,
>the one that tells it what to return at end of file. This made me do
>the (IF) backwards:

#<END-OF-FILE> may be "pretty cool," but certainly isn't conformant
with the standard.

>;; count lines


>(with-open-file (ifile "key.html" :direction :input)

> (setf nlines 0)
> (loop


> (if (eql 'eof (read-line ifile nil 'eof))
> (return (print nlines))
> (setf nlines (+ 1 nlines)))))
>
>
>And it works...
>

>And, of course, this works too:
>

>(with-open-file (ifile "key.html" :direction :input)

> (setf nlines 0)
> (loop
> (if (read-line ifile nil nil)


> (setf nlines (+ 1 nlines))

> (return (print nlines)))))
>
>So, i plod along, undaunted...
>I'm pretty sure this is an ugly program, and i appreciate suggestions.

I somewhat like the following:
(with-open-file
(ifile "c:/home/html/lynx-boo.htm" :direction :input)
(loop
for line = (read-line ifile nil 'eof)
for lines = 0 then (+ lines 1) ;;; Line count...
until (eql line 'eof)
finally (return lines)))

The use of "for" clauses has the merit of eliminating the extra
control structures inside the loop.
--
cbbr...@acm.org - <http://www.ntlug.org/~cbbrowne/lsf.html>
Rules of the Evil Overlord #132. "Before appointing someone as my
trusted lieutenant, I will conduct a thorough background investigation
and security clearance. <http://www.eviloverlord.com/>

Christopher Browne

unread,
Jun 23, 2000, 3:00:00 AM6/23/00
to
Centuries ago, Nostradamus foresaw a time when Jochen Schmidt would say:

>The Glauber wrote:
>> ;; count number of lines in file key.html
>> (with-open-file (ifile "key.html" :direction :input)
>> (setf nlines 0)
>> (loop
>> (if (read-line ifile nil)
>> (setf nlines (+ 1 nlines))
>> (return nlines))))
>>
>> It doesn't work (it just hangs, so i think it's stuck in the loop). I
>> thought it would read lines until the end of the file, when the read-
>> line would return nil, and that would trigger the second form inside
>> the if (a return, to get out of the loop).
>>
>> I'm sorry for posting something so stupid, but why doesn't this work?
>
>It works for me in cmucl (warning on the nondefined variable "nlines")
>It works in Allegro Trial Edition 5.0.1 for Linux (without warnings)
>It works in Lispworks Personal Edition 4.1.18 (without warnings)
>But it seems NOT to work with clisp !!! (as the former author noted, it
>blocks)
>
>have not looked further into it, but I found this interesting enough to
>post it.

It indeed sounds like a CLISP bug; the HyperSpec indicates that for:
read-line &optional input-stream eof-error-p eof-value recursive-p

the default value for eof-value is nil, which I'd expect to provide
the desired result.

The code's a bit ugly, but I'd sure expect the call to return "nil"
without much ado...
--
cbbr...@ntlug.org - <http://www.ntlug.org/~cbbrowne/lsf.html>
"Consistency is the single most important aspect of *ideology.*
Reality is not nearly so consistent." - <cbbr...@hex.net>

Steven M. Haflich

unread,
Jun 23, 2000, 3:00:00 AM6/23/00
to

Jochen Schmidt wrote:

> It works for me in cmucl (warning on the nondefined variable "nlines")
> It works in Allegro Trial Edition 5.0.1 for Linux (without warnings)
> It works in Lispworks Personal Edition 4.1.18 (without warnings)

Both Allegro and Lispworks have both interpreter and compiler. I
believe both would signal a warning if the code were compiled, but
choose not to signal warnings in interpreted execution. If they did,
the poor programmer would continually be harrassed by warnings when
executing typical debugging forms at the top-level listener, such as

(setq foo ...)

BTW, in an earlier post Erik wrote:

You're using a free variable, nlines, in this code. You should not
use a free variable unless you have very specific need for it. This
does not affect the correctness of your code, however.

I think this is incorrect. Use of a free, undeclared variable name
is illegal. See ANS 3.1.2.1.1.2 Dynamic Variables. It happens that
every known implementation will treat a free reference to an undeclared
variable as if the variable had been declared special (and typically
warn in the compiler) but I know of nothing in CL semantics that requires
this. Signalling error on reference to an undeclared free variable name
would also conform. (That's what Java does, ;-)

Erik Naggum

unread,
Jun 23, 2000, 3:00:00 AM6/23/00
to
* "Steven M. Haflich" <haf...@pacbell.net>

| BTW, in an earlier post Erik wrote:
|
| You're using a free variable, nlines, in this code. You should not
| use a free variable unless you have very specific need for it. This
| does not affect the correctness of your code, however.
|
| I think this is incorrect. Use of a free, undeclared variable name
| is illegal.

"Free variable" is orthogonal to "undeclared variable". Your gripe
is about "undeclared variables". I talked about "free variable".
Please, some precision when you pick nits.

Steve Long

unread,
Jun 23, 2000, 3:00:00 AM6/23/00
to
What is a "free variable?"

Christopher Browne

unread,
Jun 24, 2000, 3:00:00 AM6/24/00
to
Centuries ago, Nostradamus foresaw a time when Steve Long would say:

>Erik Naggum wrote:
>
>> * "Steven M. Haflich" <haf...@pacbell.net>
>> | BTW, in an earlier post Erik wrote:
>> |
>> | You're using a free variable, nlines, in this code. You should not
>> | use a free variable unless you have very specific need for it. This
>> | does not affect the correctness of your code, however.
>> |
>> | I think this is incorrect. Use of a free, undeclared variable name
>> | is illegal.
>>
>> "Free variable" is orthogonal to "undeclared variable". Your gripe
>> is about "undeclared variables". I talked about "free variable".
>> Please, some precision when you pick nits.
>>
>What is a "free variable?"

One that is malloc()ed and then released under the GNU General Public
License.

[Now ducking quickly, to dodge bullets, boiling oil, and projectile
vomit...]
--
aa...@freenet.carleton.ca - <http://www.hex.net/~cbbrowne/>
I knew you weren't really interested.

Erik Naggum

unread,
Jun 24, 2000, 3:00:00 AM6/24/00
to
* Steve Long <stev...@isomedia.com>

| What is a "free variable?"

One that is not bound by a surrounding (binding) form.

Steven M. Haflich

unread,
Jun 26, 2000, 3:00:00 AM6/26/00
to

Steve Long wrote:
>
> What is a "free variable?"
>
> Erik Naggum wrote:
>
> > * "Steven M. Haflich" <haf...@pacbell.net>
> > | BTW, in an earlier post Erik wrote:
> > |
> > | You're using a free variable, nlines, in this code. You should not
> > | use a free variable unless you have very specific need for it. This
> > | does not affect the correctness of your code, however.
> > |
> > | I think this is incorrect. Use of a free, undeclared variable name
> > | is illegal.
> >
> > "Free variable" is orthogonal to "undeclared variable". Your gripe
> > is about "undeclared variables". I talked about "free variable".
> > Please, some precision when you pick nits.

This is a reply to Erik's comment, not Steve Long's, but Erik's posting
has not yet appeared on my news server.

Indeed, the "free" use of a variable is orthogonal to the "undeclared"
use of a variable, but that does in itself not mean anything. A Usenet
posting may be factually incorrect, and it may be stupid. But it may
be stupid without being incorrect, and it may be incorrect without
being stupid, and it may be both stupid and incorrect. These two
properties are orthogonal. I know this because I have both read and
writen many Usenet postings over the past 17 years.

Similarly, a reference to a variable may be either or both of "undeclared"
and "free". Rather than muck around in the meaning of these terms, I'd
ask Erik the following focussed question:

Assume a freshly-booted ANS-compliant CL implementation. What behavior,
if any, is guaranteed by execution of the following form?

(print (progn (setq pie 22/7) pie))

Now, in every implementation I know, this will print an approximation of
PI, with (if in the interative top level) various prompting and whitespace
handling. It might (especially in compiled code) or might not warn about
the undeclared variable PI. None of this matters to me.

I want to know whether this behavior (modulo toplevel interaction,
prompting, and newlinification) is defined by the ANS. If you claim that
it is, please cite the ANS section references. I claim that the behavior
is either "is an error" or "is undefined".

Do you disagree?

Simon Brooke

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
"Steven M. Haflich" <haf...@pacbell.net> writes:

> Indeed, the "free" use of a variable is orthogonal to the "undeclared"
> use of a variable, but that does in itself not mean anything. A Usenet
> posting may be factually incorrect, and it may be stupid. But it may
> be stupid without being incorrect, and it may be incorrect without
> being stupid, and it may be both stupid and incorrect. These two
> properties are orthogonal. I know this because I have both read and
> writen many Usenet postings over the past 17 years.

Indeed, and anyone who has been using Usenet for that length of time
and claims (s)he hasn't made posts of both kinds is a liar.

> Similarly, a reference to a variable may be either or both of "undeclared"
> and "free". Rather than muck around in the meaning of these terms, I'd
> ask Erik the following focussed question:
>
> Assume a freshly-booted ANS-compliant CL implementation. What behavior,
> if any, is guaranteed by execution of the following form?
>
> (print (progn (setq pie 22/7) pie))

From the point of view of the argument here, aren't both the print
form and the progn forms redundent? Doesn't

* (setq pie 22/7)
==> 22/7
* pie
==> 22/7

illustrate your point just as well?

> I want to know whether this behavior (modulo toplevel interaction,
> prompting, and newlinification) is defined by the ANS. If you claim that
> it is, please cite the ANS section references. I claim that the behavior
> is either "is an error" or "is undefined".
>
> Do you disagree?

OK, I'll play

<URL:http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/sec_3-1-2-1-1.html>

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. There are three kinds of variables: lexical variables,
dynamic variables, and constant variables. A variable can store
one object. The main operations on a variable are to read[1] and
to write[1] its value.

An error of type unbound-variable should be signaled if an unbound
variable is referenced.

SETQ is defined to bind variables to forms. A variable is just any
name in the 'variable' namespace (Yeuch! LISP2! **Nasty**).
<URL:http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/spefor_setq.html#setq>

So, in your example, setq binds the name 'pie' in the current dynamic
environment, by assigning a value to that name in the namespace (all
possible names exist (in a platonic sense) in the namespace, it's just
that the overwhelming majority of them are never instantiated by being
bound). The environment happens to be top-level. The following
evaluation of the name pie retrieves the value from the namespace.

Therefore the behaviour you describe is mandated by the hyperspec. I
don't have the text of the ANSI specification to hand, but have
sufficient trust in the hyperspec editors to believe that if it's
mandated by the one, it's mandated by the other.

--
si...@jasmine.org.uk (Simon Brooke) http://www.jasmine.org.uk/~simon/

There are no messages. The above is just a random stream of
bytes. Any opinion or meaning you find in it is your own creation.

Tim Bradshaw

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
* Simon Brooke wrote:

> SETQ is defined to bind variables to forms. A variable is just any
> name in the 'variable' namespace (Yeuch! LISP2! **Nasty**).
> <URL:http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/spefor_setq.html#setq>

A variable is not a name in the variable namespace, it's a *binding*
in the variable namespace.

--tim

Erik Naggum

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
* "Steven M. Haflich" <haf...@pacbell.net>
| Similarly, a reference to a variable may be either or both of "undeclared"
| and "free". Rather than muck around in the meaning of these terms, I'd
| ask Erik the following focussed question:

I answered it years ago, to your satisfaction if I recall correctly.

However, both the question and the answer have exactly _nothing_ to
do with anything anybody else are or have been discussing. You
brought up "undeclared" in attempt to quibble my "free variable" to
death, and now you bring up "top-level" because it obviously didn't
work to quibble over "undeclared" in the context we were discussing
this. I have better things to do. You should go soak your head.

Erik Naggum

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
* Simon Brooke <si...@jasmine.org.uk>

| SETQ is defined to bind variables to forms.

Wrong.

| A variable is just any name in the 'variable' namespace

Wrong.

| (Yeuch! LISP2! **Nasty**).

Idiot.

| So, in your example, setq binds the name 'pie' in the current dynamic
| environment, by assigning a value to that name in the namespace (all
| possible names exist (in a platonic sense) in the namespace, it's just
| that the overwhelming majority of them are never instantiated by being
| bound). The environment happens to be top-level. The following
| evaluation of the name pie retrieves the value from the namespace.

Bogus from A to Z.

| Therefore the behaviour you describe is mandated by the hyperspec.

Wrong. (If it is, it isn't because of your reasoning.)

A more interesting question than Steven M Haflich's stupid quibbling
is whether (setq foo 1) is identical to (setf (symbol-value 'foo) 1)
if foo is not lexically bound. If it is, then it is completely
beside the point whether foo is "declared" or not.

Steven M. Haflich

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to

Simon Brooke wrote:
>
> "Steven M. Haflich" <haf...@pacbell.net> writes:
> From the point of view of the argument here, aren't both the print
> form and the progn forms redundent? Doesn't
>
> * (setq pie 22/7)
> ==> 22/7
> * pie
> ==> 22/7
>
> illustrate your point just as well?

Yes, but it takes four lines where one would do, and I wanted to be
careful not to expose the issue needlessly to any oddities of top-level
loop behavior. There have been Lisps that do things a little differently
at top level than elsewhere.

> > I want to know whether this behavior (modulo toplevel interaction,
> > prompting, and newlinification) is defined by the ANS. If you claim that
> > it is, please cite the ANS section references. I claim that the behavior
> > is either "is an error" or "is undefined".
> >
> > Do you disagree?
>
> OK, I'll play
>
> <URL:http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/sec_3-1-2-1-1.html>
>
> 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. There are three kinds of variables: lexical variables,
> dynamic variables, and constant variables. A variable can store
> one object. The main operations on a variable are to read[1] and
> to write[1] its value.
>
> An error of type unbound-variable should be signaled if an unbound
> variable is referenced.

Fine so far, but continue on to the specific discussion of dynamic variables:

3.1.2.1.1.2 Dynamic Variables

A variable is a dynamic variable if one of the following conditions hold:

It is locally declared or globally proclaimed special.

It occurs textually within a form that creates a dynamic binding for
a variable of the same name, and the binding is not shadowed[2] by a
form that creates a lexical binding of the same variable name.

And that's _all_ it says. No mention is made about free reference to a
variable that is neither declared nor locally bound.

(I'll decline comment on your futher analysis about setq, etc. It's not
relevant to the central point, and it's too easy to get distracted
quibbling over terminology, about which everyone is sloppy at some time
or other.)

The central question is whether a free reference to an undeclared variable
name is defined by the ANS as a reference to the dynamic variable of that
name, or is it "an error?" I find nothing in the ANS that defines it,
therefore it is unspecified behavior, and for portable code to depend upon
it is in error.

Note that my question is _not_ whether or not the variable exists.
I think we agree that every variable certainly does exist at all times,
and can be tested and referenced with boundp and symbol-value. The
question is whether a free reference to an undeclared variable name is
actually a legal reference to that variable, Platonic or otherwise.
The challenge remains to find a passage in the ANS that defines these
semantics. I know of none.

Simon Brooke

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
Erik Naggum <er...@naggum.no> writes:

> * Simon Brooke <si...@jasmine.org.uk>
> | SETQ is defined to bind variables to forms.
>
> Wrong.

So intelligent! So expostulatory! So elegantly and convincingly put! I
see immediately that I am in error.

> | A variable is just any name in the 'variable' namespace
>
> Wrong.

Such remarkable, percipient analysis! Such dazzling clarity of
exposition! How can I again hold my head up in a company in which I
have been so humiliatingly out-argued?

> | (Yeuch! LISP2! **Nasty**).
>
> Idiot.

I must say, I am overwhelmed by the lucidity of your rhetoric, the
sheer power of your arguments, and the breath of knowledge from which
you marshal the evidence with which you rebut my assertions. Clearly,
sir, you are a master of your profession. Your gracious humility
unmans me; I am abashed at my temerity even to have set foot in your
hallowed newsgroup.

Phil Stubblefield

unread,
Jun 27, 2000, 3:00:00 AM6/27/00
to
This may be the single most impressive display of sarcasm that it
has ever been my privilege to witness! :)

> ...the breath of knowledge from which you marshal the evidence...

And yet you missed scoring a perfect 10.0 by only the "breadth" of
a whisker! :)


Phil Stubblefield
Rockwell Palo Alto Laboratory 206/655-3204
http://www.rpal.rockwell.com/~phil ph...@rpal.rockwell.com

Steven M. Haflich

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
[Sorry if this reply appears twice, but my pestulent ISP's
usenet server seems to have eaten my first relpy. -smh]

3.1.2.1.1.2 Dynamic Variables

==========
Habe nun, ach! Philosophie,
Juristerei und Medizin,
Und leider auch Metacircularitie
Durchaus studiert, mit heisser Bemuehn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor;

- Goethe's Faust

Simon Brooke

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
"Steven M. Haflich" <haf...@pacbell.net> writes:

> Simon Brooke wrote:
> >
> > OK, I'll play
> >
> > <URL:http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/sec_3-1-2-1-1.html>
> >
> > 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. There are three kinds of variables: lexical variables,
> > dynamic variables, and constant variables. A variable can store
> > one object. The main operations on a variable are to read[1] and
> > to write[1] its value.
> >
> > An error of type unbound-variable should be signaled if an unbound
> > variable is referenced.
>
> Fine so far, but continue on to the specific discussion of dynamic variables:
>
> 3.1.2.1.1.2 Dynamic Variables
>
> A variable is a dynamic variable if one of the following conditions hold:
>
> It is locally declared or globally proclaimed special.
>
> It occurs textually within a form that creates a dynamic binding for
> a variable of the same name, and the binding is not shadowed[2] by a
> form that creates a lexical binding of the same variable name.

And that second clause covers the case exactly, does it not?

The name 'pie' occurs textually in the form (setq pie 22/7). The form
creates a dynamic binding (admittedly the binding is in the top level
environment). Consequently pie is a dynamic variable, and the standard
mandates (as I quoted above) that '...the value of that variable is
returned.' Note that the introductory sentence '...if one of...'
clearly indicates that the conditions are disjunctive.

That's all. It's not an error. It's not undefined. It is defined
precisely by the paragraph you indicated.

> And that's _all_ it says. No mention is made about free reference to a
> variable that is neither declared nor locally bound.

But 'local' in this case is top level. Suppose I had a form

Example 1:
(let ((pie 1))
(let ((pie 2))
(setq pie 22/7)
pie))

you would have no difficulty in agreeing that the value of that form
should be 22/7. Suppose I had a form

Example 2:
(let ((pie 1))
(let ((pie 2))
(setq pie 22/7))
pie)

you would have no difficulty in agreeing that the value of that form
should be 1, because the dynamic context in which pie is bound to 22/7
is not the dynamic context from which the value of the form is returned.

Assignment alters the value of the named variable in the dynamic
environment in which that variable exists. For example if we were to
say

Example 3:
(let ((pie 1))
(let ((tart 2))
(setq pie 22/7))
pie)

you would have no difficulty in agreeing that the value of that form
should be 22/7, because the dynamic scope of pie is the outer let
form, not the inner.

In your case, the place of my outer let form is taken by top level,
and your assignment alters the value of the variable in that
environment. What you're objecting to, I think, is that nothing
explicit had been done in your example to make pie a variable in the
top level environment.

But as I said earlier in this thread (in which I was, apparently,
'Wrong', because I am, apparently, an 'Idiot'), it doesn't need to
be. Any arbitrary name is a member of a namespace whether anyone has
ever uttered it or not, provided it meets the lexical constraints of
that namespace, just as any arbitrary positive integer is a member of
the set of natural numbers. We don't have to preinitialise LISP with
the number 658965439875478453 before we can use that number in a
computation, and similarly we don't need to preinitialise it with the
name 'pie' before 'pie' is a name.



> Note that my question is _not_ whether or not the variable exists.
> I think we agree that every variable certainly does exist at all times,
> and can be tested and referenced with boundp and symbol-value. The
> question is whether a free reference to an undeclared variable name is
> actually a legal reference to that variable, Platonic or otherwise.
> The challenge remains to find a passage in the ANS that defines these
> semantics. I know of none.

But you quoted it!

Paul Foley

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
On Wed, 28 Jun 2000 09:33:15 GMT, Simon Brooke wrote:

>> 3.1.2.1.1.2 Dynamic Variables
>>
>> A variable is a dynamic variable if one of the following conditions hold:
>>
>> It is locally declared or globally proclaimed special.
>>
>> It occurs textually within a form that creates a dynamic binding for
>> a variable of the same name, and the binding is not shadowed[2] by a
>> form that creates a lexical binding of the same variable name.

> And that second clause covers the case exactly, does it not?

No, it doesn't.

> The name 'pie' occurs textually in the form (setq pie 22/7). The form
> creates a dynamic binding (admittedly the binding is in the top level

As Erik told you quite clearly, "Wrong".

If you need clarification: SETQ does not _create_ a binding. It
_modifies_ an _existing_ binding.

> In your case, the place of my outer let form is taken by top level,
> and your assignment alters the value of the variable in that
> environment. What you're objecting to, I think, is that nothing

Unless the top level repl takes place inside a lexical environment in
which PIE is already bound (which it doesn't), this is not at all the
same thing. There's no binding in existence, and SETQ doesn't
establish one.

> But as I said earlier in this thread (in which I was, apparently,
> 'Wrong', because I am, apparently, an 'Idiot'), it doesn't need to

No; Erik said you were wrong because you were wrong. He also called
you an idiot; but there's no cause-and-effect there (at least not in
the direction Idiot->Wrong)


--
Nomina stultorum in parietibus et portis semper videmus. -- Cicero

(setq reply-to
(concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz>"))

Tim Bradshaw

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Simon Brooke wrote:

> And that second clause covers the case exactly, does it not?

> The name 'pie' occurs textually in the form (setq pie 22/7). The form
> creates a dynamic binding (admittedly the binding is in the top level
> environment). Consequently pie is a dynamic variable, and the standard
> mandates (as I quoted above) that '...the value of that variable is
> returned.' Note that the introductory sentence '...if one of...'
> clearly indicates that the conditions are disjunctive.

I don't think it's safe to assume that SETQ creates a binding in an
argument where you are trying to prove that that is what it does.

--tim

Simon Brooke

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
Tim Bradshaw <t...@cley.com> writes:

> * Simon Brooke wrote:
>
> > And that second clause covers the case exactly, does it not?
>
> > The name 'pie' occurs textually in the form (setq pie 22/7). The form
> > creates a dynamic binding (admittedly the binding is in the top level
> > environment). Consequently pie is a dynamic variable, and the standard
> > mandates (as I quoted above) that '...the value of that variable is
> > returned.' Note that the introductory sentence '...if one of...'
> > clearly indicates that the conditions are disjunctive.
>

> I don't think it's safe to assume that SETQ creates a binding in an
> argument where you are trying to prove that that is what it does.

The action of setq is described in
<URL:http://www.xanalys.com/software_tools/reference/HyperSpec/Body/spefor_setq.html#setq>,
which I had already refered to earlier in the discussion.

to err is human, to lisp divine
;; attributed to Kim Philby, oddly enough.

Erik Naggum

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Simon Brooke <si...@jasmine.org.uk>
| [ British humor elided ]

Thank you for that amazing display of typically British evasive
action, but I'm sorry to say that you're still wrong on every
technical count.

Erik Naggum

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Simon Brooke <si...@jasmine.org.uk>
| ... (in which I was, apparently, 'Wrong', because I am, apparently,
| an 'Idiot') ...

Excuse me, but where did you get the "because"? I'm now inclined to
believe that you _are_ an idiot by the way you respond, but such was
not evident at the time I replied to you. You are, however, doing
an _admirable_ job of supplying me with information to that effect.
Wny do you do that?

Tim Bradshaw

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Simon Brooke wrote:

> The action of setq is described in
> <URL:http://www.xanalys.com/software_tools/reference/HyperSpec/Body/spefor_setq.html#setq>,
> which I had already refered to earlier in the discussion.

Quite. And it doesn't say there that it creates a binding, does it?

--tim

Erik Naggum

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Tim Bradshaw -> Simon Brooke

| Quite. And it doesn't say there that it creates a binding, does it?

Forget it, Tim. He's been told he was wrong in a way he just could
not handle and now he has to salvage his pride by insisting on being
wrong for several services, possibly months. Give up and leave him
alone to recover.

Simon Brooke

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
Paul Foley <myc...@actrix.gen.nz> writes:

> On Wed, 28 Jun 2000 09:33:15 GMT, Simon Brooke wrote:
>

> >> 3.1.2.1.1.2 Dynamic Variables
> >>
> >> A variable is a dynamic variable if one of the following conditions hold:
> >>
> >> It is locally declared or globally proclaimed special.
> >>
> >> It occurs textually within a form that creates a dynamic binding for
> >> a variable of the same name, and the binding is not shadowed[2] by a
> >> form that creates a lexical binding of the same variable name.
>
> > And that second clause covers the case exactly, does it not?
>

> No, it doesn't.


>
> > The name 'pie' occurs textually in the form (setq pie 22/7). The form
> > creates a dynamic binding (admittedly the binding is in the top level
>

> As Erik told you quite clearly, "Wrong".

And that, frankly, is silly. If you believe I'm wrong, then you can
say why you believe I'm wrong. I have cited authority (namely the
hyperspec) in support of my proposition. To refute my argument, you
would either have to produce a more authoritative authority, or
demonstrate that my understanding of a very clear statement is flawed.

Which is it?

> If you need clarification: SETQ does not _create_ a binding. It
> _modifies_ an _existing_ binding.

That is a bald assertion. Undoubtedly you believe it. It isn't what
the Aluminium Book says, and it isn't what the Hyperspec
says. Furthermore, its falsehood is demonstrable by simple reference
to any working Common LISP system:

USER(1): (boundp 'foo)
NIL
USER(2): (setq foo 123)
123
USER(3): (boundp 'foo)
T

Prior to evaluating the form (setq foo 123), foo was not
bound. Subsequently, it was bound. A binding was created where no
binding existed before. What created it? The only thing which happened
was that the form (setq foo 123) was evaluated. Therefore, prima
facie, there is evidence that evaluating the form created the
binding. The hyperspec said it would; empiricism says it does.

Doubtless you have evidence to support your contrary belief, but you
haven't conveyed it. On Usenet, as elsewhere in the world, reasonable
argument is far more effective in changing minds than rudeness and
unsupported contradiction.

I'm quite prepared to believe I'm wrong, because I am, as I've said
earlier, somewhat rusty. However, neither you nor Erik have produced
any argument or evidence to support your (admittedly God-like)
utterances, and frankly I'm unimpressed.

Getout clause: The argument I'm assuming that both you and Erik are
failing to make is that you believe (setq foo 123) at top level should
create a lexical, not a dynamic binding. I think the point is moot
because I'm not sure what semantic difference the difference between
lexical and dynamic makes *at top level*; however, the behaviour I
have described is explicitly spelled out in the Hyperspec entry on
boundp. If the 'lexical' argument is that argument you're advancing,
then in theory you may be right, but I think that is debatable. In
practice, in all the real world implementations I have access to, you
are wrong.

to err is human, to lisp divine

Erik Naggum

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Tim Bradshaw -> Simon Brooke
| Quite. And it doesn't say there that it creates a binding, does it?

Forget it, Tim. He's been told he was wrong in a way he just could
not handle and now he has to salvage his pride by insisting on being

wrong for several weeks, possibly months. Give up and leave him

Thomas A. Russ

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
Simon Brooke <si...@jasmine.org.uk> writes:

> Paul Foley <myc...@actrix.gen.nz> writes:
>
> > On Wed, 28 Jun 2000 09:33:15 GMT, Simon Brooke wrote:
> >

> > >> 3.1.2.1.1.2 Dynamic Variables
> > >>
> > >> A variable is a dynamic variable if one of the following conditions hold:
> > >>
> > >> It is locally declared or globally proclaimed special.
> > >>
> > >> It occurs textually within a form that creates a dynamic binding for
> > >> a variable of the same name, and the binding is not shadowed[2] by a
> > >> form that creates a lexical binding of the same variable name.
> >
> > > And that second clause covers the case exactly, does it not?
> >

> > No, it doesn't.


> >
> > > The name 'pie' occurs textually in the form (setq pie 22/7). The form
> > > creates a dynamic binding (admittedly the binding is in the top level

Why do you think a dynamic binding is created?

> > As Erik told you quite clearly, "Wrong".
>
> And that, frankly, is silly. If you believe I'm wrong, then you can
> say why you believe I'm wrong. I have cited authority (namely the
> hyperspec) in support of my proposition. To refute my argument, you
> would either have to produce a more authoritative authority, or
> demonstrate that my understanding of a very clear statement is flawed.

You understanding of a very clear statement if flawed.

The key item of text that contributes to your misunderstanding is
"within a form that CREATES A DYNAMIC BINDING for a variable." The Lisp
toplevel does not create a dynamic binding. One example of a form that
creates dynamic bindings is PROGV, so if you had the variable textually
inside a PROGV that binds that variable (but not inside a shadowing let,
or multiple-value bind, etc.) you would have a dynamic binding.

You could also establish a dynamic binding with something like LET or
MULTIPLE-VALUE-BIND with the SPECIAL declaration, but that might be
considered covered under the first rather than the second paragraph.

The fact that most lisp systems will, by grace of the implementors,
treat undefined variables as special is convenient, but not mandated by
the Spec.

--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

Erik Naggum

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
* Simon Brooke <si...@jasmine.org.uk>

| > If you need clarification: SETQ does not _create_ a binding. It
| > _modifies_ an _existing_ binding.
|
| That is a bald assertion. Undoubtedly you believe it.

Well, as a good Lisp programmer should. It happens to be true. You
are still wrong on every technical count you have raised. That's
pretty good work, actually, since by chance you'd be right at least
_some_ of the time.

| It isn't what the Aluminium Book says, and it isn't what the
| Hyperspec says.

Earlier, you were just wrong. This, now, is a _lot_ worse.

| Furthermore, its falsehood is demonstrable by simple reference to
| any working Common LISP system:
|
| USER(1): (boundp 'foo)
| NIL
| USER(2): (setq foo 123)
| 123
| USER(3): (boundp 'foo)
| T

And (let ((foo 1)) (boundp 'foo)) produces _what_ before and after
that setq form? Did you look at the description of boundp?

Are you sure you are gaining anything by demonstrating what you are
_in fact_ demonstrating, given that it differs somewhat from what
you think you are demonstrating, to put it very mildly?

Simon Brooke

unread,
Jun 28, 2000, 3:00:00 AM6/28/00
to
t...@sevak.isi.edu (Thomas A. Russ) writes:

> Simon Brooke <si...@jasmine.org.uk> writes:
>
> > Paul Foley <myc...@actrix.gen.nz> writes:
> >
> > > On Wed, 28 Jun 2000 09:33:15 GMT, Simon Brooke wrote:
> > >

> > > >> It occurs textually within a form that creates a dynamic binding for
> > > >> a variable of the same name, and the binding is not shadowed[2] by a
> > > >> form that creates a lexical binding of the same variable name.
> > >
> > > > And that second clause covers the case exactly, does it not?
> > >

> > > No, it doesn't.


> > >
> > > > The name 'pie' occurs textually in the form (setq pie 22/7). The form
> > > > creates a dynamic binding (admittedly the binding is in the top level
>

> Why do you think a dynamic binding is created?

OK, good. Well, I think so because if I evaluate (I've mentioned this
earlier in the thread, apologies for the repetition)

USER(1): (boundp 'foo)
NIL
USER(2): (setq foo 'bar)
BAR
USER(3): (boundp 'foo)
T

The symbol foo, which wasn't bound before the assignment, is
after. This behaviour is consistent across Allegro, GCL and
CMUCL. CLtL says, I quote:

'boundp is true if the dynamic (special) variable named by symbol
has a value; otherwise, it returns nil.'

That's quite explicit. My empirical experience with implementations
supported my reading of the documents. Although, to be honest, I had
noted that CMUCL under those circumstances gives

* (setq foo 'bar)
Warning: Declaring FOO special.

BAR

which suggested to me that I hadn't got it straight...

> You understanding of a very clear statement if flawed.
>
> The key item of text that contributes to your misunderstanding is
> "within a form that CREATES A DYNAMIC BINDING for a variable." The Lisp
> toplevel does not create a dynamic binding. One example of a form that
> creates dynamic bindings is PROGV, so if you had the variable textually
> inside a PROGV that binds that variable (but not inside a shadowing let,
> or multiple-value bind, etc.) you would have a dynamic binding.

So what you're saying is that what the standard mandates would be:

(setq foo 'bar) ==> bar ;; establishes a lexical binding?
;; ?? or should be simply illegal?
(boundp 'foo) ==> nil

(let ((foo 'ban)) ;; establishes a dynamic binding
(boundp 'foo)) ==> t

(boundp 'foo) ==> nil

foo ==> bar ;; ?? is this right?

It's the last move that bothers me. The dynamic scope of top-level
makes a certain amount of sense -- it would be that dynamic scope which
exists at the bottom of the stack. I can't see how a top-level variable
has lexical scope. Again to quote ClTL:

'Lexical Scope: Here references to the established entity can only
occur within certain program portions that are lexically (that is,
textually) contained within an establishing construct... Example:
the names of parameters to a function are normally lexically
scoped' [my ellision]

So, for the sake of my confusion, is a variable assigned to in a
top-level assignment lexically bound, dynamically bound, not bound at
all, or an error?

Incidentally, thank you very kindly for giving me a response which
makes some kind of *sense*!

Morning had broken, and there was nothing left for us to do
but pick up the pieces.

Tim Moore

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
On Wed, 28 Jun 2000, Simon Brooke wrote:
> The symbol foo, which wasn't bound before the assignment, is
> after. This behaviour is consistent across Allegro, GCL and
> CMUCL. CLtL says, I quote:
>
> 'boundp is true if the dynamic (special) variable named by symbol
> has a value; otherwise, it returns nil.'
>
> That's quite explicit. My empirical experience with implementations
> supported my reading of the documents. Although, to be honest, I had
> noted that CMUCL under those circumstances gives
>
> * (setq foo 'bar)
> Warning: Declaring FOO special.
>
> BAR
>
> which suggested to me that I hadn't got it straight...

Part of the confusion (hopefully I'm not adding to it) is that "binding"
doesn't necessarily mean what you (all) think. The glossary says "binding
n. an association between a name and that which the name denotes."
Variables at top-level, whether or not they have been proclaimed dynamic
somehow, are bound if they have been assigned a value and have not been
made unbound. This "binding" has nothing to do with environments,
contours, scope, dynamic environments or whatever. Furthermore, boundp
only works for symbols in the global environment, and all it decides is
whether or not such a variable has been assigned a value.

So, to be clear as mud, setq makes a variable bound but it does not
"establish a binding."

> > "within a form that CREATES A DYNAMIC BINDING for a variable." The Lisp
> > toplevel does not create a dynamic binding. One example of a form that
> > creates dynamic bindings is PROGV, so if you had the variable textually
> > inside a PROGV that binds that variable (but not inside a shadowing let,
> > or multiple-value bind, etc.) you would have a dynamic binding.
>
> So what you're saying is that what the standard mandates would be:
>
> (setq foo 'bar) ==> bar ;; establishes a lexical binding?

No, the standard doesn't say. Some implementations like CMUCL proclaim it
special for you, so in a sense it that "establishes a binding". Strictly
speaking, setq could barf on this as foo is not a lexical variable, and
neither is it dynamic.

> ;; ?? or should be simply illegal?
> (boundp 'foo) ==> nil

Absolutely not. foo has been assigned a value, so (boundp 'foo) => t.

> (let ((foo 'ban)) ;; establishes a dynamic binding
> (boundp 'foo)) ==> t

(boundp 'foo) returns t, but it's in spite of the let. The let might or
might not establish a dynamic binding.

>
> (boundp 'foo) ==> nil

Nope.

>
> foo ==> bar ;; ?? is this right?

Yeah... this is expected if the setq "did the right thing."

> It's the last move that bothers me. The dynamic scope of top-level
> makes a certain amount of sense -- it would be that dynamic scope which
> exists at the bottom of the stack. I can't see how a top-level variable
> has lexical scope. Again to quote ClTL:

It doesn't really.

> So, for the sake of my confusion, is a variable assigned to in a
> top-level assignment lexically bound, dynamically bound, not bound at
> all, or an error?

Nope :) It's bound.

Here's another nipple-twister (*honig* has not been defvar'ed or assigned
to):

(let ((*honig* 2112))
(declare (special *honig*))
(values (boundp '*honig) (symbol-value '*honig*))) =>
NIL
2112

So, even though dynamic binding might not actually touch a symbol's slots
(think deep binding), the symbol-value accessor has to behave as if it
does.

A lot of what you're seeing is the historical convenience of using symbols
and their slots for program storage.

Tim
"A moment of convenience, a lifetime of regret"


Paul Foley

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
On Wed, 28 Jun 2000 22:33:16 GMT, Simon Brooke wrote:

> So what you're saying is that what the standard mandates would be:

No. The standard doesn't say _anything at all_ about this situation.

> (setq foo 'bar) ==> bar ;; establishes a lexical binding?

No. Again, SETQ doesn't establish _any_ kind of binding.

> (let ((foo 'ban)) ;; establishes a dynamic binding
> (boundp 'foo)) ==> t

Have you tried this? Did you mean to put a (DECLARE (SPECIAL FOO)) in
there? Or have you done (PROCLAIM '(SPECIAL FOO)) or (DEFVAR FOO) or
equivalent? If you're using CMUCL, that happens automatically when
you use SETQ at top level (i.e., top level SETQ is equivalent to
DEFPARAMETER; this will bite you if you're not careful). On the other
hand, if you're doing this in the same Lisp as the previous top level
SETQ, the result has nothing to do with this LET.

> (boundp 'foo) ==> nil

> foo ==> bar ;; ?? is this right?

No.

Paul Foley

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
On 29 Jun 2000 00:57:20 GMT, Tim Moore wrote:

> Here's another nipple-twister (*honig* has not been defvar'ed or assigned
> to):

> (let ((*honig* 2112))
> (declare (special *honig*))
> (values (boundp '*honig) (symbol-value '*honig*))) =>
> NIL
> 2112

I don't think so.

Simon Brooke

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
Tim Moore <mo...@herschel.bricoworks.com> writes:

> Part of the confusion (hopefully I'm not adding to it) is that "binding"
> doesn't necessarily mean what you (all) think. The glossary says "binding
> n. an association between a name and that which the name denotes."

I'm with you so far...

> Variables at top-level, whether or not they have been proclaimed dynamic
> somehow, are bound if they have been assigned a value and have not been
> made unbound. This "binding" has nothing to do with environments,
> contours, scope, dynamic environments or whatever. Furthermore, boundp
> only works for symbols in the global environment, and all it decides is
> whether or not such a variable has been assigned a value.
>
> So, to be clear as mud, setq makes a variable bound but it does not
> "establish a binding."

Now I am comletely at sea in semantic soup. What you are saying is
that foo is bound with a non-existent binding? Surely, in logic,
either it is unbound or there exists some binding which binds it?

> > (setq foo 'bar) ==> bar ;; establishes a lexical binding?
>

> No, the standard doesn't say. Some implementations like CMUCL proclaim it
> special for you, so in a sense it that "establishes a binding". Strictly
> speaking, setq could barf on this as foo is not a lexical variable, and
> neither is it dynamic.

So what you are saying is that strictly speaking, as the standard is
written, assignment at top level is (at best) undefined,
implementation dependent behaviour?

> > ;; ?? or should be simply illegal?
> > (boundp 'foo) ==> nil
>
> Absolutely not. foo has been assigned a value, so (boundp 'foo) => t.

Well, so I should (naiively) think. But ClTL explicitly says that
boundp only yields 't for a dynamic binding. The HyperSpec says only
that boundp 'Returns true if symbol is bound; otherwise, returns
false' but goes on to define bound: 'bound adj., v.t. 1. adj. having an
associated denotation in a binding.'

So, as I understand it,
either
(i) a symbol bound at top level must have a dynamic binding, or at
least
(ia) assignment at top level must establish some binding, or

(ii) boundp should yield false from a top-level assigned symbol, or

(iii) the documentation is internally inconsistent.

And before anyone gets excited again, I'm not claiming this is the
truth, I'm merely setting out my understanding as clearly as I can so
that those of you who know better can explain where I'm wrong.

> > (let ((foo 'ban)) ;; establishes a dynamic binding
> > (boundp 'foo)) ==> t
>

> (boundp 'foo) returns t, but it's in spite of the let. The let might or
> might not establish a dynamic binding.

So what you're saying is that if I enter the following as the first
form after starting an idealised perfect Common LISP implementation:

(let ((foo 'bar))
(boundp 'foo))

it would return nil?

I think at this point I need to step back and establish what I'm
arguing about here.

In LISP (as I understand, it, speaking generically about LISP and not
about any standard in particular) there is a top level namespace
(which in general is implemented as a hashtable, but which could be an
alist or any other conceivable representation, and this is slightly
more complicated because of plists and in LISPs having multiple
namespaces). For the sake of clarity I'll refer to this association as
the oblist, without making any assumptions about the detailed
implementation.

When the top-level value of a variable is assigned, a new association
is created in the toplevel namespace which associates a name with a
pointer; logically equivalent to

(lambda (name value)
(setq *oblist*
(cons '(name . value)
(remove (assoc name *oblist*) *oblist*))))

Then, when we evaluate a form, a frame is pushed onto the stack which,
among other things, contains a data structure representing either

(i) the values of the symbols bound in that frame (aka deep
binding); or
(ii) the values which the symbols bound in that frame had
in the global environment prior to the creation of the frame
(aka shallow binding, and how this works in multi-threaded
LISPs I don't even pretend to understand).

Am I right in believing that the bindings in (i) and (ii) above are
called 'dynamic bindings', and that these bindings are visible to
anything subsequently pushed onto the stack (unless shadowed)?

As a completely separate mechanism, a block of code may contain an
association between symbols defined in that block of code and
permanent storage locations associated with them which are independent
of the oblist; permanent and local to the block of code. Am I right in
saying that these bindings are called 'lexical' bindings, and that their
values are only visible in the block of code in which they are
defined, and are not visible to anything subsequently pushed onto the
stack?

When there is a conflict between a potentially visible binding in the
dynamic namespace and a potentially visible binding in the lexical
namespace, am I right (HyperSpec 3.1.2.1.1.4) in believing that Common
LISP prefers the lexical to the dynamic?

OK, and if I'm right so far, then there is no lexical environment at
top level (is there? If so, what is it?).

Maybe, as Erik thinks, I'm on an ego-trip here trying to prove more
experienced people wrong. And maybe I *am* an idiot. But I really
don't get this.

There are, as I understand it, two fundamental kinds of variables in
Common LISP: those that are bound in stack-frames, and those that are
bound in code-blocks. The variables bound in the oblist are logically
part of the mechanism which accesses variables in stack frames,
whether the binding scheme we're considering is deep or shallow. It
doesn't seem to me clear that there is any obvious relationship
between binding in code-blocks and binding on the oblist.

So, circularly back to where we started, and I apologise for going
round again but I still haven't got an answer which I understand:

If, at top level, in a fresh invocation of LISP, we evaluate

(setq foo 'bar)

then either the assignment causes a change to the oblist, or no
assignment is effected. Am I right so far?

My understanding, expressed above, is that

(lemma i) there are two kinds of variables, those bound in code-blocks
which are called 'lexical', and those bound on the stack which are
called 'dynamic', and that
(lemma ii) no code block exists which the top-level environment is in
scope of.

By excluded middle, if (lemma i) holds, then any binding which is not
lexical is dynamic;
If (lemma ii) holds, any binding at top level is not lexical.

Which brings me right back to my original conclusion, which is that
assignment at top level either establishes a dynamic binding, or
establishes no binding, or is an error.

But If it establishes no binding, then boundp, which returns t if and
only if there is a binding, should return nil. Furthermore, if there
is no binding, then to quote the hyperspec [3.1.2.1.1]: 'An error of


type unbound-variable should be signaled if an unbound variable is

referenced.'

Morning had broken, and there was nothing left for us to do

Erik Naggum

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
* Tim Moore <mo...@herschel.bricoworks.com>

| Here's another nipple-twister (*honig* has not been defvar'ed or
| assigned to):
|
| (let ((*honig* 2112))
| (declare (special *honig*))
| (values (boundp '*honig) (symbol-value '*honig*))) =>
| NIL
| 2112
|
| So, even though dynamic binding might not actually touch a symbol's
| slots (think deep binding), the symbol-value accessor has to behave
| as if it does.

You will get different results if you spell *honig* consistently.

Steven M. Haflich

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to

Paul Foley wrote:
>
> On 29 Jun 2000 00:57:20 GMT, Tim Moore wrote:
>
> > Here's another nipple-twister (*honig* has not been defvar'ed or assigned
> > to):
>
> > (let ((*honig* 2112))
> > (declare (special *honig*))
> > (values (boundp '*honig) (symbol-value '*honig*))) =>
^
Be more careful about spelling, Tim.

> > NIL
> > 2112
>
> I don't think so.

Be more careful about reading, Paul.

Thomas A. Russ

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
Tim Moore <mo...@herschel.bricoworks.com> writes:

> Here's another nipple-twister (*honig* has not been defvar'ed or assigned
> to):
>
> (let ((*honig* 2112))
> (declare (special *honig*))
> (values (boundp '*honig) (symbol-value '*honig*))) =>

> NIL
> 2112

Um, did you really intend to use a different symbol in BOUNDP than in
SYMBOL-VALUE? The first one does not have the trailing * as part of the
symbol name. If you use the same names, boundp returns T (in ACL):

USER> (let ((*honig* 2112))
(declare (special *honig*))
(values (boundp '*honig*) (symbol-value '*honig*)))
T
2112

Tim Moore

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
On Thu, 29 Jun 2000, Steven M. Haflich wrote:

>
> Paul Foley wrote:
> >
> > On 29 Jun 2000 00:57:20 GMT, Tim Moore wrote:
> >

> > > Here's another nipple-twister (*honig* has not been defvar'ed or assigned
> > > to):
> >
> > > (let ((*honig* 2112))
> > > (declare (special *honig*))
> > > (values (boundp '*honig) (symbol-value '*honig*))) =>

> ^
> Be more careful about spelling, Tim.

I am a butthead. I think's that 1067th time I've made that particular
typo...

Tim

Tim Moore

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
On Thu, 29 Jun 2000, Simon Brooke wrote:
> Tim Moore <mo...@herschel.bricoworks.com> writes:

> > So, to be clear as mud, setq makes a variable bound but it does not
> > "establish a binding."
>
> Now I am comletely at sea in semantic soup. What you are saying is
> that foo is bound with a non-existent binding? Surely, in logic,
> either it is unbound or there exists some binding which binds it?

Not if "bound" is an overloaded word :)

> > > (setq foo 'bar) ==> bar ;; establishes a lexical binding?
> >
> > No, the standard doesn't say. Some implementations like CMUCL proclaim it
> > special for you, so in a sense it that "establishes a binding". Strictly
> > speaking, setq could barf on this as foo is not a lexical variable, and
> > neither is it dynamic.
>
> So what you are saying is that strictly speaking, as the standard is
> written, assignment at top level is (at best) undefined,
> implementation dependent behaviour?

If the variable has not been proclaimed special, yes. Personally I'm
happy to think about this as (setf (symbol-value 'foo) 'bar) and let
the chips fall where they may, but that's a bias for a particular
implementation.

> > > ;; ?? or should be simply illegal?
> > > (boundp 'foo) ==> nil
> >
> > Absolutely not. foo has been assigned a value, so (boundp 'foo) => t.
>
> Well, so I should (naiively) think. But ClTL explicitly says that
> boundp only yields 't for a dynamic binding. The HyperSpec says only
> that boundp 'Returns true if symbol is bound; otherwise, returns
> false' but goes on to define bound: 'bound adj., v.t. 1. adj. having an
> associated denotation in a binding.'

But a binding is defined as "an association between a name and that which
the name denotes." foo now denotes something, no?

> So, as I understand it,
> either

> (iii) the documentation is internally inconsistent.

Or at least, confusing.

> So what you're saying is that if I enter the following as the first
> form after starting an idealised perfect Common LISP implementation:
>
> (let ((foo 'bar))
> (boundp 'foo))
>
> it would return nil?

Exactly. In fact, CMUCL emits a warning that foo is unused. That's a
clue that the foo in the let form is a lexical binding.

[Description of global symbol data structure elided...]

> Then, when we evaluate a form, a frame is pushed onto the stack which,
> among other things, contains a data structure representing either
>
> (i) the values of the symbols bound in that frame (aka deep
> binding); or
> (ii) the values which the symbols bound in that frame had
> in the global environment prior to the creation of the frame
> (aka shallow binding, and how this works in multi-threaded
> LISPs I don't even pretend to understand).

It might be possible to implement dynamic binding in Common Lisp in the
way you describe, but it's a lot easier to reason about what the Spec
means if you think about a very simple shallow binding implementation with
these features:

* A symbol is a data structure with, among other things, a value slot;
* When a symbol comes into being via intern, its value slot is initialized
to 'magic-unbound-value;
* symbol-value and (setf symbol-value) are accessors of the value slot.
symbol-value signals an error if (eq value-slot 'magic-unbound-value)
* All references to a variable that has no lexical binding are to the
symbol associated with the variable name and its value slot.
* Dynamic binding is the shallow mechanism you describe: the old value is
saved away and the new value is stored in the value slot.

In this scheme, the implementation of boundp is trivial:
(defun boundp (variable)
(eq (symbol-value-slot variable) 'magic-unbound-value))

Whether or not a variable is proclaimed special is an issue for the
evaluator/compiler in how it evaluates bindings and references.

The spec is consistent with this simple model. At one time it was the
state of the art in Lisp implementation. You're right that it doesn't
work well in the presence of threading, but its performance advantages
over deep binding (especially in Lisps where every variable is dynamic)
can not be gainsaid.

However, the spec certainly doesn't mandate this implementation.

> When there is a conflict between a potentially visible binding in the
> dynamic namespace and a potentially visible binding in the lexical
> namespace, am I right (HyperSpec 3.1.2.1.1.4) in believing that Common
> LISP prefers the lexical to the dynamic?

I don't read that at all in 3.1.2.1.1.4. What it says is that there can
be no conflict. "The same symbol can name both a lexical variable and a
dynamic variable, but never in the same lexical environment." I.e., you
can't create a situation where a variable name could refer to both.

The example in that section confused me for a second:

(let ((x 1)) ;Binds a special variable X
(declare (special x))
(let ((x 2)) ;Binds a lexical variable X
(+ x ;Reads a lexical variable X
(locally (declare (special x))
x)))) ;Reads a special variable X

At first reading I thought the inner binding of x was special too, but
special declarations do *NOT* affect inner bindings of the same variable.
In contrast, special proclaimations affect all bindings.

> OK, and if I'm right so far, then there is no lexical environment at
> top level (is there? If so, what is it?).

That's right.

> There are, as I understand it, two fundamental kinds of variables in
> Common LISP: those that are bound in stack-frames, and those that are
> bound in code-blocks. The variables bound in the oblist are logically
> part of the mechanism which accesses variables in stack frames,
> whether the binding scheme we're considering is deep or shallow. It
> doesn't seem to me clear that there is any obvious relationship
> between binding in code-blocks and binding on the oblist.

I find your code-block terminology a little confusing, but I think you're
on the right track here. There is no relationship between variables in
"code-blocks" (really lexical environments) and variables that live
in symbol value slots, whether special or not. If a variable has not been
lexically bound and isn't special either, it is undefined. That situation
is not handled by the spec. At least implmentation, CMUCL, warns you
about this and then uses the symbol value slot.

>
> So, circularly back to where we started, and I apologise for going
> round again but I still haven't got an answer which I understand:
>
> If, at top level, in a fresh invocation of LISP, we evaluate
>
> (setq foo 'bar)
>
> then either the assignment causes a change to the oblist, or no
> assignment is effected. Am I right so far?

Yeah, it either does or it doesn't :) However, just because a change is
made to the "oblist" doesn't mean anything in particular to the variable's
specialness.

> My understanding, expressed above, is that
>
> (lemma i) there are two kinds of variables, those bound in code-blocks
> which are called 'lexical', and those bound on the stack which are
> called 'dynamic', and that

I'll go out on a limb and assert that nowhere does the spec say "It is an
error for a variable to be neither lexical nor special."

> (lemma ii) no code block exists which the top-level environment is in
> scope of.
>

Alternatively, the top-level environment is not a lexical environment?

> By excluded middle, if (lemma i) holds, then any binding which is not
> lexical is dynamic;
> If (lemma ii) holds, any binding at top level is not lexical.

If lemma i does not hold, the behavior is undefined. I do not believe the
spec requires lemma i to hold in a conforming implementation.

> Which brings me right back to my original conclusion, which is that
> assignment at top level either establishes a dynamic binding, or
> establishes no binding, or is an error.

You've got all the bases covered, except for "makes a non-special variable
bound".

> But If it establishes no binding, then boundp, which returns t if and
> only if there is a binding, should return nil. Furthermore, if there

Nope! Think about the simple shallow binding model I described above.

> is no binding, then to quote the hyperspec [3.1.2.1.1]: 'An error of
> type unbound-variable should be signaled if an unbound variable is
> referenced.'

The moral of the story is: proclaim top-level variables special one way or
another.

Tim

Thomas A. Russ

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
Simon Brooke <si...@jasmine.org.uk> writes:

> Paul Foley <myc...@actrix.gen.nz> writes:
>
> > On Wed, 28 Jun 2000 09:33:15 GMT, Simon Brooke wrote:
> >

> > >> 3.1.2.1.1.2 Dynamic Variables
> > >>
> > >> A variable is a dynamic variable if one of the following conditions hold:
> > >>
> > >> It is locally declared or globally proclaimed special.
> > >>
> > >> It occurs textually within a form that creates a dynamic binding for
> > >> a variable of the same name, and the binding is not shadowed[2] by a
> > >> form that creates a lexical binding of the same variable name.
> >
> > > And that second clause covers the case exactly, does it not?
> >

> > No, it doesn't.


> >
> > > The name 'pie' occurs textually in the form (setq pie 22/7). The form
> > > creates a dynamic binding (admittedly the binding is in the top level

Why do you think a dynamic binding is created?

> > As Erik told you quite clearly, "Wrong".


>
> And that, frankly, is silly. If you believe I'm wrong, then you can
> say why you believe I'm wrong. I have cited authority (namely the
> hyperspec) in support of my proposition. To refute my argument, you
> would either have to produce a more authoritative authority, or

> demonstrate that my understanding of a very clear statement is flawed.

You understanding of a very clear statement if flawed.

The key item of text that contributes to your misunderstanding is

"within a form that CREATES A DYNAMIC BINDING for a variable." The Lisp
toplevel does not create a dynamic binding. One example of a form that
creates dynamic bindings is PROGV, so if you had the variable textually
inside a PROGV that binds that variable (but not inside a shadowing let,
or multiple-value bind, etc.) you would have a dynamic binding.

You could also establish a dynamic binding with something like LET or


MULTIPLE-VALUE-BIND with the SPECIAL declaration, but that might be
considered covered under the first rather than the second paragraph.

The fact that most lisp systems will, by grace of the implementors,
treat undefined variables as special is convenient, but not mandated by
the Spec.

--

Thomas A. Russ

unread,
Jun 29, 2000, 3:00:00 AM6/29/00
to
Simon Brooke <si...@jasmine.org.uk> writes:

> > Why do you think a [top level] dynamic binding is created?


>
> OK, good. Well, I think so because if I evaluate (I've mentioned this
> earlier in the thread, apologies for the repetition)

But that doesn't address the issue of what the standard mandates. It
just demonstrates what a particular implementation does.

> USER(1): (boundp 'foo)
> NIL
> USER(2): (setq foo 'bar)
> BAR
> USER(3): (boundp 'foo)
> T
>

> The symbol foo, which wasn't bound before the assignment, is
> after. This behaviour is consistent across Allegro, GCL and
> CMUCL. CLtL says, I quote:
>
> 'boundp is true if the dynamic (special) variable named by symbol
> has a value; otherwise, it returns nil.'
>
> That's quite explicit. My empirical experience with implementations
> supported my reading of the documents. Although, to be honest, I had
> noted that CMUCL under those circumstances gives
>
> * (setq foo 'bar)
> Warning: Declaring FOO special.
>
> BAR
>
> which suggested to me that I hadn't got it straight...

The main point is that the standard is silent on what the behavior is
for assigning values to undeclared variables at top level. It turns out
that for both historic reasons and for the convenience of the programmer
in debugging code, all or almost all Lisp systems will treat such
undeclared variables as if they were special (dynamic) variables.

Most Lisps will treat

(setq new-var 3)

as if there were an implicit

(defvar new-var)

before the SETQ, although there is no requirement in the standard that
this be done this way. One consequence of this (and also the reason
CMUCL warns you) is that this has the effect of making that symbol be
globally proclaimed as a SPECIAL variable, and there isn't any
declaration that will undo it to allow a purely lexical binding of that
symbol.

At least one Lisp would treat the variable as special on an as-needed
basis without introducing the global proclamation.


> (setq foo 'bar) ==> bar ;; establishes a lexical binding?

> ;; ?? or should be simply illegal?

The standard doesn't say anything about the meaning of this construct.
It is therefore up to the implementation to decide how to handle this.
Now a lexical binding would be tough to imagine, since there isn't any
scoping, so I would expect that the two reasonable things an
implementation COULD do would be to either make a dynamic binding or
signal an error. As noted above, all implementations I know of
establish a binding, but a conforming implementation could signal an
error instead if it so chose.

> (boundp 'foo) ==> nil


>
> (let ((foo 'ban)) ;; establishes a dynamic binding
> (boundp 'foo)) ==> t

This would only return T if foo were globally proclaimed to be SPECIAL,
which is what will often happen if you make an undeclared reference to
that variable.

One bizarre efficiency hack I have seen is to do something like the
following:

(defun possibly-recursive-function (x)
(if (boundp '*inside-myself*)
(frobnicate-if-called-recursively x)
(let ((*inside-myself* t)) ;; Value doesn't matter
(declare (special *inside-myself*))
(frobnicate-if-called-directly x))))

The trick here is that the function will establish a special binding and
use that to figure out if it has been called before. By guarding the
establishment of the special with BOUNDP, the binding is only done once.

A non-global use of special was done to avoid adding a global variable,
and the BOUNDP test was found (by profiling) to be quicker than looking
up the value of the special binding, so it was used instead. (I will
refrain from commenting on the wisdom of this choice).

> It's the last move that bothers me. The dynamic scope of top-level
> makes a certain amount of sense -- it would be that dynamic scope which
> exists at the bottom of the stack. I can't see how a top-level variable
> has lexical scope. Again to quote ClTL:

It really can't, but not declaring the intent with PROCLAIM, DECLAIM,
DEFVAR or DEFPARAMETER could be treated as an error.

Your confusion arises because you are doing two different things in your
attempt to understand this behavior: Reading the standard and
experimenting with implementations. A close reading of the standard
will let you realize that the standard doesn't say what happens. The
fact that all major implementations have taken the same design choice
then leads you to believe that it must somehow be specified in the
standard, when it isn't. The behavior may be a de facto standard, but
you can't rely on it, and the effects are subtly different in at least
one implementation (the issue of whether such top-level variables are
considered globally special or only when refered to without a lexical binding)


> So, for the sake of my confusion, is a variable assigned to in a
> top-level assignment lexically bound, dynamically bound, not bound at
> all, or an error?

It could be dynamically bound or it could be an error at the discretion
of the implementation. I suppose it could be something else as well --
although I can't imagine what -- since the behavior is not defined by
the standard.

Rainer Joswig

unread,
Jul 1, 2000, 3:00:00 AM7/1/00
to

> ==========
> Habe nun, ach! Philosophie,
> Juristerei und Medizin,
> Und leider auch Metacircularitie
> Durchaus studiert, mit heisser Bemuehn.
> Da steh' ich nun, ich armer Tor!
> Und bin so klug als wie zuvor;
>
> - Goethe's Faust

Well, isn't it Goethe + Haflich? ;-)

How about:

Habe nun, ach! CLtL1,
CLtL2 und ANSI CL,
Und leider auch R5RS


Durchaus studiert, mit heisser Bemuehn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor;

;-)

--
Rainer Joswig, BU Partner,
ISION Internet AG, Steinhöft 9, 20459 Hamburg, Germany
Tel: +49 40 3070 2950, Fax: +49 40 3070 2999
Email: mailto:rainer...@ision.net WWW: http://www.ision.net/

Reini Urban

unread,
Jul 1, 2000, 3:00:00 AM7/1/00
to
Steven M. Haflich wrote:
>==========
>Habe nun, ach! Philosophie,
>Juristerei und Medizin,
>Und leider auch Metacircularitie
>Durchaus studiert, mit heisser Bemuehn.
>Da steh' ich nun, ich armer Tor!
>Und bin so klug als wie zuvor;
>
>- Goethe's Faust


nitpicking:
"mit heißem Bemühn" heißt's im Original.
maskulin, dativ.

http://gutenberg.aol.de/goethe/faust1/faust005.htm
--
Reini

Simon Brooke

unread,
Jul 2, 2000, 3:00:00 AM7/2/00