[plt-scheme] 299.11

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Fri Jul 2 16:09:51 EDT 2004

The v299-tagged code in CVS for MzScheme and MrEd is now version 299.11.
(The exp-tagged code is still version 207.1.)

I've finally added `begin-for-syntax' and `require-for-template', which
let you modularize macro implementations more nicely.

Here's an example (adapted from the manual) showing a problem that
macro implementors often encounter:

 (module et mzscheme
   (define (mx) #'700)
   (provide mx))

 (module m mzscheme
   (require-for-syntax et)
   (define-syntax (onem stx) (mx))
   (printf "~a~n" (onem)))   ; prints 700 when run?  No, ...

The use of `onem' doesn't work, because the `et' module has no bindings
that correspond to the run time of `m'. As a result, the compiler can't
make sense of the expression `700' that is generated by expanding
`(onem)'.

Before 299.10, the solution was to pass identifiers or other context
into `mx'. Now, the problem can be solved by simply adding a
`require-for-template' in `et':

 (module et mzscheme
   (require-for-template mzscheme) ; introduces a binding for the `#%datum'
                                   ; that lives in the future (relative to
                                   ; this module's run time)
   (define (mx) #'700)
   (provide mx))

 (module m mzscheme
   (require-for-syntax et)
   (define-syntax (onem stx) (mx))
   (printf "~a~n" (onem)))   ; prints 700 when run

Alternatively, the implementor of `m' might not want another module.
Maybe the implementor merely wanted a helper `mx' to use in several
macros within `m'. In that case, the `begin-for-syntax' form offers a
better solution:

 (module m mzscheme
   (begin-for-syntax
     (define (mx) #'700))
   (define-syntax (onem stx) (mx))
   (printf "~a~n" (onem)))   ; prints 700 when run

Technically, `begin-for-syntax' is a macro that turns `define-values'
declarations into `define-values-for-syntax', and the latter is a core
form. The `begin-for-syntax' form also turns `require' into
`require-for-syntax' and `require-for-template' into `require'.

To complete the set, `define-for-syntax' expands into
`define-values-for-syntaxes'. So the above can also be written

 (module m mzscheme
   (define-for-syntax (mx) #'700)
   (define-syntax (onem stx) (mx))
   (printf "~a~n" (onem)))   ; prints 700 when run


There's no `provide-for-syntax' or `require-for-syntax-for-syntax', so
there's also no `define-syntax-for-syntax' (which wouldn't be useful
without at least one of the other two). Similarly, it's no use to put
`begin-for-syntax' inside `begin-for-syntax'.

In the future, I may change MzScheme so that the core forms are
`begin-for-syntax' and `begin-for-template', and so they can be nested
arbitrarily. Then, a single module could contain definitions for
arbitrarily many different phases ("past" and "future").

But I think that we'll get pretty far with just `require-for-template'
and a restrictive `begin-for-syntax'. In any case, the current system
is a convenient stop on the way to the most general one.

----------------------------------------

Changes:

 * New forms:
     `require-for-template' [core form]
     `define-values-for-syntax' [core form]
     `define-for-syntax'
     `begin-for-syntax'

 * New procedures:
     `local-transformer-expand'
     `syntax-transforming?'

 * `module-compiled-imports' now returns 3 values

 * `identifier-binding' and `identifier-transformer-binding' return a
   list of five items instead of four, in the case of a module-bound
   identifier.

 * Added an optional argument to `make-input-port' to support custom
   line counting.

Temporary docs are in the usual place:

  http://www.cs.utah.edu/~mflatt/tmp/mzscheme-doc.plt
  http://www.cs.utah.edu/~mflatt/tmp/mzlib-doc.plt
  http://www.cs.utah.edu/~mflatt/tmp/mred-doc.plt


Matthew



Posted on the users mailing list.