How ,',z
works is that:
`(list ,x `(,',z ,,@y))))
^ ^
| `- this comma
`- belongs to this backquote
The above comma interpolates, into the inner backquote, the expression ',z
or (quote ,z)
. And that ,z
, in turn, belongs to the outer backquote.
Thus the value of z
is inserted into (quote ,z)
to make (quote <value-of-z>)
.
Then, effectively, the inner backquote then behaves like `(,'<value-of-z>)
.
Concretely, suppose z
contains the list (+ 2 2)
. Then we can understand it in terms of the outer backquote inserting (+ 2 2)
into the inner one to produce `(,'(+ 2 2) ...)
. This is now straightforward to understand: when the inner backquote is evaluated, the (+ 2 2)
is protected from evaluation, resulting in the object ((+ 2 2) ...)
.
The pattern ,',',', ... ,',expr
is used to obtain a single evaluation of expr
during the evaluation of the outermost backquote, such that this value is then propagated through any number of evaluation rounds of the remaining backquote nestings without undergoing further evaluation. There is a kind of "backquote algebra" at play here in which the "commas and quotes cancel out".
You can also visualize the ,',','...
as a kind of drill bit that digs through the layers of nesting to allow you plant a literal value anywhere in the structure. E.g.
(defmacro super-nested-macro (arg)
`(... `(.... `(.....`(we simply want arg down here ,',',',arg)))))
The author of super-nested-macro
just wants to stick the value of arg
into the template, in a position that is buried in three other backquotes. Thus the usual ,arg
cannot be used: that comma would be misinterpreted as belonging to the inner-most backquote.
Are there any other weird edge cases with backquote/quasiquote?
One weird edge case in backquote is trying to splice into a dot position:
`(a b c . ,@foo) ;; not allowed
`(a b c . ,foo) ;; OK: equivalent to `(a b c ,@foo)
Not sure how various implementations deal with a backquote in a dot position:
`(a b c . `(d e f))
It doesn't really make sense, and I suspect that the actual result obtained will depend on the backquote implementation internals.
Not all objects are traversed for unquoting:
`#c(,(sin theta) ,(cos theta)) ;; Not required by ANSI CL, oops!
This could work via an implementation's extension.