Next: , Previous: , Up: baselib   [Index]


4.16 Quasiquotation

Syntax: quasiquote ?qq-template
Auxiliary Syntax: unquote
Auxiliary Syntax: unquote-splicing

“Backquote” or “quasiquote” expressions are useful for constructing a list or vector structure when some but not all of the desired structure is known in advance.

?qq-template should be as specified by the grammar at the end of this entry.

If no unquote or unquote-splicing forms appear within the ?qq-template, the result of evaluating (quasiquote ?qq-template) is equivalent to the result of evaluating (quote ?qq-template).

If an (unquote ?expression …) form appears inside a ?qq-template, however, the ?expressions are evaluated (“unquoted”) and their results are inserted into the structure instead of the unquote form.

If an (unquote-splicing ?expression …) form appears inside a ?qq-template, then the ?expressions must evaluate to lists; the opening and closing parentheses of the lists are then “stripped away” and the elements of the lists are inserted in place of the unquote-splicing form.

Any unquote-splicing or multi–operand unquote form must appear only within a list or vector ?qq-template.

The following abbreviations may be used:

(quasiquote ?qq-template)       =  `?qq-template
(unquote ?expression)           =  ,?expression
(unquote-splicing ?expression)  =  ,@?expression

Examples:

`(list ,(+ 1 2) 4)                      ⇒ (list 3 4)

(let ((name 'a))
  `(list ,name ',name))                 ⇒ (list a (quote a))

`(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)   ⇒ (a 3 4 5 6 b)

`((foo ,(- 10 3))
  ,@(cdr '(c)) . ,(car '(cons)))        ⇒ ((foo 7) . cons)

`#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8)
                                        ⇒ #(10 5 2 4 3 8)

(let ((name 'foo))
  `((unquote name name name)))          ⇒ (foo foo foo)

(let ((name '(foo)))
  `((unquote-splicing name name name))) ⇒ (foo foo foo)

(let ((q '((append x y) (sqrt 9))))
  ``(foo ,,@q))
⇒ `(foo (unquote (append x y) (sqrt 9)))

(let ((x '(2 3))
      (y '(4 5)))
  `(foo (unquote (append x y) (sqrt 9))))
⇒ (foo (2 3 4 5) 3)

Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing at the same nesting level as the outermost quasiquote. The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.

`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
⇒  (a `(b ,(+ 1 2) ,(foo 4 d) e) f)

(let ((name1 'x)
      (name2 'y))
  `(a `(b ,,name1 ,',name2 d) e))
⇒  (a `(b ,x ,'y d) e)

A quasiquote expression may return either fresh, mutable objects or literal structure for any structure that is constructed at run time during the evaluation of the expression. Portions that do not need to be rebuilt are always literal. Thus:

(let ((a 3))
  `((1 2) ,a ,4 ,'five 6))

may be equivalent to either of the following expressions:

'((1 2) 3 4 five 6)

(let ((a 3))
  (cons '(1 2)
        (cons a (cons 4 (cons 'five '(6))))))

However, it is not equivalent to this expression:

(let ((a 3))
  (list (list 1 2) a 4 'five 6))

It is a syntax violation if any of the identifiers quasiquote, unquote, or unquote-splicing appear in positions within a ?qq-template other than as described above.

The following grammar for quasiquote expressions is not context–free. It is presented as a recipe for generating an infinite number of production rules. Imagine a copy of the following rules for N = 1, 2, 3, …; N keeps track of the nesting depth.

;;This is the argument of QUASIQUOTE.
;;
?qq-template -> ?qq-template-1

;;This represents an expression to be evaluated.  It exists
;;to represent ?qq-template-(N-1) when N=1.
;;
?qq-template-0 -> ?expression

?quasiquotation-N -> (quasiquote ?qq-template-N)

?qq-template-N
   -> ?lexeme-datum
    | ?list-qq-template-N
    | ?vector-qq-template-N
    | ?unquotation-N

?list-qq-template-N
   -> (?qq-template-or-splice-N*)
    | (?qq-template-or-splice-N+ . ?qq-template-N)
    | ?quasiquotation-(N+1)

?vector-qq-template-N -> #(?qq-template-or-splice-N*)

?unquotation-N -> (unquote ?qq-template-(N-1))

?qq-template-or-splice-N
   -> ?qq-template-N
    | ?splicing-unquotation-N

?splicing-unquotation-N
   -> (unquote-splicing ?qq-template-(N-1)*)
    | (unquote ?qq-template-(N-1)*)

In quasiquotations, a ?list-qq-template-N can sometimes be confused with either an ?unquotation-N or a ?splicing-unquotation-N. The interpretation as an ?unquotation-N or ?splicing-unquotation-N takes precedence.


Next: , Previous: , Up: baselib   [Index]