Search code examples
common-lispreader-macroon-lisp

The necessity of quote in On Lisp's #[ read macro?


I am reading On Lisp and cannot make out why the code below has use a quote. Here is the excerpt from the text:

Another character combination reserved for the user is #[. Figure 17.3 gives an example of how this character might be defined as a more elaborate kind of left parenthesis. It defines an expression of the form #[x y] to read as a list of all the integers between x and y, inclusive:

#[2 7]
(2 3 4 5 6 7)

Figure 17.3: A read-macro defining delimiters.

(set-macro-character #\] (get-macro-character #\)))

(set-dispatch-macro-character #\# #\[
                              #'(lambda (stream char1 char2)
                                   (let ((accum nil)
                                         (pair (read-delimited-list #\] stream t)))
                                     (do ((i (ceiling (car pair)) (1+ i)))
                                         ((> i (floor (cadr pair)))
                                          (list 'quote (nreverse accum)))
                                       (push i accum)))))

         Figure 17.3: A read-macro defining delimiters.

I do not understand why the line in the result form for the do**is **(list 'quote (nreverse accum))) rather than (nreverse accum). Because we can run the code which does not using quote below without problem, right?

(let ((acc nil))
  (do ((i 2 (1+ i)))
      ((> i 7)
       (nreverse acc))
    (push i acc)))

Does any one know the trick here?


Solution

  • If you enter the new syntax at a Lisp listener, the reader would return a list of numbers. Evaluating this list of numbers would be an error, since Lisp expects a function or macro as the head of a list. Lists are not evaluating to themselves, as vectors, numbers, hash tables, ... are.

    Thus you have two choices:

    1. have the user write a quote in front of the interval expression to prevent evaluation
    2. return a quoted list

    Here we see choice 2.

    CL-USER 7 > (read-from-string "#[5 10]")
    (QUOTE (5 6 7 8 9 10))
    
    CL-USER 8 > (eval (read-from-string "#[5 10]"))
    (5 6 7 8 9 10)
    
    CL-USER 9 > (let ((e #[5 10]))
                  (describe e))
    
    (5 6 7 8 9 10) is a LIST
    0      5
    1      6
    2      7
    3      8
    4      9
    5      10
    

    If the reader macro would not return a quote list form, we would have to write:

    CL-USER 10 > (let ((e '#[5 10]))   ; notice the QUOTE
                   (describe e))
    
    (5 6 7 8 9 10) is a LIST
    0      5
    1      6
    2      7
    3      8
    4      9
    5      10
    

    Hmm, I would personally actually prefer the latter, having to write the quote explicitly.

    I get:

    CL-USER 17 > '(#[5 10] #[20 25])
    ((QUOTE (5 6 7 8 9 10)) (QUOTE (20 21 22 23 24 25)))
    

    But I would have preferred:

    CL-USER 18 > '(#[5 10] #[20 25])
    ((5 6 7 8 9 10) (20 21 22 23 24 25))