macrosschemer5rs

Use of literals in hygienic macros in Scheme


In the Scheme language (let's take R5RS as a language reference) hygienic macros can be defined amongst others with the construct (define-syntax <keyword> <transformer>) where <keyword> is the name of the macro and <transformer> describes the <pattern> the macro will match and a <template> describes how that pattern should be transformed. The <transformer> has the following form: (syntax-rules <literals> <syntax-rule> ...) and each <syntax-rule> is of the form (<pattern> <template>).

For example:

(define-syntax swap
  (syntax-rules ()
      (; pattern to be matched:
       (swap x y)
       ; template the pattern will get replaced by:
       (let ((tmp x))
         (set! x y)
         (set! y tmp)))))

However, it is also allowed to specify some <literals> as part of the syntax-rules declaration. I understand from the language specification that any identifier that appears in the <pattern> of a <syntax-rule> is a pattern variable, unless it is the <keyword> that begins the pattern, or is listed in <literals>, or is the identifier .... Pattern variables match arbitrary input elements and are used to refer back in the template to elements of the input matched in the pattern. Identifiers that appear in <literals> however are interpreted as literal identifiers to be matched against corresponding subforms of the input.

In practice, in almost all of the examples that one can find this list of literals () is kept empty (as in the example above).

Can someone provide me with a simple example that illustrates the relevance of having such literals. In what realistic use-case would it make sense to have such literals? A concrete and simple example would be helpful.


Solution

  • You can create "within-fix" expression syntaxes.
    Silly example:

    (define-syntax swap
      (syntax-rules (with unless)
           (swap x with y unless c)
           (when (not c)
             (let ((tmp x))
               (set! x y)
               (set! y tmp))))))
    

    Test:

    > (define a 1)
    > (define b 2)
    > (swap a with b unless (< a b))
    > a
    1
    > b
    2
    > (swap a with b unless (< b a))
    > a
    2
    > b
    1