Some corrections for [the book] ANSI Common Lisp


November 22, 2004

Below is a letter, I recently wrote to Paul Graham.

Dear Mr. Graham,

I am gradually working my way through your book, ANSI Common Lisp, and I've noticed a few things, which you might like to note in your errata (and for possible future editions). These are noted below.

Appologies for the verbosity of this email. Hope you can find the time to make it all the way though.

I would also like to say that this is a fantastic book, and I have enjoyed reading it immensely, as I have with Hackers and Painters and many of your other essays.

Keep up the good work!

Take care,

Josh Staiger
http://www.joshstaiger.org

~~~~~

1. p. 97. In chapter five, problem four, you ask the reader to rewrite the num-month function located in Figure 5.1 (page 94). Unfortunately the num-month function does not appear in Figure 5.1, but rather in Figure 5.2 (page 96).

This leads to some confusion on whether you would like the num-month function in Figure 5.2 to be rewritten or the month-num function in Figure 5.1 to be rewritten. I assume that you mean month-num from figure 5.1, as it seems to make much more sense to rewrite using a case statement.

2. p. 127. There is a bug in the function buf-flush.

A (buf-reset b) call needs to be added as the first line of the body to output any characters that have already been read with buf-next.

 (defun buf-flush (b str)
   (buf-reset b) ; bug-fix   i (buf-end b)))
     (princ (bref b i) str)))

For example, without this fix using stream-subst to match the string "ec" on the string "ee" would leave a trailing 'e' in the buffer at the end which would be read by buf-next but would never be outputted with buf-flush.

 > (with-input-from-string (in "ee")
     (stream-subst "ec" "foo" in *standard-output*))
 e
 NIL

3. p. 141. There is a small bug in henley. When we read in a body of text using read-text, no following symbols will be associated with the very last word in the text in the *words* hash (unless it has already appeared previously in the text). This becomes a problem if we try to call random-next on this symbol, as the function will try to randomly pick a (non-existant) following choice.

 > (random-next '|lastsym|)

Yields the error:

 Argument is not a positive integer or a positive float: 0

My quick solution to this was simply to modify random-next to assume the '|.| symbol if we happen to hit the last symbol.

 (defun random-next (prev)
  (let ((choices (gethash prev *words*)))
    (if (null choices)
        '|.|
      (let ((i (random (reduce #'+ choices
                               :key #'cdr))))
        (dolist (pair choices)
          (if (minusp (decf i (cdr pair)))
              (return (car pair))))))))