[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Scheme modules using HERALD, MODULE, and IMPORT.



Here is a crack at the kind of module system I envision.  It was
motivated by worrying about the multiple definition problem.  Consider
the problem of writing a random number generator.  You would like to
hide the seed, but provide a means to set the seed as well as compute
the next pseudo-random number.  One would like to write:

	(DEFINE-MANY (set-seed! random)
	   (DEFINE seed 42)
	   (DEFINE (set-seed! value) (SET! seed value))
	   (DEFINE (random) ....))

Since you would like to be able to use DEFINE-MANY where ever local
DEFINE's can be used, it is not clear how to expand DEFINE-MANY, but
at top-level, it might expand into:

	(DEFINE set-seed! '())
	(DEFINE random '())
	(LET ((seed 42))
	   (SET! set-seed! (LAMBDA (value) (SET! seed value)))
	   (SET! random (LAMBDA () ....)))

DEFINE-MANY makes its export list explicit, and augments the current
environment with the exported values.  Its body is defined in the
current environment augmented by all the definitions within the body.

All good module systems separate a module's interface description from
its implementation.  Hence we abandon DEFINE-MANY for HERALD, MODULE,
and IMPORT.

The HERALD form defines a module's interface, and may appear where
ever a DEFINE appears.

	(HERALD module-id id*)

The environment in which the module is defined is given by the
position of the HERALD form.  The form also lists the identifiers
exported by the module.

The implementation of a module is declared by using MODULE, and its
body simply follows the MODULE form. 

	(MODULE module-id) definition*

Another property of any good module system is the ability to separate
the definition environment from the elaboration environment.  The
form

	(IMPORT module-id)

simply imports the module's exports into the current lexical
environment.  It cannot change the definition of a module.

The structure of a Scheme program becomes:
--------------------------------------
program		::= definition* expression module*

definition	::= (DEFINE ....)		; Usual definition.
		 |  (IMPORT module-id)		; module import.
		 |  (HERALD module-id id*)	; module interface.

expression	::= id
		 |  constant
		 |  (LAMBDA (id*)
		       definition*
		       expression+)
		 |  (IF expression expression expression)
		 |  (SET! id expression)
		 |  (expression+)		; call

module		::= (MODULE module-id) definition*
--------------------------------------

While each module has exactly one HERALD and MODULE
form, there may be any number of IMPORT forms which reference that
module.  The three module forms return unspecified values just like
DEFINE. 

For a program contained in one file, the module-id can simply be a
symbol.  For multi-file programs, a module-id could be a list of
symbols interpreted in a machine dependent way.  As an example, the
module-id "(tsystem sources sys gc two-finger)" on a Unix machine
might reference the module named "two-finger" in the file
"$TSYSTEM/source/sys/gc.scm".

The MODULE form could be used to specify read tables and syntax tables
as is done in T.  The HERALD form would give a compiler its early
binding environment.

I have not thought out the details of an implementation of this module
system.  The implementation would have to handle circular module
references, but I see no obvious difficulties.
John