Quoting and Unquoting in Common Lisp

Thursday, Nov 23, 2023

Reading Let Over Lambda (LOL), and in Chapter 3 he demonstrates how to create macros that will only evaluate a form once. The macro is defmacro! and on page 60 he gives an example of it's use and the results.

(defmacro! square (o!x)
  `(progn
     (format t "[~a gives ~a]~%")
         ',o!x ,g!x)
     (* ,g!x ,g!x))

Note the quote-unquote (',) preceding o!x

The thing I have to remember is that macros do not evaluate the forms they are given, but return forms to be evaluated later.

To show how this works, set a variable to a form that is quoted.

CL-USER> (defvar b '(+ 1 3))
(+ 1 3)

The REPL returns the form unevaluated.

If we use it in an expression, backquote the expression and unquote symbol B, we will see how it expands.

CL-USER>  `(+ 1 ,b)
(+ 1 (+ 1 3))

And if we evaluate the above it will return 5.

CL-USER>  (eval `(+ 1 ,b))
5

BUT, if we quote-unquote it, the top-level returns:

CL-USER> `(+ 1 ',b)
(+ 1 '(+ 1 3))

If we were to evaluate the above it would throw us into the debugger because of '(+ 1 3)

To evaluate it without throwing an error we need to perform two evaluations:

CL-USER> (eval `(+ 1 (eval ',b)))
5

This also demonstrates how functions evaluate their arguments first BEFORE they perform the calculations in defined in the function.

With macros, they do not evaluate their arguments. Macros return forms to be evaluated later. Thus, when a macro is given an expression (+ 1 3) it needs to be unquoted in order to be evaluated at a later time (remember when defining macros everything is wrapped in a backquote).