[racket-dev] submodules and local-expand

From: Sam Tobin-Hochstadt (samth at ccs.neu.edu)
Date: Wed Jun 6 13:32:19 EDT 2012

I think the current semantics of submodules doesn't work for Typed
Racket, and in general for the technique described in "Language as
Libraries", but we can fix it easily.

In particular, consider a language that lets you statically assert
that an identifier is bound to 5, so that this program is a static
error:

   #lang five
   (define f 6)
   (assert5 f)

Now, we can let our language, using `#%module-begin`, record
information about what identifiers are bound to 5, inserting updates
to a compile-time table after analyzing the fully-expanded module
body.  So this program:

   #lang five
   (define g 5)
   (provide g)

expands to, roughly:

   (module racket
     (define-values (g) '5)
     (provide g)
     (begin-for-syntax (declare-5! #'g)))

However, when we add submodules, in particular submodules declared
with `module*`, things go wrong:

   #lang five
   (define g 5)
   (module* m #f (assert5 g))

Now, we're going to check that `g` is bound to 5 in the inner module
during the local-expansion of the outer module, which is *before*
we've inserted the declaration that `g` is bound to 5.  So we're in
trouble.

What we'd like to do is to change our expansion to not expand the
submodules, in particular `module*` submodules, until we're done with
processing the main module.  This would be in keeping with the way
that module dependencies are usually expanded.  However, we can't just
add `module*` to the stop list at the moment, because if anything is
in the stop list, then all the core forms are added, and then we
wouldn't fully expand the program.

However, I think we can relax this restriction in the case of
`module*`.  In particular, if the stop list contains *only* `module*`,
then we should avoid adding the other core forms.  This is safe
because the submodule is intentionally "later" than the rest of the
module, and so we don't run into the binding and renaming issues that
motivated this restriction in the first place.  And then our `five`
language can avoid expanding `module*` submodules, and not worry about
anything else.
-- 
sam th
samth at ccs.neu.edu

Posted on the dev mailing list.