[R6RS] syntax-case
Manuel Serrano
Manuel.Serrano
Mon Apr 11 10:04:34 EDT 2005
> Like syntax-rules, syntax-case is designed to make the specification
> of syntactic forms in the input and output as natural (free of
> matching noise) as possible while supporting the kind of extraction and
> recombination of syntactic elements that is common in macro transformers.
> In other words, it is designed to be essentially just as "high level"
> as syntax-rules.
>
> For comparison, here's letrec* with syntax-rules and syntax-case:
>
> (define-syntax letrec* (define-syntax letrec*
> (syntax-rules () (lambda (x)
> [(_ ((x e) ...) b1 b2 ...) (syntax-case x ()
> (let ((x (void)) ...) [(_ ((x e) ...) b1 b2 ...)
> (set! x e) ... #'(let ((x (void)) ...)
> (let () b1 b2 ...))])) (set! x e) ...
> (let () b1 b2 ...))])))
>
> Of course, syntax-case is also designed to be more expressive than
> syntax-rules, so it allows the output to be constructed by arbitrary
> Scheme code, with output templates embedded in "syntax" (#') forms.
> For example, here's a straightforward implementation of the r5rs letrec
> expansion using syntax-case. A syntax-rules macro producing the same
> output is more difficult to write and less transparent.
>
> (define-syntax letrec
> (lambda (x)
> (syntax-case x ()
> [(_ ((x e) ...) b1 b2 ...)
> (with-syntax ([(t ...) (generate-temporaries #'(x ...))])
> #'(let ((x (void)) ...)
> (let ((t e) ...)
> (set! x t) ...
> (let () b1 b2 ...))))])))
>
> The design is realized by the following characteristics that distinguish
> syntax-case from typical general-purpose matchers.
>
> * Pattern variables are not explicitly marked in an input pattern;
> instead, the set of literal identifiers, if any, is listed separately.
>
> Listing literals separately works well for syntactic abstractions,
> which tend to contain just a few closely related clauses and often
> require no literals. It does not work as well for general matching.
That's true. Would you consider adding a conventional special character
for marking non-literal as a burden? For instance, in Bigloo, we are
using "?". That is:
[(_ ((x e) ...) b1 b2 ...) <expression>]
is written
[(?- ((?x ?e) . ?rest1) ?b1 ?b2 . ?rest2) <expression>]
I agree that since in the context of macros most elements are pattern
variables, your syntax is nicer than the one deployed by a general pattern
matching syntax. However, my personal feeling is that the "?" mark is
not very intrusive nor error prone.
> * Neither pattern variables nor literal identifiers are explicitly
> marked in an output form; instead, pattern variables are distinguished
> from ordinary variables. The syntax form inserts the values of
> pattern variables into the output, while treating other identifiers,
> including other variables, as literal syntax. The syntax form also
> handles ellipses.
Isn't in contradiction with the fact that SYNTAX-CASE allows the output
to be constructed by arbitrary Scheme code. Is it correct to think that
everything works fine as long as the arbitrary code is a #'expression?
> To make this work in the general case, we'd need a non-syntax
> equivalent of the syntax form, in addition to the syntax form.
> (One possibility is to overload quasiquote for this purpose.
> Our matcher overloads quasiquote to handle ... in output forms;
> we could presumably teach it to handle pattern variables as well.)
I imagine that extending the definition of , and ,@ could do it. I will
try that.
> * Additional matching constraints, if any, are not embedded in the
> pattern; instead, they are specified via a "fender" that appears
> outside of the pattern.
>
> I prefer this (over an enriched input-pattern language) for
> general-purpose matching as well, but others probably do not.
I'm not familiar enough with your fender proposal to really understand
all the implications. In with context is evaluated the fender? Is it in a
context where all the pattern variables are bound to syntaxes? How would you
write an equivalent to:
[(+ (and (? integer?) ?v1) (and (? integer?) ?v2)) <expr>]
Would you write something such as:
[(_ e1 e2) (and (integer? (syntax-object->datum e1) (syntax-object->datum e2))) <expr>]
I think that I prefer the first syntax but I must admit that this is really
a matter of taste.
> In essence, syntax-case is a domain-specific pattern matcher for
> syntactic abstraction. If we can generalize it to serve as a suitable
> general-purpose matcher without making it clumsier for syntactic
> abstraction, great. If not, we shouldn't be shy about including both.
Sure. May I add that we should integrate both if the specialized pattern
matcher is far better (more elegant and concise I would say) than the general
pattern matcher.
--
Manuel
ps: The Bigloo MATCH-CASE form I'm frequently refering to is documented
at: http://www-sop.inria.fr/mimosa/fp/Bigloo/doc/bigloo-7.html
More information about the R6RS
mailing list