1.2.2 Optional Keyword Arguments
This section explains how to write a macro that accepts (simple)
optional keyword arguments. We use the example mycond, which
is like Racket’s cond except that it takes an optional
keyword argument that controls what happens if none of the clauses
Optional keyword arguments are supported via head
patterns. Unlike normal patterns, which match one term, head patterns
can match a variable number of subterms in a list. Some important
head-pattern forms are ~seq, ~or*, and
Here’s one way to do it:
|> (define-syntax mycond*|
| (syntax-rules ()|
| [(mycond error? who [question answer] . clauses)|
| (if question answer (mycond* error? who . clauses))]|
| [(mycond #t who)|
| (error who "no clauses matched")]|
| [(mycond #f _)|
We cannot simply write #'who in the macro’s right-hand side,
because the who attribute does not receive a value if the
keyword argument is omitted. Instead we must first check the attribute
using (attribute who), which produces #f if matching
did not assign a value to the attribute.
|> (mycond [(even? 13) 'blue]|
| [(odd? 4) 'red])|
|> (mycond #:error-on-fallthrough 'myfun|
| [(even? 13) 'blue]|
| [(odd? 4) 'red])|
myfun: no clauses matched
There’s a simpler way of writing the ~or*
22.214.171.124 Optional Arguments with ~?
The ~? template form provides a compact alternative to
explicitly testing attribute values. Here’s one way to do it:
If who matched, then the ~? subtemplate splices in
the two terms #t who into the enclosing template ([email protected]
is the template splicing form). Otherwise, it splices in #f #f.
Here’s an alternative definition that re-uses Racket’s cond macro:
In this version, we optionally insert an else clause at the
end to signal the error; otherwise we use cond’s fall-through
behavior (that is, returning (void)).
If the second subtemplate of a ~? template is
([email protected])—that is, it produces no terms at all—the second
subtemplate can be omitted.
Yet another way is to introduce a splicing syntax class, which
is like an ordinary syntax class but for head patterns.
Defining a splicing syntax class also makes it easy to eliminate the
case analysis we did before using attribute by defining
error? and who as attributes within both of the
syntax class’s variants. This is possible to do in the inline pattern
version too, using ~and and ~parse, but it is less
convenient. Splicing syntax classes also closely parallel the style of
grammars in macro documentation.