3.1 Subforms and Keywords
Synopsis: How to represent special subforms and write macros that interpret them.
Examples: cond and else; class and public, init, etc
3.1.1 By-binding keywords
(define-syntax (else stx) |
(raise-syntax-error #f "not allowed as an expression" stx)) |
Macros recognize by-binding keywords explicitly using free-identifier=? or implicitly using the “literals list” of syntax-rules or syntax-case.
Here’s an example of a “capricious conditional” macro that has two special subforms: the standard else clause and a perhaps clause that randomly decides whether to succeed or fail.
(module capcond scheme/base |
(require (for-syntax scheme/base)) |
(provide perhaps capcond) |
(define-syntax (perhaps stx) |
(raise-syntax-error #f "not allowed as an expression" stx)) |
(define-syntax capcond |
(syntax-rules (else perhaps) |
[(capcond) |
(void)] |
[(capcond [else answer]) |
answer] |
[(capcond [perhaps answer] . clauses) |
(if (zero? (random 2)) |
answer |
(capcond . clauses))] |
[(capcond [question answer] . clauses) |
(if question |
answer |
(capcond . clauses))]))) |
It is important for the else and perhaps patterns to occur before the final question pattern. It is also important for perhaps to be provided along with capcond. If perhaps were not provided, then users of capcond in other modules would have no way of writing a perhaps clause. Whatever the local binding of perhaps might be, it would not be the same binding as the one expected by the capcond macro.
Connection: In the example above, a keyword identifier carries no information other than its identity: else is distinct from perhaps, and both are distinct from any definition or expression forms. It is possible to make the keyword identifier itself carry information; this idea leads to the Static Information pattern.
3.1.2 By-name keywords and other alternatives
Recognizing keywords by binding avoids ambiguity and makes keyword identifiers subject to manipulation by standard scoping mechanisms (module import, export, and renaming; and local shadowing). On the other hand, when there is no chance of ambiguity, recognizing keywords by name makes reserving the keywords unnecessary and reduces competition for the limited number of short, apt names. For example, the keywords that tag the #%require form’s raw require spec variants are recognized by name.
Another idiomatic approach is to use actual syntactic keywords (not identifiers) to delineate special subforms.