I'm working my way through Graham's book "On Lisp" and can't understand the following example at page 37:
If we define exclaim so that its return value incorporates a quoted list, (defun exclaim (expression) (append expression ’(oh my))) > (exclaim ’(lions and tigers and bears)) (LIONS AND TIGERS AND BEARS OH MY) > (nconc * ’(goodness)) (LIONS AND TIGERS AND BEARS OH MY GOODNESS) could alter the list within the function: > (exclaim ’(fixnums and bignums and floats)) (FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS) To make exclaim proof against such problems, it should be written: (defun exclaim (expression) (append expression (list ’oh ’my)))
Does anyone understand what's going on here? This is seriously screwing with my mental model of what quoting does.
nconc
is a destructive operation that alters its first argument by changing its tail. In this case, it means that the constant list '(oh my)
gets a new tail.
To hopefully make this clearer. It's a bit like this:
; Hidden variable inside exclaim
oh_my = oh → my → nil
(exclaim '(lions and tigers and bears)) =
lions → and → tigers → and → bears → oh_my
(nconc * '(goodness)) destructively appends goodness to the last result:
lions → and → tigers → and → bears → oh → my → goodness → nil
so now, oh_my = oh → my → goodness → nil
Replacing '(oh my)
with (list 'oh 'my)
fixes this because there is no longer a constant being shared by all and sundry. Each call to exclaim
generates a new list (the list
function's purpose in life is to create brand new lists).