6.8.1 Defining Macros

A macro is a binding between a keyword and a syntax transformer. Since it’s difficult to discuss define-syntax without discussing the format of transformers, consider the following example macro definition:

(define-syntax when
  (syntax-rules ()
    ((when condition exp ...)
     (if condition
         (begin exp ...)))))

(when #t
  (display "hey ho\n")
  (display "let's go\n"))
-| hey ho
-| let's go

In this example, the when binding is bound with define-syntax. Syntax transformers are discussed in more depth in Syntax-rules Macros and Support for the syntax-case System.

Syntax: define-syntax keyword transformer

Bind keyword to the syntax transformer obtained by evaluating transformer.

After a macro has been defined, further instances of keyword in Scheme source code will invoke the syntax transformer defined by transformer.

One can also establish local syntactic bindings with let-syntax.

Syntax: let-syntax ((keyword transformer) …) exp1 exp2 …

Bind each keyword to its corresponding transformer while expanding exp1 exp2 ....

A let-syntax binding only exists at expansion-time.

(let-syntax ((unless
              (syntax-rules ()
                ((unless condition exp ...)
                 (if (not condition)
                     (begin exp ...))))))
  (unless #t
    (primitive-exit 1))
  "rock rock rock")
⇒ "rock rock rock"

A define-syntax form is valid anywhere a definition may appear: at the top-level, or locally. Just as a local define expands out to an instance of letrec, a local define-syntax expands out to letrec-syntax.

Syntax: letrec-syntax ((keyword transformer) …) exp1 exp2 …

Bind each keyword to its corresponding transformer while expanding exp1 exp2 ....

In the spirit of letrec versus let, an expansion produced by transformer may reference a keyword bound by the same letrec-syntax.

(letrec-syntax ((my-or
                 (syntax-rules ()
                   ((my-or)
                    #t)
                   ((my-or exp)
                    exp)
                   ((my-or exp rest ...)
                    (let ((t exp))
                      (if t
                          t
                          (my-or rest ...)))))))
  (my-or #f "rockaway beach"))
⇒ "rockaway beach"