[COLUG] Re: Lisp variable scope
Steven Huwig
shuwig at columbus.rr.com
Sat Dec 2 22:57:27 EST 2006
On Dec 2, 2006, at 8:01 PM, David Riggs wrote:
>
>> From: Steven Huwig <shuwig at columbus.rr.com>
>
>> I think your trouble is using '("a" . 0) instead of (cons "a" 0).
>
> Dear Steven,
>
> Thank you.
>
> YES, that's it! Now the values are reset to zero each time the
> function is called. But why? Apparently there is something
> fundamental that I still do not get about lists, and Steele does
> not explain it (as far as I can tell).
The behavior actually has nothing to do with lists, but rather
with the quote operator and the particular Lisp implementation.
Remember that '("a" . 0) is shorthand for (quote ("a" . 0)). The
quote operator is used to "escape" forms that would otherwise be
evaluated. For example, if you were to write:
(let ((x ("a" . 3))) ... )
then Emacs would respond with:
Lisp error: (invalid-function "a")
because (f x) means to apply function f to x, but "a" is a
string, not a function. So you need (quote ("a" . 3)).
But... quote is handled at read time, not evaluation time! The
object '("a" . 3) is a literal value in your code, and modifying
a literal value has undefined behavior.
When you use (cons "a" 0), that is a function that is evaluated each
time through the loop. Each time you are guaranteed to be working
with a fresh object with value ("a" . 0).
I didn't find any treatment in CLtL2 about this, but I don't typically
use that as a Lisp reference. It is noted in the Hyperspec entry for
QUOTE: <http://www.lisp.org/HyperSpec/Body/speope_quote.html>, and is
mentioned in chapter 4, footnote 14 in Practical Common Lisp at
<http://www.gigamonkeys.com/book/syntax-and-semantics.html>.
The situation here is similar to the following situation in C:
#import <stdio.h>
int main() {
char* x = "Hello, World!\n";
x[4] = 'd';
printf(x);
return 0;
}
which gives the following result on my system:
scully:~/Code steve$ gcc example.c
scully:~/Code steve$ ./a.out
Bus error
scully:~/Code steve$
Using cons, however, is similar to doing this:
#import <stdio.h>
#import <string.h>
int main() {
char x[15];
strncpy(x, "Hello, World!\n", 15);
x[4] = 'd';
printf(x);
return 0;
}
which results in:
scully:~/Code steve$ gcc example2.c
scully:~/Code steve$ ./a.out
Helld, World!
scully:~/Code steve$
The reason is that the C and Lisp implementations are allowed to
handle literals in a variety of ways. The Emacs interpreter
apparently ends up reusing a pointer to the literal for the
target of your setcdr. After all, what's the point of constantly
re-reading ("a" . 0) each time in the loop? The interpreter
already did that once, and the answer's sitting right over here
in this memory cell here ... hope nobody messed with its cdr
... oh well, not Emacs's problem ...
Hope this helps,
Steve
P.S. If you are wanting to delve into the particulars of Lisp
semantics, you may want to either find Emacs Lisp-specific
references instead of using Common Lisp references, or change to
a Common Lisp implementation. Emacs Lisp is quite idiosyncratic.
More information about the colug432
mailing list