5.5 KiB
Quasiquoting: quasiquote
and ‘
+[missing] in [missing] also documents
quasiquote
.
The quasiquote
form is similar to quote
:
(quasiquote datum)
However, for each (unquote expr)
that appears within the datum
, the
expr
is evaluated to produce a value that takes the place of the
unquote
sub-form.
Example:
> (quasiquote (1 2 (unquote (+ 1 2)) (unquote (- 5 1))))
'(1 2 3 4)
This form can be used to write functions that build lists according to certain patterns.
Examples:
> (define (deep n)
(cond
[(zero? n) 0]
[else
(quasiquote ((unquote n) (unquote (deep (- n 1)))))]))
> (deep 8)
'(8 (7 (6 (5 (4 (3 (2 (1 0))))))))
Or even to cheaply construct expressions programmatically. (Of course, 9 times out of 10, you should be using a macro to do this (the 10th time being when you’re working through a textbook like PLAI).)
Examples:
> (define (build-exp n)
(add-lets n (make-sum n)))
> (define (add-lets n body)
(cond
[(zero? n) body]
[else
(quasiquote
(let ([(unquote (n->var n)) (unquote n)])
(unquote (add-lets (- n 1) body))))]))
> (define (make-sum n)
(cond
[(= n 1) (n->var 1)]
[else
(quasiquote (+ (unquote (n->var n))
(unquote (make-sum (- n 1)))))]))
> (define (n->var n) (string->symbol (format "x~a" n)))
> (build-exp 3)
'(let ((x3 3)) (let ((x2 2)) (let ((x1 1)) (+ x3 (+ x2 x1)))))
The unquote-splicing
form is similar to unquote
, but its expr
must
produce a list, and the unquote-splicing
form must appear in a context
that produces either a list or a vector. As the name suggests, the
resulting list is spliced into the context of its use.
Example:
> (quasiquote (1 2 (unquote-splicing (list (+ 1 2) (- 5 1))) 5))
'(1 2 3 4 5)
Using splicing we can revise the construction of our example expressions
above to have just a single let
expression and a single +
expression.
Examples:
> (define (build-exp n)
(add-lets
n
(quasiquote (+ (unquote-splicing
(build-list
n
(λ (x) (n->var (+ x 1)))))))))
> (define (add-lets n body)
(quasiquote
(let (unquote
(build-list
n
(λ (n)
(quasiquote
[(unquote (n->var (+ n 1))) (unquote (+ n 1))]))))
(unquote body))))
> (define (n->var n) (string->symbol (format "x~a" n)))
> (build-exp 3)
'(let ((x1 1) (x2 2) (x3 3)) (+ x1 x2 x3))
If a quasiquote
form appears within an enclosing quasiquote
form,
then the inner quasiquote
effectively cancels one layer of unquote
and unquote-splicing
forms, so that a second unquote
or
unquote-splicing
is needed.
Examples:
> (quasiquote (1 2 (quasiquote (unquote (+ 1 2)))))
'(1 2 (quasiquote (unquote (+ 1 2))))
> (quasiquote (1 2 (quasiquote (unquote (unquote (+ 1 2))))))
'(1 2 (quasiquote (unquote 3)))
>
(quasiquote (1 2 (quasiquote ((unquote (+ 1 2)) (unquote (unquote (- 5 1)))))))
'(1 2 (quasiquote ((unquote (+ 1 2)) (unquote 4))))
The evaluations above will not actually print as shown. Instead, the
shorthand form of quasiquote
and unquote
will be used: \(i.e., a backquote\) and
,` i.e., a comma
. The same shorthands can be used
in expressions:
Example:
> `(1 2 `(,(+ 1 2) ,,(- 5 1)))
'(1 2 `(,(+ 1 2) ,4))
The shorthand form of unquote-splicing
is ,@
:
Example:
> `(1 2 ,@(list (+ 1 2) (- 5 1)))
'(1 2 3 4)