3.4 Expression Wrapper: #%expression
syntax
(#%expression expr)
Produces the same result as expr. Using
#%expression forces the parsing of a form as an
expression.
Examples:
> (#%expression (+ 1 2)) 3
> (#%expression (define x 10)) eval:8:0: define: not allowed in an expression context
in: (define x 10)
The #%expression form is helpful in recursive definition contexts
where expanding a subsequent definition can provide compile-time information
for the current expression. For example, consider a define-sym-case
macro that simply records some symbols at compile-time in a given identifier.
(define-syntax (define-sym-case stx) (syntax-case stx () [(_ id sym ...) (andmap identifier? (syntax->list #'(sym ...))) #'(define-syntax id '(sym ...))]))
and then a variant of case that checks to make sure the symbols
used in the expression match those given in the earlier definition:
(define-syntax (sym-case stx) (syntax-case stx () [(_ id val-expr [(sym) expr] ...) (let () (define expected-ids (syntax-local-value #'id (λ () (raise-syntax-error 'sym-case "expected an identifier bound via def-sym-case" stx #'id)))) (define actual-ids (syntax->datum #'(sym ...))) (unless (equal? expected-ids actual-ids) (raise-syntax-error 'sym-case (format "expected the symbols ~s" expected-ids) stx)) #'(case val-expr [(sym) expr] ...))]))
If the definition follows the use like this, then
the define-sym-case macro does not have
a chance to bind id and the sym-case
macro signals an error:
> (let () (sym-case land-creatures 'bear [(bear) 1] [(fox) 2]) (define-sym-case land-creatures bear fox)) eval:11:0: sym-case: expected an identifier bound via
def-sym-case
at: land-creatures
in: (sym-case land-creatures (quote bear) ((bear) 1)
((fox) 2))
But if the sym-case is wrapped in an #%expression,
then the expander does not need to expand it to know it is
an expression and it moves on to the define-sym-case
expression.
> (let () (#%expression (sym-case sea-creatures 'whale [(whale) 1] [(squid) 2])) (define-sym-case sea-creatures whale squid) 'more...) 'more...
Of course, a macro like sym-case should not require its
clients to add #%expression; instead it should check
the basic shape of its arguments and then expand to #%expression
wrapped around a helper macro that calls syntax-local-value
and finishes the expansion.