You are looking at historical revision 2659 of this page. It may differ significantly from its current revision.



   The name 'lexmod' is short for 'lexical module' -- this module

system is based on lexical capture --.


(LEXMOD <module-name> <exports> <body>) -> lexmod               ;syntax
   Create a lexmod with the given name, export list, and body.  The
   export list should have a form of:
       (EXPORT <export-clause> ...)
   Each EXPORT-CLAUSE should have a form of:
         Export SYMBOL as defined from BODY
       (AS <exported> <internal>)
         Export EXPORTED as what INTERNAL was defined as in BODY.
   The definitions in BODY are evaluated as in a LAMBDA body.
   Qualified module names have the form: (MODULE 'NAME)
   Modules within modules are perfectly possible.  Qualified names in
   nested modules can end up becoming a little hairy, though --
   ((MODULE 'SUBMODULE) 'SUBMODULE-BINDING) --.  In a later version,
   this might be made nicer.
(DEFINE-LEXMOD <name> <exports> <body>)                         ;syntax
   Convenience for
       (define NAME (lexmod NAME EXPORTS BODY))
(LEXMOD-EXPORTS? <lexmod> <name>) -> boolean                 ;procedure
   LEXMOD-EXPORTS? takes a lexmod and a symbol and returns #T iff the
   lexmod exports the symbol, or #F otherwise.
(LET-IMPORTS  ((<module> <import-clause> ...) ...) <body>)      ;syntax
(LET*-IMPORTS ((<module> <import-clause> ...) ...) <body>)      ;syntax
   Import names from lexmods in a local context.  Each MODULE should
   evaluate to a lexmod; each IMPORT-CLAUSE should have a form of:
         Import SYMBOL from the corresponding module exactly
       (AS <imported> <exported>)
         Import EXPORTED from the corresponding module, but rather
         bind IMPORTED to its value.
   LET*-IMPORTS is like LET-IMPORTS, but it binds each module clause
   sequentially, whereas LET-IMPORTS binds in an order such that each
   MODULE is evaluated in the environment of the context of the
   LET-IMPORTS form.  That is, LET-IMPORTS might be defined to expand
       (let-imports ((MOD1 A (as B Z) C) (MOD2 D (as E Y) F)) BODY)
       (let ((A (MOD1 'A)) (B (MOD1 'Z)) (C (MOD1 'C))
             (D (MOD2 'D)) (E (MOD2 'Y)) (F (MOD2 'F)))
   and LET*-IMPORTS might expand
       (let*-imports ((MOD1 A (as B Z) C) (MOD2 D (as E Y) F)) BODY)
       (let-imports   ((MOD1 A (as B Z) C))
         (let-imports ((MOD2 D (as E Y) F))
(DEFINE-IMPORTS (<module> <import-clause> ...) ...)             ;syntax
   Like LET-IMPORTS, but expand to a set of DEFINEs, rather than bind
   locally a bunch of variables.  Each IMPORT-CLAUSE has the same
   syntax & semantics as with LET-IMPORTS.
(IMPORT-IN <module> (<import-clause> ...) <body>)               ;syntax
       *DEPRECATED* - Use LET-IMPORTS instead.  Will disappear in a
       later release.
   Import a set of names from a single module in a local context.
   Return whatever BODY returns.
(INTERFACE <name> ...) -> interface                             ;syntax
   Create an interface with the given exports.
(INTERFACE-EXPORTS? <interface> <name>) -> boolean           ;procedure
   Does INTERFACE contain NAME in its export list?
(LEXMOD-SATISFIES? <lexmod> <interface>) -> boolean          ;procedure
   Does LEXMOD export everything that INTERFACE demands it to?
(FUNCTOR <name> ((<lexmod-arg> <interface>) ...) <export-list>  ;syntax
(FUNCTOR        ((<lexmod-arg> <interface>) ...) <export-list>  ;syntax
   Functors are functions that take lexmods and return lexmods.  The
   FUNCTOR macro ensures that the lexmods satisfy the interfaces.
   EXPORT-LIST is like the list of exports in LEXMOD.  NAME will be
   the name of the lexmod the functor returns; it defaults to the
   symbol _ANONYMOUS_.  The functor takes a parametre list (param-name
   ...) and each PARAM-NAME is checked to satisfy its respective
   INTERFACE when the functor is applied.  Functor application is
   ordinary function application.


 modules    - @<module name>
 interfaces - <interface name>-INTERFACE
 functors   - @MAKE-<name>

Known problems

There are only four [known] problems with this module system:

1. It doesn't support macros (this module system is purely run-time, while macros are macro-expand- or compile-time-only).

2. There can be no initialization code scattered throughout the module, so you can't do, for instance:

   (lexmod @foo (export bar baz quux)
     (define bar #f)
     (define (baz stuff) body)
     (set! bar (baz mumble))
     (define quux (zot bar)))

because then the SET! expression unsets the fact that it's a definition context in the rest of the LEXMOD expression, and so that DEFINE expression below it is in an expression context, not a definition context, which won't work very well. Instead put all initialization after all definition -- for example:

   (lexmod @foo (export bar baz quux)
     (define bar #f)
     (define (baz stuff) body)
     (define quux #f)
     (set! bar (baz mumble))
     (set! quux (zot bar)))

(SYNTAX-CASE's module system exhibits this problem as well, so hah!)

Riastradh has written a macro for giving top-level semantics to local scopes, but it has one problem: those local bodies can't contain macros that expand to DEFINE and work right, which is why he hasn't put it in the lexmod distribution yet.

3. Because each subform is wrapped inside a single LET, the definitions are ordinary internal defines, so they're equivalent to a LETREC -- i.e. they aren't evaluated sequentially, and they don't have _all_ the properties of top-level defines (for example, they're not equivalent to SET! if the variable is already defined) --.

These two could be fixed by wrapping every form in a LEXMOD expression with LET, but that would cons a closure for every expression, which would be rather annoying.

4. The export list should be able to be an interface as created with the INTERFACE macro, not just with (export ...). Due to this problem, I'll probably change interfaces to use macro magic that lets them be both macro-expand-time and run-time values so that the LEXMOD macro can use them, and they can also be used as ordinary run-time values.


Taylor Campbell, packaged for CHICKEN by felix winkelmann


initial release as a CHICKEN extension