This site is a static rendering of the Trac instance that was used by R7RS-WG1 for its work on R7RS-small (PDF), which was ratified in 2013. For more information, see Home.

Source for wiki ModulesShinn version 2

author

DekuDekuplex

comment

Corrected misspelling: "except" -> "exception".

ipnr

122.26.252.111

name

ModulesShinn

readonly

0

text

== Title ==

WG1 Library Syntax

== Authors ==

Alex Shinn

== Abstract ==

A simple, static module syntax is provided which can easily be
implemented on top of existing module systems.  Modules have separate
namespaces, and can import and export variables and macros with
fine-grained control.  The description of the module is done with a
Scheme-like DSL, clearly separated from the code of the module for ease
of static analysis.  Users are free to either include the module code
directly in the DSL or in separate files or both.

== Issues ==

  * The number of times a module is instantiated is left unspecified.

  * Phasing is irrelevant in the absense of low-level macros, and is thus
  ignored.

  * Versioning is left out entirely.  This is an important feature for
  practical application development, not to be ignored lightly, but the
  author felt that experimentation with it in current Scheme
  implementations is insufficient for standardization at the current
  time.

  * The keywords used are open for debate - `library` is chosen for
  compatibility with R6RS.

  * The body of the library when placed in the same file is indented a
  single extra character as compared to library forms with implicit
  bodies.  A separator syntax `---` could remove this extra space.

  * Forwards compatibility of non-essential forms (declarations,
  optimizations and other meta-info) could be achieved by specifying
  that any unknown library form simply be ignored.  However this can
  cause difficulties for extensions that _are_ essential.

  * We still need to choose the default module hierarchy for the WG1 core.

  * With either R5RS or R6RS identifier syntax, it is possible for both
  a prefix to be a valid identifier, and an export to be a valid
  identifier, but the resulting concatenation invalid.  For example,
  `-` is a valid prefix, but prepended to `foo` results in `-foo`
  which is not a valid literal.  We need to note this in the
  description of prefix, or modify the symbol syntax so that this
  can't occur.  This is especially tricky because `i` with a prefix of
  `-` results in `-i`, a number.

== Rationale ==

The charter explicitly requires a module system:

   To promote extensibility, the language developed by working group 1
   must include support for macros and modules in a way that is
   appropriate for the language's size and goals. Semantics compatible
   with interactive read/eval/print loops should be provided.

Module systems serve the purpose of encapsulating code and managing
namespaces.  Although `lambda` lets us manage local identifiers, it
does't allow us to encapsulate macros, and it wants for a friendlier
interface for typical "module-like" uses.

== Specification ==

A module definition takes the following form:

  (library <module-name>
    <module-declarations>)

The keyword `library` is used for compatibility with R6RS - except for
this one keyword, this proposal will refer to modules, reserving the
option to change terminology at a later date.

The module name is a list of symbols or exact integers specifying the
name of the module, for use when importing from other modules.  R6RS
does not allow non-symbol components, but as this is popular and
convenient for numeric concepts such as (srfi 1) and (rfc 821) it is
explicitly allowed.

The <module-declarations> can be any of:

  * (export <export-spec> ...)
  * (import <import-set> ...)
  * (include <resource-name> ...)
  * (body <module-body> ...)

Future standards may extend the syntax with additional forms.

`export` specifies a set of bindings to be exported.  Each
<export-spec> has one of the two forms:

  * <identifier>
  * (rename <local-identifier> <exported-identifer>)

where the former exports the identifier with the same name, and the
latter can be used to rename the identifier on export.

`import` specifies one or more modules to import into the current
module.  An <import-set> has one of the following forms:

  * <module-name>
  * (only <import-set> <identifier> ...)
  * (except <import-set> <identifier> ...)
  * (rename <import-set> (<old-identifier> <new-identifier>) ...)
  * (prefix <import-set> <prefix-identifier>)

By default, all of the bindings in a module's export clause are
imported with the same names (or the exported names if exported with a
`rename` form).  The additional <import-set> forms modify this as
follows.

  * An `only` form produces a subset of the given <import-set>,
  including only the listed identifiers (after any renaming).  It is a
  syntax error if any of the listed identifiers are not found in the
  original set.

  * An `except` form produces a subset of the given <import-set>,
  excluding the listed identifiers.  It is a syntax error if any of
  the listed identifiers are not found in the original set.

  * A `rename` form modifies the given <import-set>, replacing each
  instance of <old-identifier> with <new-identifier>.  It is a syntax
  error if any of the listed <old-identifiers> are not found in the
  original set.

  * A `prefix` form automatically renames all identifiers in the given
  <import-set>, prefixing each with the specified identifier.

It is a syntax error if the same identifier is imported twice, from
any combination of modules or multiple `import` forms.

`body` and `include` declarations provide a means to specify the
Scheme code that makes up the body of the module.  `body` takes the
forms literally and splices them as a `begin`, whereas `include` takes
one or more file names, reads all the top-level forms in the files,
and splices the results.  The forms from all `body` and `include`
declarations are expanded in the order in which they occur in the
module declaration.

The bodies of an imported module may be evaluated multiple times, but
will be evaluated at least once before the body of any module which
imports it is evaluated.  It is a syntax error if any set of modules
form a cyclic import dependency.

== REPL Interaction ==

To load a module into an interactive REPL, a REPL should extend the
standard environment with an `import` form that works as within a
module declaration, but importing the bindings directly into the REPL
environment.

Multiple imports of the same identifier in the same `import` form is
still a syntax error, however identifiers may later be rebound by
subsequent `import` forms.

== Top-Level Programs ==

To be specified.

== Implementation ==

Scheme48 provides a module system compatibile with this, with some
minor syntactic differences, and using plain identifiers instead of
lists for module names.  Chibi-Scheme provides a similar module system
based on the Scheme48 system, removing all keywords and regulating the
module names, now lists, to a separate namespace.

== Compatibility ==

=== R5RS ===

The R5RS has no module system, so implementations all provide their own
incompatible module systems.  To work together and with WG1 standard
Scheme implementations, they should support the specified library syntax
in addition to (or in place of) their current syntax.

=== R6RS ===

The syntax is largely a subset of the R6RS `library` form, with the
exception that there is no implicit body.  To support WG1 library forms,
the core library (e.g. `(rnrs 7)`) should provide two macros,
`include` and `body`.  `body` can be defined simply as an alias for
`begin`:

  (define-syntax body
    (syntax-rules ()
      ((body x ...) (begin x ...))))

`include` can't be defined with `syntax-rules`, but can in a low-level
macro system.  The R6RS library specification gives a sample
definition of `include`.

=== WG2 ===

WG2 will likely need to address phasing issues, and provide the
equivalent of the R6RS `for` form.

time

2010-06-03 04:46:07

version

2