In Racket 7, the syntax form supports two new template subforms:
~@ (“splice”) splices the result of its subtemplate (which must
produce a syntax list) into the enclosing list template, and
~? (“try”) chooses between alternative subtemplates depending
on whether their pattern variables have “absent” values.
These features originated in syntax/parse/experimental/template:
the template form was like an extended version of syntax, and
?@ and ?? were the splicing forms and the try/else template
forms, respectively. The names were changed to ~@ and ~? to
avoid name collisions with other libraries. In Racket 7, the old
syntax/parse/experimental/template library just exports the new
standard forms under the old names (that is, it exports syntax under
the name template, and so on).
In my
last post, I talked about macros and referential auxiliary
identifiers—what we usually call a macro’s “literals.” Scheme
macro systems only get it half right, though, because while they
compare identifiers using referential equality (i.e., using the
free-identifier=? predicate), they allow literals to refer to
nonexistent bindings. While the comparison is well-defined via the
definition of free-identifier=?, at a higher level the idea
is nonsensical.
In contrast, syntax-parse requires that every literal
refer to some binding. (I’ll sometimes refer to this requirement as
the is-bound property for short.) This requirement is
problematic in a different way. Specifically, this property cannot be
checked statically (that is, when the syntax-parse expression
containing the literal is compiled).
Macros often have associated auxiliary identifiers (sometimes called
keywords or reserved words, although both terms are
problematic in Racket). For example, cond has else;
class has public, private, etc;
unit has import and export.
The fundamental question is what constitutes a use of an auxiliary
identifier, and there are two reasonable answers: symbolic
equality and referential equality. By symbolic equality I
mean, for example, that any identifier written with exactly the
letters else is accepted as an else auxiliary form. By
referential equality I mean any identifier that refers to
(using the standard notions of binding, environments, etc) the binding
identified as the else binding.
Danny Yoo had an interesting question on the plt-scheme mailing list
recently. At first it seemed like your standard non-hygienic, “I want
this to mean something in here” macro question. I used to group
macros into three levels of “hygienicness”: the hygienic ones, the
ones that are morally hygienic in that the names they introduce are
based on their input, and the totally non-hygienic ones that have a
fixed name that they stick into the program. An example of the middle
set is define-struct, and an example of the third set is a
loop construct that binds the name yield in its body.
The third class used to offend me from a purist’s (semi-purist?)
perspective. But it’s a very reasonable thing to want to do. Consider
the class macro and the names it uses to do interesting
things: super, public, field,
init, and so on. It depends on those particular names.
Copyright 2006–2020 Ryan Culpepper.
This work is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International License.