Syntactic Binding Constructs - MIT/GNU Scheme 7.7.90+
Description: MIT/GNU Scheme 7.7.90+

Next: Pattern Language, Previous: Macros, Up: Macros

#### 2.11.1 Binding Constructs for Syntactic Keywords

`let-syntax`, `letrec-syntax`, `let*-syntax` and `define-syntax` are analogous to `let`, `letrec`, `let*` and `define`, but they bind syntactic keywords to macro transformers instead of binding variables to locations that contain values.

Any argument named transformer-spec must be a macro-transformer expression, which is one of the following:

- A macro transformer defined by the pattern language and denoted by the syntactic keyword `syntax-rules`.
- A macro transformer defined by one of the low-level mechanisms and denoted by one of the syntactic keywords `sc-macro-transformer`, `rsc-macro-transformer`, or `er-macro-transformer`.
- A syntactic keyword bound in the enclosing environment. This is used to bind another name to an existing macro transformer.

— special form: let-syntax bindings expression expression ...

> Bindings should have the form

>               ((keyword transformer-spec) ...)

> Each keyword is an identifier, each transformer-spec is a a macro-transformer expression, and the body is a sequence of one or more expressions. It is an error for a keyword to appear more than once in the list of keywords being bound.

> The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the `let-syntax` expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the expressions as its region.

>               (let-syntax ((when (syntax-rules ()
>                                    ((when test stmt1 stmt2 ...)
>                                     (if test
>                                         (begin stmt1
>                                                stmt2 ...))))))
>                 (let ((if #t))
>                   (when if (set! if 'now))
>                   if))                           =>  now

>               (let ((x 'outer))
>                 (let-syntax ((m (syntax-rules () ((m) x))))
>                   (let ((x 'inner))
>                     (m))))                       =>  outer

— special form: letrec-syntax bindings expression expression ...

> The syntax of `letrec-syntax` is the same as for `let-syntax`.

> The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the `letrec-syntax` expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the bindings as well as the expressions within its region, so the transformers can transcribe expressions into uses of the macros introduced by the `letrec-syntax` expression.

>               (letrec-syntax
>                 ((my-or (syntax-rules ()
>                           ((my-or) #f)
>                           ((my-or e) e)
>                           ((my-or e1 e2 ...)
>                            (let ((temp e1))
>                              (if temp
>                                  temp
>                                  (my-or e2 ...)))))))
>                 (let ((x #f)
>                       (y 7)
>                       (temp 8)
>                       (let odd?)
>                       (if even?))
>                   (my-or x
>                          (let temp)
>                          (if y)
>                          y)))        =>  7

— special form: let*-syntax bindings expression expression ...

> The syntax of `let*-syntax` is the same as for `let-syntax`.

> The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the `letrec-syntax` expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the subsequent bindings as well as the expressions within its region. Thus

>               (let*-syntax
>                  ((a (syntax-rules ...))
>                   (b (syntax-rules ...)))
>                 ...)

> is equivalent to

>               (let-syntax ((a (syntax-rules ...)))
>                 (let-syntax ((b (syntax-rules ...)))
>                   ...))

— special form: define-syntax keyword transformer-spec

> Keyword is an identifier, and transformer-spec is a macro transformer expression. The syntactic environment is extended by binding the keyword to the specified transformer.

> The region of the binding introduced by `define-syntax` is the entire block in which it appears. However, the keyword may only be used after it has been defined.

> MIT/GNU Scheme permits `define-syntax` to appear both at top level and within `lambda` bodies. The Revised^4 Report permits only top-level uses of `define-syntax`.

> When compiling a program, a top-level instance of `define-syntax` both defines the syntactic keyword and generates code that will redefine the keyword when the program is loaded. This means that the same syntax can be used for defining macros that will be used during compilation and for defining macros to be used at run time.

> Although macros may expand into definitions and syntax definitions in any context that permits them, it is an error for a definition or syntax definition to shadow a syntactic keyword whose meaning is needed to determine whether some form in the group of forms that contains the shadowing definition is in fact a definition, or, for internal definitions, is needed to determine the boundary between the group and the expressions that follow the group. For example, the following are errors:

>               (define define 3)

>               (begin (define begin list))

>               (let-syntax
>                 ((foo (syntax-rules ()
>                         ((foo (proc args ...) body ...)
>                          (define proc
>                            (lambda (args ...)
>                              body ...))))))
>                 (let ((x 3))
>                   (foo (plus x y) (+ x y))
>                   (define foo x)
>                   (plus foo x)))