Page 162


Exercise for the reader: what's the difference between Graham's nil! and the following:

(defun set-nil (x)
      (setf x nil))

Page 163

Macro functions

The comment at the top of the page about macros being functions is confusing. Macros are not functions, so you can't pass a macro to apply, mapcar, etc.

However, macros work by calling macro expanders to expand the macro call into Lisp code. Macro expanders are functions. You can get the macro expander for a macro using macro-function.

Page 165


Why is the macro that swaps two variables called rotatef? Well, the f part is by analogy to setf. rotatef operates on "places" just like setf does. The rotate part is because rotatef can handle any number of places, not just two. See the glossary in Graham for details.


If you do the list-of macro exercise, then you can define quicksort on a list (not a vector) like this:

(defun quicksort (l)
      (cond ((null l) nil)
            (t (let ((p (car l))
                    (r (cdr l)))
                (append (quicksort (list-of x (x :in r) (< x p)))
                        (list p)
                        (quicksort (list-of x (x :in r) (>= x p))))))))

This is pretty inefficient (it conses a lot), but it does capture the essence of the algorithm nicely: choose a pivot p and split the list into those items less than p and greater than p.

Page 169

Graham's append1f example is not portable. On this page and in the glossary, he correctly says that define-modify-macro requires a function name. Why he then used a lambda I can't say.

Page 172


This is a cute example of compile-time optimization but it's also an example of an evil macro.