SC Transformer Definition (MIT/GNU Scheme 10.1.6)

Next: SC Identifiers, Previous: Syntax Terminology, Up: Syntactic Closures [Contents][Index]

#### 2.11.3.2 Transformer Definition

This section describes the special forms for defining syntactic-closures macro transformers, and the associated procedures for manipulating syntactic closures and syntactic environments.

special form: sc-macro-transformer expression

  The expression is expanded in the syntactic environment of the `sc-macro-transformer` expression, and the expanded expression is evaluated in the transformer environment to yield a macro transformer as described below. This macro transformer is bound to a macro keyword by the special form in which the `transformer` expression appears (for example, `let-syntax`).

  In the syntactic closures facility, a macro transformer is a procedure that takes two arguments, a form and a syntactic environment, and returns a new form. The first argument, the input form, is the form in which the macro keyword occurred. The second argument, the usage environment, is the syntactic environment in which the input form occurred. The result of the transformer, the output form, is automatically closed in the transformer environment, which is the syntactic environment in which the `transformer` expression occurred.

  For example, here is a definition of a `push` macro using `syntax-rules`:

      (define-syntax push
        (syntax-rules ()
          ((push item list)
           (set! list (cons item list)))))

  Here is an equivalent definition using `sc-macro-transformer`:

      (define-syntax push
        (sc-macro-transformer
         (lambda (exp env)
           (let ((item (make-syntactic-closure env '() (cadr exp)))
                 (list (make-syntactic-closure env '() (caddr exp))))
             `(set! ,list (cons ,item ,list))))))

  In this example, the identifiers `set!` and `cons` are closed in the transformer environment, and thus will not be affected by the meanings of those identifiers in the usage environment `env`.

  Some macros may be non-hygienic by design. For example, the following defines a `loop` macro that implicitly binds `exit` to an escape procedure. The binding of `exit` is intended to capture free references to `exit` in the body of the loop, so `exit` must be left free when the body is closed:

      (define-syntax loop
        (sc-macro-transformer
         (lambda (exp env)
           (let ((body (cdr exp)))
             `(call-with-current-continuation
               (lambda (exit)
                 (let f ()
                   ,@(map (lambda (exp)
                            (make-syntactic-closure env '(exit)
                              exp))
                          body)
                   (f))))))))

special form: rsc-macro-transformer expression

  This form is an alternative way to define a syntactic-closures macro transformer. Its syntax and usage are identical to `sc-macro-transformer`, except that the roles of the usage environment and transformer environment are reversed. (Hence RSC stands for Reversed Syntactic Closures.) In other words, the procedure specified by expression still accepts two arguments, but its second argument will be the transformer environment rather than the usage environment, and the returned expression is closed in the usage environment rather than the transformer environment.

  The advantage of this arrangement is that it allows a simpler definition style in some situations. For example, here is the `push` macro from above, rewritten in this style:

      (define-syntax push
        (rsc-macro-transformer
         (lambda (exp env)
           `(,(make-syntactic-closure env '() 'SET!)
             ,(caddr exp)
             (,(make-syntactic-closure env '() 'CONS)
              ,(cadr exp)
              ,(caddr exp))))))

  In this style only the introduced keywords are closed, while everything else remains open.

  Note that `rsc-macro-transformer` and `sc-macro-transformer` are easily interchangeable. Here is how to emulate `rsc-macro-transformer` using `sc-macro-transformer`. (This technique can be used to effect the opposite emulation as well.)

      (define-syntax push
        (sc-macro-transformer
         (lambda (exp usage-env)
           (capture-syntactic-environment
            (lambda (env)
              (make-syntactic-closure usage-env '()
                `(,(make-syntactic-closure env '() 'SET!)
                  ,(caddr exp)
                  (,(make-syntactic-closure env '() 'CONS)
                   ,(cadr exp)
                   ,(caddr exp)))))))))

To assign meanings to the identifiers in a form, use `make-syntactic-closure` to close the form in a syntactic environment.

procedure: make-syntactic-closure environment free-names form

  Environment must be a syntactic environment, free-names must be a list of identifiers, and form must be a form. `make-syntactic-closure` constructs and returns a syntactic closure of form in environment, which can be used anywhere that form could have been used. All the identifiers used in form, except those explicitly excepted by free-names, obtain their meanings from environment.

  Here is an example where free-names is something other than the empty list. It is instructive to compare the use of free-names in this example with its use in the `loop` example above: the examples are similar except for the source of the identifier being left free.

      (define-syntax let1
        (sc-macro-transformer
         (lambda (exp env)
           (let ((id (cadr exp))
                 (init (caddr exp))
                 (exp (cadddr exp)))
             `((lambda (,id)
                 ,(make-syntactic-closure env (list id) exp))
               ,(make-syntactic-closure env '() init))))))

  `let1` is a simplified version of `let` that only binds a single identifier, and whose body consists of a single expression. When the body expression is syntactically closed in its original syntactic environment, the identifier that is to be bound by `let1` must be left free, so that it can be properly captured by the `lambda` in the output form.

In most situations, the free-names argument to `make-syntactic-closure` is the empty list. In those cases, the more succinct `close-syntax` can be used:

procedure: close-syntax form environment

  Environment must be a syntactic environment and form must be a form. Returns a new syntactic closure of form in environment, with no free names. Entirely equivalent to

      (make-syntactic-closure environment '() form)

To obtain a syntactic environment other than the usage environment, use `capture-syntactic-environment`.

procedure: capture-syntactic-environment procedure

  `capture-syntactic-environment` returns a form that will, when transformed, call procedure on the current syntactic environment. Procedure should compute and return a new form to be transformed, in that same syntactic environment, in place of the form.

  An example will make this clear. Suppose we wanted to define a simple `loop-until` keyword equivalent to

      (define-syntax loop-until
        (syntax-rules ()
          ((loop-until id init test return step)
           (letrec ((loop
                     (lambda (id)
                       (if test return (loop step)))))
             (loop init)))))

  The following attempt at defining `loop-until` has a subtle bug:

      (define-syntax loop-until
        (sc-macro-transformer
         (lambda (exp env)
           (let ((id (cadr exp))
                 (init (caddr exp))
                 (test (cadddr exp))
                 (return (cadddr (cdr exp)))
                 (step (cadddr (cddr exp)))
                 (close
                  (lambda (exp free)
                    (make-syntactic-closure env free exp))))
             `(letrec ((loop
                        (lambda (,id)
                          (if ,(close test (list id))
                              ,(close return (list id))
                              (loop ,(close step (list id)))))))
                (loop ,(close init '())))))))

  This definition appears to take all of the proper precautions to prevent unintended captures. It carefully closes the subexpressions in their original syntactic environment and it leaves the `id` identifier free in the `test`, `return`, and `step` expressions, so that it will be captured by the binding introduced by the `lambda` expression. Unfortunately it uses the identifiers `if` and `loop` within that `lambda` expression, so if the user of `loop-until` just happens to use, say, `if` for the identifier, it will be inadvertently captured.

  The syntactic environment that `if` and `loop` want to be exposed to is the one just outside the `lambda` expression: before the user’s identifier is added to the syntactic environment, but after the identifier `loop` has been added. `capture-syntactic-environment` captures exactly that environment as follows:

      (define-syntax loop-until
        (sc-macro-transformer
         (lambda (exp env)
           (let ((id (cadr exp))
                 (init (caddr exp))
                 (test (cadddr exp))
                 (return (cadddr (cdr exp)))
                 (step (cadddr (cddr exp)))
                 (close
                  (lambda (exp free)
                    (make-syntactic-closure env free exp))))
             `(letrec ((loop
                        ,(capture-syntactic-environment
                          (lambda (env)
                            `(lambda (,id)
                               (,(make-syntactic-closure env '() `if)
                                ,(close test (list id))
                                ,(close return (list id))
                                (,(make-syntactic-closure env '() `loop)
                                 ,(close step (list id)))))))))
                (loop ,(close init '())))))))

  In this case, having captured the desired syntactic environment, it is convenient to construct syntactic closures of the identifiers `if` and the `loop` and use them in the body of the `lambda`.

  A common use of `capture-syntactic-environment` is to get the transformer environment of a macro transformer:

      (sc-macro-transformer
       (lambda (exp env)
         (capture-syntactic-environment
          (lambda (transformer-env)
            …))))

Next: SC Identifiers, Previous: Syntax Terminology, Up: Syntactic Closures [Contents][Index]