0

I'm having difficulty understanding the workings of a bit of code that someone with more experience may comprehend:

(let ((x 0))
  (loop for var in '(x)
    do (set var 3))
  x)

My expectation is that the expression should return 3, the new value of x, but it actually returns 0. Why does x not get reset? Is there another way to iterate over a list of variables and assign them values?

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
davypough
  • 1,847
  • 11
  • 21
  • 2
    `X` is a lexical variable. `SET` only sets the value-slot of a symbol (in other words it sets the value of a global variable). – jkiiski Oct 25 '16 at 03:57
  • 1
    @jkiiski: that is the answer, not a comment. – Svante Oct 25 '16 at 07:19
  • 1
    [`set`](http://clhs.lisp.se/Body/f_set.htm) is deprecated so you shouldn't use it. Use `setf` special form to mutate bindings special global or lexical. Updating bindings based on a symbol that looks the same probably needs to be solved with other data structures like hash tables instead. – Sylwester Oct 25 '16 at 07:48

1 Answers1

7

Access to lexical variables using symbols is not supported.

Common Lisp does not give you access to lexical variables via symbols. By default variables are bound lexically.

Special variables use dynamic binding.

It works with special variables, which use dynamic binding:

CL-USER 14 > (let ((x 0))
                (declare (special x))
                (loop for var in '(x) do (set var 3))
                x)
3

Alternatively you can declare a global special variable and the special declaration extends to let bindings. That's also why one marks them visually with a naming convention. We write *foo* and not foo.

CL-USER 15 > (defvar *x123* 0)
*X123*

CL-USER 16 > (let ((*x123* 1))
               (loop for var in '(*x123*) do (set var 3))
               *x123*)
3
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • Can you expand a little on what no access to lexical vars via symbols means? Eg, does a lexical var have the usual symbol slots like print-name, symbol-value, symbol-function, prop list, etc? Or does a lex var never have a symbol as its symbol-value? Thanks for any clarification, and sorry if this is elementary. (cont'd below) – davypough Oct 26 '16 at 03:14
  • Second, I was hoping to avoid using global vars. The user will be providing the var names (acquired by macros). Currently, I am constructing a let clause (at load time) with these var names (see above for my example with one variable named x), and then setting their values appropriately in the body. If "set" is not available for lex vars, then is "setq" (or "setf") the only way left? But then it looks like I can't group all these var names into a list, and process each one with a loop variable. Is there some other way to set the values (all numbers) within the let? (cont'd below) – davypough Oct 26 '16 at 03:14
  • The only other idea I've had is maybe to create a separate user package (or perhaps use the :keywords package), and intern these names there. But this might require some significant code rewriting/rethinking. Looking for any experienced insights. Thanks. – davypough Oct 26 '16 at 03:15
  • OK, thanks Rainer. With further reading I've been able to correct some mistaken ideas about lexical & special variables. Just ignore my previous comments. I can use the (declare (special ...)) solution you mentioned. – davypough Oct 27 '16 at 14:00