Newer
Older
til / common_lisp / 20231123_quote_unquote.html

<h4>Quoting and Unquoting in Common Lisp</h4>
<p>Thursday, Nov 23, 2023</p>

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

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

<p>
  Note the <code>quote-unquote (',)</code> preceding <code>o!x</code>
</p>

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

<p>To show how this works, set a variable to a form that is quoted.</p>

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

<p>The REPL returns the form unevaluated.</p>

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

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

<p>And if we evaluate the above it will return 5.</p>

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

<p>BUT, if we quote-unquote it, the top-level returns:</p>

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

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

<p>
To evaluate it without throwing an error we need to perform two evaluations:
</p>

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

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

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