lispcommon-lispliteralsquotingon-lisp

Strange Lisp Quoting scenario - Graham's On Lisp, page 37


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.


Solution

  • 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).