2

Considering the behavior of dynamic and lexical bound variables, I understand the output of symbol-value in the following code (dynamically bound variable a is shadowed by a lexical bound variable a (that explanation is wrong, see edit below)):

(defvar a 1)
(let ((a 2))
  (list a (symbol-value 'a)))
 ; => (2 2)

But when using progv to create a similar environment, symbol-value gives a different result:

(progv '(x) '(1)
  (let ((x 2))
    (list x (symbol-value 'x))))
 ; => (2 1)

Why is (symbol-value 'x) returning 1 in the second example?

final edit accompanying the accepted answer: throughout comments at Rainer Joswig's answer I learnt that (let ((a 2)) ... ) does not bind a lexical variable, but shadows the value of the former dynamic binding. Also Martin Buchmann pointed out, in a comment, that symbol-value ignores lexical variables.

jue
  • 435
  • 5
  • 7
  • 1
    I think the [documentation](http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_5.htm) of `symbol-value` gives you the explanation. `symbol-value` ignores lexical variables if I understand it correctly. – Martin Buchmann Apr 04 '21 at 19:48
  • @MartinBuchmann thank you, this means my understanding (and explanation) of the first example is wrong. (i.e. this means `a` is not shadowed by a *lexical* bound variable `a`, but only the value is shadowed) – jue Apr 06 '21 at 11:02

1 Answers1

3

The PROGV special form creates dynamic bindings, but does not declare the variable to be special for enclosed forms.

Thus we need to declare the LET binding of the variable x to be special:

CL-USER 27 > (progv '(x) '(1)
               (let ((x 2))
                 (declare (special x))
                 (list x (symbol-value 'x))))
(2 2)

DEFVAR OTOH declares its variable to be special. Globally and there is no direct way to undo that declaration.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • But `(let ((x 1)) (declare (special x)) (let ((x 2)) (list x (symbol-value 'x))))` evals to `; => (2 1)` – jue Apr 06 '21 at 11:13
  • Also I have a problem to distinguish between the meanings of "variable with dynamic binding" and "special variable". Is the explanation at the [c2 wiki](https://wiki.c2.com/?SpecialVariable)? (I've not yet full grasped the meaning of "IndefiniteScope", thats an english translation issue on my side) – jue Apr 06 '21 at 11:29
  • First comment: @jue: The *special* declaration is only for the first LET. – Rainer Joswig Apr 06 '21 at 11:32
  • Second comment: @jue: a variable declared to be *special* binds values in a dynamic environment. They are not *lexical variables*. – Rainer Joswig Apr 06 '21 at 11:34
  • 1
    ok, so regarding the examples in my question, `(let ((a 2))...)` does not bind a lexical variable, while `(let ((x 2)) ...)` binds a lexical variable. Is that correct? – jue Apr 06 '21 at 11:42