Hi,
This is working:
CL-USER> (setf a 11)
11
CL-USER> (setf b 12)
12
CL-USER> (setf c 13)
13
CL-USER> (dolist (el '(a b c)) (print (eval el)))
11
12
13
And this doesn't work :
CL-USER> (let ((d 21) (e 22) (f 23))
(dolist (el '(d e f)) (print (eval el))))
; Evaluation aborted
with the error :
EVAL: variable D has no value
[Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
What did I do wrong ?
How can I get the correct result ?
Thanks,
Joseph
On Feb 19, 4:06 pm, Joseph Frippiat <···············@skynet.be> wrote:
>
> CL-USER> (let ((d 21) (e 22) (f 23))
> (dolist (el '(d e f)) (print (eval el))))
> ; Evaluation aborted
>
> with the error :
>
> EVAL: variable D has no value
> [Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
>
> What did I do wrong ?
Note: I'm not an expert on this, so I expect to be corrected, but this
should set you along the proper path...
EVAL runs within a certain environment (see http://www.lisp.org/HyperSpec/Body/sec_3-1-1.html).
Those variables are not being declared within that environment - they
are being declared in a LEXICAL environment, and so are unbound when
that data is evaluated.
> How can I get the correct result ?
Any number of ways, but if you want to use the LET, one way would be
to declare those bindings as dynamic so they exist in the dynamic
environment. For example:
(let ((a 1) (b 2) (c 3))
(declare (special a b c))
(dolist (el '(a b c))
(print (eval el))))
1
2
3
HTH,
Jeff M.
Hi,
> What did I do wrong ?
You used EVAL. :)
More to the point, the value of '(D E F) (which is EQUAL to the value
of (list 'D 'E 'F) is not a list of variables, it's a list of
symbols. Symbols don't refer to specific lexical variable bindings.
They're just names.
> How can I get the correct result ?
(let ((d 21) (e 22) (f 23))
(dolist (el (list d e f))
(print el)))
Bye,
Matthias
From: Kent M Pitman
Subject: Re: Printing values of a list of variables
Date:
Message-ID: <u63wkwig1.fsf@nhplace.com>
Joseph Frippiat <···············@skynet.be> writes:
Looks like a few people already answered, and not incorrectly, but
this is the kind of thing that needs some detail to get through so
I've added some texture here that I hope will help.
> Hi,
>
> This is working:
>
> CL-USER> (setf a 11)
> 11
> CL-USER> (setf b 12)
> 12
> CL-USER> (setf c 13)
> 13
At toplevel, not in a program, you are actually outside the semantics
of the language. It simply does not define the meaning of assigning a
variable you have not declared.
In practice, such variables are almost always treated as special
variables, not lexical variables, since CL has no notion of a global
lexical but does have a notion of a global special, and so assuming
they are meant as global specials is the "easiest reach" for an
implementor grasping about for an interpretation when they go to
implement the behavior in an underspecified situation.
You should also know/learn that the special variable is,
coincidentally, stored in a place accessed by the symbol-value
operation on a symbol. That is, the variables a, b, and c above are
variables, not symbols. But those variables are named by symbols, and
since [in most implementations] those variables are treated as
special, you are ALSO setting a place, we'll call it a slot, though
it's not quite the same kind of "slot" that you get in a class
definition, in the symbol [it's not necessarily "in" the symbol,
either, but it suffices to think of it as if it were just a slot of a
symbol].
> CL-USER> (dolist (el '(a b c)) (print (eval el)))
You are here iterating across a list of symbols, not a list of
variables. Symbols do not accidentally become variables. Symbols are
symbols by virtue of the fact that they are data, and they only become
variables if you "promote" them by use of a function like eval or
compile.
So here you have used eval. That takes the symbol A and says "treat
this as if it were a program". Then Lisp says, "oh, i see, so you
mean you want me to execute a program containing only the variable
named by the symbol A" and it does this, and it gives back the value
of the special variable [in most implementations] for the same reason
as that's what got assigned above.
Same for B and C.
> 11
> 12
> 13
>
> And this doesn't work :
>
> CL-USER> (let ((d 21) (e 22) (f 23))
Here you are binding d, e, f lexically. These are also variables
named by symbols. But, importantly, the thing about lexical variables
is that their lexicality necessarily and definitionally implies that
they are not stored in a place that is named by anything other than
the set of three pieces of knowledge: that they were named by that
symbol, that they were in the textual space of that program [within
that LET], and that they were within the dynamic activation context of
that particular running instance of that expression [the LET], or some
closure over it.
> (dolist (el '(d e f)) (print (eval el))))
So here you are trying to access a special varaible when you've bound
a lexical. No good.
You can either do:
(let ((d 21) (e 22) (f 23))
(declare (special d e f))
(dolist (el '(d e f)) (print (eval el))))
making the binding be special, or else you can do:
(let ((d 21) (e 22) (f 23))
(dolist (el '(d e f))
(print (cond ((eq el 'd) d)
((eq el 'e) e)
((eq el 'f) f)
(t (error "that's all i know lexically."))))))
where in this case you translate special to lexical by virtue of
exhaustively and explicitly enumerating the set of lexically known
variables--there is no way to do it by inspecting the environment
because the environment is not required to persist into runtime. The
WHOLE POINT of a lexical variable is to allow the compiler to "compile
it away". If it were left around for you to poke at and discover by
some investigative means (like EVAL), then it would not have been
adequately optimized!
> ; Evaluation aborted
>
> with the error :
>
> EVAL: variable D has no value
> [Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
>
> What did I do wrong ?
> How can I get the correct result ?
There is no canonical notion of correct here. You have a mismatch
between how you bound the variable and how you accessed it. The two
approaches I show above are radically different but each addresses the
mismatch, one by changing the binding to match the way the access is
done, the other by leaving the binding alone and changing the access.
Incidentally, you show know that your subject line is misleading.
PRINT is irrelevant here. PRINT is just printing the value of an
expression. Your problem is accessing the value of a variable, not
printing the result of such an access. And the reason you're having
trouble is that you're not sure what variable you want to access,
perhaps because you're not seeing the difference between specials and
lexicals. (I admit CL works hard to finesse that difference and not
make it always apparent, so that's why it's a hard thing to get over.
But really, once you see what's going on, you'll find it easier.)
It will also help you REALLY A LOT if you learn to always mark special
variables with *'s and always mark lexicals without them. This will
avoid a number of program errors, and in particular once someone knows
you use this convention, they can look at your program and say with
some certainty "oh, you're confused if you think this is a special"
(or "isn't a special"). Theoretically, any variable can be
either. But if you use the *foo* convention, then it's easy to tell
you if you made a mistake in thinking which world you were in.
In the above, if you had done (setf *a* 1) ... and later
(dolist (x '(*a* ...)) ...)
you'd have marked them correctly and you'd see the issue. As soon as
someone does
(dolist (x '(a b c)) ...)
and thinks they will access lexicals, you already know they are in
trouble, since there is no way for a program P1 to turn data into a
lexical access into that selfsame program P1. You can construct
another program P2 that has lexical bindings and accesses within it,
but that's different.
Hopefully this gives you a bit more to go on. Ask questions if
something still confuses you and I'm sure people will be happy to
help.
In article <·············@nhplace.com>,
Kent M Pitman <······@nhplace.com> wrote:
> > And this doesn't work :
> >
> > CL-USER> (let ((d 21) (e 22) (f 23))
>
> Here you are binding d, e, f lexically.
And if you don't know what that means, this might help:
http://www.flownet.com/ron/specials.pdf
rg
Kent M Pitman wrote:
> Looks like a few people already answered, and not incorrectly, but
> this is the kind of thing that needs some detail to get through so
> I've added some texture here that I hope will help.
Thanks for the detailed explanations. And thanks to everybody who answered.
Joseph