Search code examples
syntaxcommon-lispreader-macro

Common Lisp No Dispatch Character Defined


I am currently reading the chapter on read-time macros from Paul Graham's "On Lisp" book.

The problem I am encountering is the following. When I run one of his examples:

(set-dispatch-macro-character #\# #\?
  #’(lambda (stream char1 char2)
    ‘#’(lambda (&rest ,(gensym))
       ,(read stream t nil t))))

I get the following error:

No dispatch function defined for #\’

Why is it happening? Could it be because I am running it at the REPL? What can one do to fix it?


Solution

  • The PDF from which you are copying the code uses punctuation marks outside the range of basic ASCII characters you are supposed to use here:

    CL-USER> (char-name #\’)
    "RIGHT_SINGLE_QUOTATION_MARK"
    

    The usual quote symbol should instead use the apostrophe character:

    CL-USER> (char-name #\')
    "APOSTROPHE"
    

    The same goes for backquote:

    CL-USER> (char-name #\‘)
    "LEFT_SINGLE_QUOTATION_MARK"
    

    You should be writing instead:

    (set-dispatch-macro-character #\# #\?
                                  #'(lambda (stream char1 char2)
                                    `#'(lambda (&rest ,(gensym))
                                         ,(read stream t nil t))))
    

    The #' is not necessary before lambda, since Common Lisp also defines a macro named lambda which expands into (function (lambda ...)).

    You can test your new read macro as follows:

    CL-USER> #?10
    #<FUNCTION (LAMBDA (&REST #:G617)) {1001C541FB}>
    
    CL-USER> (funcall *)
    10
    

    When using SBCL, I obtain warnings about unused variables. This happens because the code declares variables in anonymous functions but never uses them. This is not a serious problem, but generally speaking, it is better to declare which variables are ignored:

    (set-dispatch-macro-character
     #\# #\?
     (lambda (stream &rest chars)
       (declare (ignore chars))
       (let ((rest (gensym)))
         `(lambda (&rest ,rest)
            (declare (ignore ,rest))
            ,(read stream t nil t)))))