[R6RS] syntax-case

R. Kent Dybvig dyb
Wed Oct 20 00:12:30 EDT 2004


> > I agree in principle and would be happy to work with you on this,
> > but there are some fundamental differences between syntax-case and
> > general-purpose matchers like match-case that might prevent their
> > unification.

> Can you elaborate on this.  I'm not sure what you are refering to.

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.

  * 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.

    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.)

  * 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.

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.

Kent


More information about the R6RS mailing list