This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Modules, some proposals


Modules---The Straw Man Attacks:

This is some philosophy and a few proposals about semantic aspects of
modules.  To avoid mixing issues, I will say little about
implementation.  The intention is that the semantics should be clear,
and implementable, using an arbitrary mixture of interpreter,
compiler, and moby grokker.

A module is not a run time object.  This is hell on a compiler.  Rather,
a Scheme program may be broken into several files linked together by
(load "filename") calls.  These separate files are called modules.
The meaning of the set of modules is given by describing how they
can be patched together into a single Scheme program.  Various kinds
of pre-processing may be done to make the result more efficient, but
that has no effect on the meaning.

Problems of installation are handled by making sure the Guile system
finds the right files.  This is important, but it is not a semantic
issue, and so is outside the scope.

The expression (load "abc") has the same meaning as the expression
(begin <contents of file "abc">) in the same context.  Note that,
according to R4RS section 5.2, definitions leak out of a begin.

Putting a (load ..) form inside a binding form is perverse.  There is
no agreement on what it means, and I hope these proposals work without
doing that.

On the other hand, the following programs work as expected, and if
variable p has a value known at compile time, then so does variable a.

  (if p (define a 1) (define a 0))
  (if p (load "defa1") (load "defa0"))

(Where the named files contain the obvious definitions.)

Non-terminal syntactic variables used but not defined below are in
R4RS.

If there are N problems there should be N solutions.

---------------

Problem: Avoid accidental identifier clashes

Proposal: (with-prefix <identifier> <expression or definition>*)

This special form is equivalent to

   (begin <expression or definition>*)

but with every identifier that is defined by definitions in the list
replaced by a new identifier.  The new identifier is made by prefixing
the original with the given <identifier> and a colon.  This
replacement is done to both the defining occurrence of the identifier
and all applied occurrences.

Example:

guile> (with-prefix mapping
                    (define (zip a b) (map cons a b))
                    (define (vadd x y)(map + (zip x y))) )
guile> (mapping:zip '(a b c) '(1 2 3))
  ((a . 1)(b . 2)(c . 3))
guile> (with-prefix gnu (load "file-utilities"))
guile> (gnu:ls "/")
  ("usr" "bin" "etc")

The first expression is equivalent to
(define (mapping:zip a b) (map cons a b))
(define (mapping:vadd x y) (map + (mapping:zip x y)))

Rational:  If you want to load two modules that might have clashing
variable names you can systematically rename before loading them.  If
you have several mutually recursive definitions you can use short
names when defining them but have them known globally by longer names
that show that they are related.  I think this all works without
making the colon "special" in any way, but it may help the
implementation to know that prefixes are possible only with a colon.

-------------------

Problem: Limit the amount of text that must be read to know whether
 a particular variable is ever assigned to.

Proposal:
  <variable-list or identifier> ::= <variable list> | <identifier>
  <variable-list> ::= ( <variable>* >

(never-set <variable-list or identifier>*)

This has no effect whatsoever on the meaning of the program, if the
program remains correct.  If the program containing this special form
also contains any form like (set! <variable> ..), where the <variable>
also occurs in the <variable list> of the (never-set ..) form, then the
program is incorrect.  Whether the ensuing error message is attached
to the set! or the never-set is not specified.  Certain pre-defined
identifiers are equivalent in this context to a particular list of
variables.  For example, the identifier r4rs is equivalent to a list
of all variables in the index of the forth Revised Report.

Note that (never-set (x))
          (define x (string #\a #\b #\c))
is compatible with
          (string-set! x 1 #\w)
but not with
          (set! x "awc")

There is an obvious definition for (never-string-set ..), but no
hope of doing it at compile time.

Example:
A file containing the following:
  (never-set r4rs (f))
  (define (f a b) (+ (* b b) (* a a)))
can be compiled to make f into instructions to the compiler to
substitute arithmetic operations in-line, but it can never be loaded
into a program that sets f, +, or *.  (But who knows what that might
be intended to mean?)

On the other hand:
  (never-set r4rs (x y z))
  (load "goofy")
will give an error message if the goofy file contains
  (set! + string-append).

-----------------------

Problem: Load a *.o file produced elsewhere.

Proposal: A <filename>.c file that is to be compiled and loaded into
Guile must contain a procedure called <filename>_init.  This procedure
must contain calls to gh_new_procedure and its ilk to define all
Scheme accessable variables.  The (load "<filename>") call must
arrange that the prefix set up by surrounding (with-prefix ..) forms
be made available to gh_new_procedure, which will add the prefix to
each definition.  It must then call <filename>_init in the
<filename>.o file.

-- 
     --Keith

This mail message sent by GNU emacs and Linux.
Power to the people. Linux is here.
Food, Shelter, Source code.