From: Marc Wachowitz
Subject: Re: CFP: scheme standard libraries
Date: 
Message-ID: <5kabed$scv$4@trumpet.uni-mannheim.de>
Ray Dillinger <····@sonic.net> wrote:
> The entire point of this was to try to extract *SPECIFIC* *PROPOSALS* 
> for the module system (and the other stuff).  We all agree that it's 
> what we need; I was asking, not what we need, but what *specific form* 
> it should take!!  Doesn't *anybody* have an opinion?

EuLisp might be a good example, but perhaps not be popular here, since it
disallows the usage of a macro in the module which defines it. If that's
acceptable, I'd favour using that one as it is, with SYNTAX-CASE (and the
declarative SYNTAX-RULES) instead of their crippled macros. Alternatively,
here's a proposal for a simple Scheme module system - with the expectation
that interactive development systems should allow redefinitions beyond
what's defined below, with the cost of either fewer optimization opportunities
(like inlining and type/value inference), or also needing a sophisticated
dynamic dependency management system with automatic recompilation. However,
such stuff should remain implementation-dependent.

Modules are identified by their name, which is mapped in an implementation-
dependent way to the associated source code (probably it corresponds to
a file name in a one-to-one mapping, possibly with escape conventions for
characters which can't appear in file names, or mapping tables in case the
length of file names is too restricted).

A module is a set of named bindings, the values of which can only be set!
by code from within the module; clients can only read imported bindings.
Import dependencies between modules must be non-cyclic. No assumption is
made whether different modules are translated in the same Scheme image or
e.g. in separate compilations (like calling a compiler from "make" in the
traditional Unix style). It's expected that a good implementation can work
out everything given some kind of "main module" and a set of potentially
used sources (e.g. a list of directories with source files).

Source code for a module is wrapped in the top-level form DEFINE-MODULE;
the module body is ordinary Scheme code, consdired to be at top-level. If
desired, we might define that source code outside of any module defintions
is implicitly part of a module named e.g. after a loaded file, which exports
everything defined in it (or something a module *INTERACTIVE*, which cannot
be imported into other modules, for interactively entered code). There's no
"global top-level" shared by all modules.

(define-module MODULE-NAME BODY)

MODULE-NAME is any Scheme symbol. Module names are only used in imports,
and don't appear in the ordinary lexical name space of Scheme programs.

The special form IMPORT specifies a set of named bindings to be imported
into the current module's scope. Names imported implicitly from more
than one module are completely hidden; explicit imports shadow implicit ones,
and conflicts between explicit imports are a static error. Imported names
can only be used after the respective import form, and the usage of a name
disallows effective importing it in further code (necessary to prevent funny
ambiguities or horribly complicated non-sequential/top-down analysis). The
expected normal case is to collect all imports at the beginning of a module,
but for large modules, it might be preferable to use a different grouping.

(import MODULE-NAME [IMPORT-MODIFIER])
	makes the set of exported bindings of MODULE-NAME available

The IMPORT-MODIFIER generate a set of named bindings; if omitted above, it
corresponds to an empty (except) clause:

(only NAME ...)
	makes only the named bindings available

(except NAME ...)
	makes all exported bindings available, except for the given names

(rename IMPORT-MODIFIER RENAME-CLAUSE ...)
	where RENAME-CLAUSE is a list of the name in IMPORT-MODIFIER and
	the new name under which the associated binding should be available;
	the empty list as IMPORT-MODIFIER is equivalent to (except)

(prefix IMPORT-MODIFIER PREFIX)
	where PREFIX is a Scheme symbol to be prepended to the names;
	the empty list as IMPORT-MODIFIER is equivalent to (except)

(select IMPORT-MODIFIER NAME ...)
	select the given names explicitly from this import, shadowing
	potential other implicit imports (via except) of the same name;
	top-level definitions in the importing module work similarly for
	implicit imports of the same name

The new special form EXPORT makes top-level bindings available for clients
of the current module:

(export NAME ...)

Top-level hygienic macros capture module dependencies as part of the lecical
environment; users of imported macros don't need to worry whether the code
generated from such macros might use other modules etc. If procedural macros
(i.e. not merely the declarative syntax-rules) are used, there also should
be a way to make definitions and/or code available to such macros, including
the case where another module is only used by the macro at compilation time,
but doesn't need to available for the generated code. The top-level form

(eval-when (SITUATION ...) BODY)

can be used for that purpose, where SITUATION may be the symbol COMPILE or
the symbol LOAD (both may be specified), and BODY remains conceptually at
top-level (which can also include imports).

I'd also restrict imports to top-level forms (including those in BEGIN or
EVAL-WHEN), to simplify implementations, but that's only a mild preference;
importing names into a nested lexical environment would be acceptable.

The standard predefined names of Scheme are available from a module named
e.g. R4RS for that version of the standard; the most recent standard which
is supported by a particular implementation is also available from module
SCHEME (this should not include implementation-specific extensions; these
should be available from different modules).

I can work out the details and make the procedural semantics more explicit
if this general model is accepted; I hope the above is sufficiently clear
to find out if that's what sufficiently many people want to use at all. The
intention is to have declarative semantics as far as possible, encouraging
a clear programming style without obscure semantics for dirty tricks (even
if a few ambiguities can only be detected and signalled as error after some
procedural macro has already  generated side effects, the idea is not to let
correct code pay for such stuff).

-- Marc Wachowitz <··@ipx2.rz.uni-mannheim.de>