I'm a Common Lisp beginner and came across this piece of code:
(let ((foo (list 42)))
(setf (rest foo) foo))
The REPL seem to just loop forever when trying to execute it.
I'm a Common Lisp beginner and came across this piece of code:
(let ((foo (list 42)))
(setf (rest foo) foo))
The REPL seem to just loop forever when trying to execute it.
What is
FOO
?FOO
is initially a fresh list,(42)
. In Lisp, lists are represented by cons cells, blocks of mutable memory containing each aCAR
and aCDR
slot. Another way to print it is(42 . NIL)
, where theCAR
andCDR
are on each side of the dot. This can also be pictured as follows:When you call
SETF
with the(rest foo)
place and thefoo
value, you are saying that you want the cdr cell ofFOO
to hold the valueFOO
. In fact, this occurrence ofSETF
is likely to macroexpand into a call toRPLACD
.Why does the REPL loop forever?
The "P" part of the "REPL" (print) tries to print your circular structure. This is because
SETF
's value is the one being returned from the form being evaluated, and the value returned bySETF
is the value of its second argument, namelyFOO
. Imagine you want to write a cons cell X with a naive algorithm:However, for
foo
, step 4 will print the same structure, recursively, and will never terminate.What can you do?
Try setting
*PRINT-CIRCLE*
to T first:And now, your REPL should be happy:
The "Sharpsign Equal-Sign" notation allows the reader to affect part of a form to a (reader) variable, like
#1=...
, and reuse it afterwards, e.g.#1#
. This make it possible to represent circular cross-references between data, either during reading or printing. Here, we can see that the variable#1#
denotes a cons-cell, where theCAR
is 42 and theCDR
is#1#
itself.