Use of literals in hygienic macros in Scheme

113 Views Asked by At

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.

2

There are 2 best solutions below

5
molbdnilo On BEST ANSWER

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
2
Sylwester On

The literals list is to get symbols to be treated the same way as strings. Eg. in this example only the string "hello" as the first argument will match the rule:

(define-syntax example
  (syntax-rules ()
    [(test "hello" ...) (...)]))

However if we switch this to match a symbol:

(define-syntax example
  (syntax-rules ()
    [(test hello ...) (...)]))

Then this will actually match the same as the previous string example since a symbol matches ANY data token and binds it. If we want it only to match the symbol hello we add it to the literals list:

(define-syntax example
  (syntax-rules (hello)
    [(test hello ...) (...)]))

You can use hello in the expansion and in the case hello is a bound variable it will be the same variable that just happens to be named hello. Because of this we can break hygiene in syntax-rules as demonstrated by Oleg's paper (PDF).