0

I would like to use an array or list to store dynamic variables for later retrieval via an index. So if I have:

(defparameter *foo* '(1 2 3))
(defparameter *bar* '(3 4 5))
(defparameter *baz*
  (make-array 2 :initial-contents '(*foo* *bar*)))

I would like to retrieve *foo* by calling (aref *baz* 0) and have this return '(1 2 3)

Of course, this doesn't work and the *foo* stored in *baz* isn't even the special variable I defined at top-level, as shown when I try to do (elt (aref *baz* 0) 1) which only returns an error and not the value 2. Let me say I am new to Common Lisp and I don't even know how to describe this question in a way that helped me in searching through CLHS, etc. Any help would be appreciated!

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346

2 Answers2

3

You need to understand the difference between a symbol (which is a data type in Lisp) and its value. The symbol exists as an object. The value of a symbol is either the result of an evaluation or can be retrieved by accessing the symbol value. Lisp is one of the few languages where a symbol is a first class datatype and which has also a value which can be set and bound.

> '*foo*
*foo*       ; the symbol *foo* itself

> *foo*
(1 2 3)     ; the value of the symbol *foo* -> this list

> (eval '*foo*)
(1 2 3)     ; the value of the symbol *foo* -> this list


> (symbol-value '*foo*)
(1 2 3)     ; the value of the symbol *foo* -> this list

One can retrieve the value of a symbol with the function symbol-value:

(symbol-value '*foo*)

(let ((symbol '*foo*))
  (symbol-value symbol))
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
2

I suggest you to read When to use ' (or quote) in Lisp? and CLHS quote entry for a comprehensive explanation.

I will just focus on two problems in your code:

Usage of quote

Look at '(*foo* *bar*). quote stops the evaluation of these two symbols, so result of this expression will be a list with two symbols, *foo* and *bar*.

Compare that with (list *foo* *bar*)- during evaluation, symbols *foo* and *bar* are evaluated to their values, so the result will be '((1 2 3) (3 4 5)).

Usage of quoted lists

As CLHS quote entry says:

The consequences are undefined if literal objects (including quoted objects) are destructively modified.

If you want to modify your lists later, you should create them with list or another function.

So, your code should look like this:

(defparameter *foo* (list 1 2 3))
(defparameter *bar* (list 3 4 5))
(defparameter *baz*
  (make-array 2 :initial-contents (list *foo* *bar*)))

I would also consider using 2d array, so you can combine elt + aref into one (aref *baz* 0 0), but that depends on the exact problem you're trying to solve.

Martin Půda
  • 7,353
  • 2
  • 6
  • 13
  • To be clear: using the `quote` form is fine for specifying the initial contents in the call to `make-array` even if `*baz*` will be modified later since `*baz*` is bound to the new array and not the initial contents list. – ad absurdum May 11 '23 at 23:02