Next: , Up: Macros


6.10.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 and Syntax Case.

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

Bind keyword... to transformer... while expanding exp....

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

Bind keyword... to transformer... while expanding exp....

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 exp
                                    exp
                                    (my-or rest ...)))))))
            (my-or #f "rockaway beach"))
          ⇒ "rockaway beach"