Next: stdlib syntax-case violations, Previous: stdlib syntax-case temporaries, Up: stdlib syntax-case [Index]
The forms and procedures described in this section can be defined in terms of the forms and procedures described in earlier sections of this chapter.
The with-syntax
form is used to bind pattern variables, just as
let
is used to bind variables. This allows a transformer to
construct its output in separate pieces, then put the pieces together.
Each ?pattern is identical in form to a syntax-case
pattern. The value of each ?expression is computed and
destructured according to the corresponding ?pattern, and pattern
variables within the ?pattern are bound as with
syntax-case
to the corresponding portions of the value within
?body.
The with-syntax
form may be defined in terms of
syntax-case
as follows.
(define-syntax with-syntax (lambda (x) (syntax-case x () ((_ ((p e0) ...) e1 e2 ...) (syntax (syntax-case (list e0 ...) () ((p ...) (let () e1 e2 ...))))))))
As example of deconstructing a syntax object:
(define stx (datum->syntax #'display '(1 2 3))) (with-syntax (((a b ...) stx)) (syntax->datum #'a)) ⇒ 1
The following definition of cond
demonstrates the use of
with-syntax
to support transformers that employ recursion
internally to construct their output. It handles all cond
clause
variations and takes care to produce one-armed if
expressions
where appropriate.
(define-syntax cond (lambda (x) (syntax-case x () ((_ c1 c2 ...) (let f ((c1 #'c1) (c2* #'(c2 ...))) (syntax-case c2* () (() (syntax-case c1 (else =>) ((else e1 e2 ...) #'(begin e1 e2 ...)) ((e0) #'e0) ((e0 => e1) #'(let ((t e0)) (if t (e1 t)))) ((e0 e1 e2 ...) #'(if e0 (begin e1 e2 ...))))) ((c2 c3 ...) (with-syntax ((rest (f #'c2 #'(c3 ...)))) (syntax-case c1 (=>) ((e0) #'(let ((t e0)) (if t t rest))) ((e0 => e1) #'(let ((t e0)) (if t (e1 t) rest))) ((e0 e1 e2 ...) #'(if e0 (begin e1 e2 ...) rest)))))))))))
The quasisyntax
form is similar to syntax
, but it allows
parts of the quoted text to be evaluated, in a manner similar to the
operation of quasiquote
(see baselib quasiquotation).
Within a quasisyntax
template, subforms of unsyntax
and unsyntax-splicing
forms are evaluated, and everything else is
treated as ordinary template material, as with syntax
.
The value of each unsyntax
subform is inserted into the output in
place of the unsyntax
form, while the value of each
unsyntax-splicing
subform is spliced into the surrounding list or
vector structure. Uses of unsyntax
and unsyntax-splicing
are valid only within quasisyntax
expressions.
A quasisyntax
expression may be nested, with each
quasisyntax
introducing a new level of syntax quotation and each
unsyntax
or unsyntax-splicing
taking away a level of
quotation. An expression nested within n quasisyntax
expressions must be within n unsyntax
or
unsyntax-splicing
expressions to be evaluated.
As noted in scheme lex datum abbreviations:
#`?template ≡ (quasisyntax ?template) #,?template ≡ (unsyntax ?template) #,@?template ≡ (unsyntax-splicing ?template)
The quasisyntax
keyword can be used in place of
with-syntax
in many cases. For example, the definition of
case
shown under the description of with-syntax
above can
be rewritten using quasisyntax
as follows.
(define-syntax case (lambda (x) (syntax-case x () ((_ e c1 c2 ...) #`(let ((t e)) #,(let f ((c1 #'c1) (cmore #'(c2 ...))) (if (null? cmore) (syntax-case c1 (else) ((else e1 e2 ...) #'(begin e1 e2 ...)) (((k ...) e1 e2 ...) #'(when (memv t '(k ...)) (begin e1 e2 ...)))) (syntax-case c1 () (((k ...) e1 e2 ...) #`(if (memv t '(k ...)) (begin e1 e2 ...) #,(f (car cmore) (cdr cmore))))))))))))
Uses of unsyntax
and unsyntax-splicing
with zero or more
than one subform are valid only in splicing (list or vector) contexts.
(unsyntax template …)
is equivalent to
(unsyntax template) ...
, and (unsyntax-splicing
template ...)
is equivalent to (unsyntax-splicing
template) ...
. These forms are primarily useful as intermediate
forms in the output of the quasisyntax
expander.
NOTE Uses of
unsyntax
andunsyntax-splicing
with zero or more than one subform enable certain idioms, such as ‘#,@#,@’, which has the effect of a doubly indirect splicing when used within a doubly nested and doubly evaluatedquasisyntax
expression, as with the nestedquasiquote
examples shown in section baselib quasiquotation.
Next: stdlib syntax-case violations, Previous: stdlib syntax-case temporaries, Up: stdlib syntax-case [Index]