Why this Common Lisp macro does not work? Is the answer sheet from the book wrong?

115 views Asked by At

I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs, and Slime.

In chapter 14, the last one, the author covers macros. The following problem is presented:

Write a macro called VARIABLE-CHAIN that accepts any number of inputs. The expression (VARIABLE-CHAIN A B C D) should expand into an expression that sets A to ’B, B to ’C, and C to ’D.

The answer sheet is:

enter image description here

Copying from the pdf and pasting it here:

(defmacro variable-chain (&rest vars)
 ‘(progn 
    ,@(do ((v vars (rest v))
           (res nil))
          ((null (rest v)) (reverse res))
        (push ‘(setf ,(first v) ’,(second v))
               res))))

In Emacs, I used this hack to remove smart-quotes. Pasting it in Emacs, I get:

(defmacro variable-chain (&rest vars)
  '(progn
     ,@(do ((v vars (rest v))
            (res nil))
           ((null (rest v)) (reverse res))
         (push '(setf ,(first v)
                      ',(second v))
                res))))

Unfortunately, I cannot compile it to the Slime's REPL, it throws an error:

> READ error during COMPILE-FILE: Comma not inside a backquote.

I tried changing '(progn to:

`(progn

But it also did not work: "comma not inside a backquote".

Did I do something wrong? Or, is the answer sheet incorrect?

Thanks.

1

There are 1 answers

2
Will Ness On BEST ANSWER

You need to change the other one as well:

(defmacro variable-chain (&rest vars)
  `(progn
 ;; this one you did change
     ,@(do ((v vars (rest v))
            (res nil))
           ((null (rest v)) (reverse res))
         (push `(setf ,(first v)
           ;; ^^^ also need to change this one
                      ',(second v))
                res))))

The is the backquote, whereas is the regular quote, but your "hack" turned both of them into the regular quote ' chars erroneously:

(defmacro variable-chain (&rest vars)
 ‘(progn 
 ;; backquote
    ,@(do ((v vars (rest v))
           (res nil))
          ((null (rest v)) (reverse res))
        (push ‘(setf ,(first v) ’,(second v))
          ;; backquote         quote
               res))))