Exercise for the reader: what's the difference between Graham's
nil! and the following:
(defun set-nil (x) (setf x nil))
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
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
Why is the macro that swaps two variables called
rotatef? Well, the
f part is by analogy to
rotatef operates on "places" just
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
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.
append1f example is not portable. On this
page and in the glossary, he correctly says that
requires a function name. Why he then used a
lambda I can't say.
This is a cute example of compile-time optimization but it's also an example of an evil macro.