[racket-dev] submodules
[Some of these points may have come up earlier, I just didn't want to
lose comments so reply as I read it.]
[To be clear in advance, the following should be qualified by an "I
love it".]
Two days ago, Matthew Flatt wrote:
>
> Given the term "submodule", the first thing that you're likely to try
> will work as expected:
>
> #lang racket/base
>
> (module zoo racket/base
> (provide tiger)
> (define tiger "Tony"))
>
> (require 'zoo)
>
> tiger
>
> Within `module', a module path of the form `(quote id)' refers to
> the submodule `id', if any. If there's no such submodule, then
> `(quote id)' refers to an interactively declared module, as before.
This is *really* nice in how it's building a scope for module names,
but OTOH, it makes the quote seem more like a syntactic hack...
> [...later...]
>
> (require (submod 'zoo monkey-house))
>
> [...] a shorthand for `(submod "." zoo)' [...]
...especially here -- why is there a quote only on the first and not
on the second? Is there any meaning for (submod foo) without the
quote (or a sting)? If not, then having (submod zoo monkey-house)
seems beter in building up an intuition of `submod' implicitly
"quoting" the following name.
Perhaps a more obvious question is why aren't all `submod' uses get
"." as an implicit first expression? IIUC, this means that it works
nicely without quotes, and there's only a single magical ".." thing.
> The 'zoo module path above is really a shorthand for `(submod "."
> zoo)', where "." means the enclosing module and `zoo' is its
> submodule. You could write `(submod "." zoo monkey-house)' in place
> of `(submod 'zoo monkey-house)'.
I also love the analogy to paths -- but using strings for them doesn't
look so nice, since strings are begging to be combined... (I can
already see myself wishing for "./../foo".) Other than the obvious
reader issue, would there be a problem in using `|.|' and `..' for
these (and making them into special module names)?
Or if there was always an implicit first ".", then there's only need
for a single `..' magic token thing... (It even makes syntactic sense
that (submod) is something that you can't require.)
Reading the later "Design Issues" section, I see that these are
indeed arbitrary. So to clarify, I propose a `submod' form that
always begins with a "." (under its current semantics), with no need
to use a quote, and with `..' being a special name that goes up the
hierarchy. To make things connect nicely to toplevel requires,
(submod foo) could also resort to the repl-entered module thing, which
means that we now have:
(require (submod foo))
is very common, so it can be written a bit more conveniently as
(require 'foo)
(But this might be pushing the description into showing them as closer
than they are.)
> Instead of `require'ing its enclosing module, a `module*' form can
> use `#f' as its language, in which case its lexical context starts
> with all of the bindings of the enclosing module (implicitly
> imported) instead of with an empty lexical context. As a result, the
> submodule can access bindings of the enclosing module that are not
> exported:
>
> #lang racket/base
>
> (module aquarium racket/base
> (define fish '(1 2))
>
> (module* book #f
> (append fish '(red blue))))
>
> (require (submod 'aquarium book))
The explanation for this looks reasonable, but the result looks
unfortunate since the common case requires you to remember to add two
special things (the `*' and `#f'). But I also really don't like to abuse
`module' for both uses. How about just (submodule foo ...) be a more
memorable syntax for (module* foo #f ...)?
Later, I see:
> As things stand, the ugly pattern `(module* main #f ...)' would be
> common. Probably we should have a macro that expands to `(module* main
> #f ...)'. Should the macro be called `main'?
So above is my suggestion. But maybe even make it more generally
convenient so it can cover the `test' use without needing a library --
taking what Jay did (I think, didn't look at the code or the
followups, yet), and making this:
(submodule <name> E ...)
be something that can appear anywhere in the code, expands to what
(module* main #f E ...) is doing now, *and* is allowed to be used more
than once, with all uses being collected into a single submodule.
This way I can easily interleave regular code, main code, test code,
sanity assertion code, documentation code etc.
IOW, I see this as something that can be used straightforwardly with
any testing tool, or made into a macro by one, or being used in the
obvious way by in-line documentation tools like Neil V's mcfly thing
(which is more straightforward for this than srcdoc).
> A common use of `module*' is likely to be with `main', since
> `racket' will load a `main' submodule (after `require'ing its
> enclosing module) for a module named on its command line. For
> example, if you run this program via `racket':
>
> #lang racket/base
>
> (provide fish)
> (define fish '(1 2))
(Just in case this was missed and is/will be in some docs: that should
probably have been '(2 1).)
> The `#lang' reader form was previously defined as a shorthand for
> `#reader' where the name after the `#lang' is mangled by adding
> "/lang/reader". With submodules, `#lang' first tries using the name
> as-is and checking for a `reader' submodule; if it is found, then
> the submodule is used instead of mangling the name with
> "/lang/reader", otherwise it falls back to the old behavior.
(BTW, there's an obvious question here of why not do that for all
paths, so that `foo/bar/baz' can access a `bar/baz' submodule in `foo'
or a `baz' in `foo/bar'... This is very similar to what I did in the
old plt-schme.org web page sources, where a page is usually a file,
but some files have subpages (with a `begin-page'). It was a mess.)
> #lang racket/base
>
> (provide (all-from-out racket/base)
> fish)
> (define fish '(1 2 3))
>
> (module reader syntax/module-reader
> #:language 'ocean)
[This could be even nicer with:
(module reader syntax/module-reader
#:language (submod "."))
]
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!