macroscommon-lisplisp-macros

How to re-write this Common Lisp macro avoiding the back-quote notation?


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 the last chapter, on Macros, the author presents examples to re-write the built-in incf macro. He teaches the concept with two different approaches: using back-quote notation and without it. Such as:

(defmacro list-notation-my-incf (x)
  (list 'setq x (list '+ x 1)))

(defmacro backquote-notation-my-incf (x)
  `(setq ,x (+ ,x 1)))

Later, the author introduces another example:

In the example below, TWO-FROM-ONE is a macro that takes a function name and another object as arguments; it expands into a call to the function with two arguments, both of which are the quoted object.

He only uses back-quote character to do it:


(defmacro two-from-one (func object)
  `(,func ',object ',object))

And it works as expected:

CL-USER> (two-from-one cons stack-overflow)
(STACK-OVERFLOW . STACK-OVERFLOW)

Using slime-macroexpad-1, I have:

(CONS 'STACK-OVERFLOW 'STACK-OVERFLOW)

As an exercise that I created for myself, I tried doing the same, but avoiding the back-quote notation. Unfortunately, I could not make it work:

(defmacro list-two-from-one (func object)
  (list func (quote object) (quote object)))

Slime throws the error:

The variable OBJECT is unbound.
   [Condition of type UNBOUND-VARIABLE]

Doing a macro expansion, I see:

(CONS OBJECT OBJECT)

If I try a different approach, it seems to be closer, but it does not work either:

(defmacro list-two-from-one (func object)
  (list func object object))

Throws the error:

The variable STACK-OVERFLOW is unbound.
   [Condition of type UNBOUND-VARIABLE]

And, finally, the macro expansion indicates:

(CONS STACK-OVERFLOW STACK-OVERFLOW)

I feel stuck. How do I successfully re-write the macro without using back-quote notation?

Thanks.


Solution

  • What you are looking for is something like

    (defmacro list-two-from-one (func object)
      (list func (list 'quote object) (list 'quote object)))
    

    basically, the body of a macro should return the code, that, when evaluated, produces the desired result.

    I.e., the macro body should produce (CONS 'STACK-OVERFLOW 'STACK-OVERFLOW).

    Since 'a is the same as (quote a), you want your macro to produce

    (CONS (QUOTE STACK-OVERFLOW) (QUOTE STACK-OVERFLOW))
    

    which is what my defmacro above returns.