This is the mail archive of the
guile@cygnus.com
mailing list for the Guile project.
Re: Where should guile modules store meta data?
[please excuse the delay]
David Lutterkort <lutter@cise.ufl.edu> writes:
> (defmacro* define-module (name #&key import export . rest)
> (let ((body (remove-keywords rest)))
> `(let ((new-module (make-new-module)))
> (register-module ',name new-module)
> (module-resolve-imports new-module ',import)
> (module-make-public-interface new-module ',export)
> (eval (begin ,@body) (module-eval-environment new-module))
> new-module)))
In other words:
1. create a generic module <new-module>---in which environment!?!
2. restrict the type of <new-module> to (im-/export)
3. evaluate its body in the environment of <new-module>
The problem: In which environment should (define-module...) be
evaluated? If it is evaluated in the current module, you can't share
this module with others because it (logically) belongs to the current
module.
This is why Jonathan Rees has created a special config environment
where all modules live:
> ,config ; leave the scheme world and enter a meta world to create
; a new module
config> (define-structure A (export c) (open scheme) (begin (define a 12) (define (b) (display a))))
config> a
'#{Structure 116 a}
config> scheme
'#{Structure 56 scheme}
config> (define x 99)
config> x
99
config>,in a ; enter the scheme world (module a)
a> a
12
Note that structures are created in a separate environment ("world").
He uses a configuration language (which is scheme of course) to
create and modify structures ("modules").
What is wrong with the (define-module ..) syntax above?
"A module is a structure used to encapsulate related data and
functions with a restricted view from the outside." But does this
mean that a module is part of the system it structures? Is a module a
first class object?
A module can't be a first class object because it describes the physical
view of the system. When you look at a system from the outside, you
see modules. But if you step inside the system you can see other modules,
but these modules tradidionally have a differend name: "classes".
In other words a module structures a system physically while a class
structures a system logically. I think we should not mix these two
(related) concepts.
This means that you can't *define* a module at runtime. If your
computer crashes, the module is gone. What you can do is to create a
module and register it in some kind of secondary repository, but it is
impossible to *define* a new module within guile. (In scheme48 the
primary module repository is the config environment.)
(Don't take the following too serious)
The guile module repository
----------------------------
Guile modules are stored under $GUILE_LOAD_PATH/<module-name>.scm
For example: (org gnu guile ice-9 test) will be stored unter
$GUILE_LOAD_PATH/org/gnu/guile/ice-9/test.scm.
Guile uses two repositories. One for modules stored in
the file system and one for in-memory modules created by
(create-module ...) and register_c_module() (?).
The configuration language:
---------------------------
(export <sig>) -> unspecified symbols must exist
(protect <sig>) -> unspecified symbols must exist
(open (<name>)) -> unspecified module must exist in file <name>
(access <name>) -> <module> module must exist in file <name>
;(<module> symbol) -> <value> symbol must exist in module
(ref <module> symbol) -> <value> symbol must exist in module
(load <name>) -> unspecified load code from file file must exist
(the-module) -> <module>
-----
Special case for backward compatibility (used to create
old (define-module ...) syntax):
(module <name> optionals) -> unspecified
checks if module <name> is the current module and does
nothing. :>
optionals: (export <sig>)
(protect <sig>)
(open <name>)
(begin <code>)
(load <name>)
(see above)
-----
Creating new modules (in memory)
(create <name>) -> <module>
Starting new repl in module
(go <module>) -> unspecified new repl
Accessing environments:
(module-eval-environment <module>) -> <eval-environment>
(module-ref <module> <ref-module> <sym>)
syntax: (ref (the-module) <ref-module> sym)
(module-load <module> <name>)
syntax: (load (the-module) <name>)
(module-go <module> <go-module>)
syntax: (go (the-module) <go-module>)
(module-protect <module> protect-list)
syntax: (protect (the-module) protect-list)
(module-export <module> export-list)
syntax: (export (the-module) export-list)
(module-open <module> import-list)
syntax: (open (the-module) import-list)
(module-access <module> <name>)
syntax: (access (the-module) <name>)
(module-create <module> <name>)
syntax: (create (the-module) <name>)
Examples:
guile > (define m (create (my test))) ; create a new module
guile > (go m) ; start a new repl in m
my/test > (the-module) -> #(#<eval environment> #f #f <useslist> ice-9/test5)
my/test > (export (a b c)) ; set the export list
my/test > (the-module) -> #(#<eval environment> #<export environment> #f <useslist> ice-9/test5)
my/test > (go (create (my test2))) ; create and go to my/test2
my/test2 > (open ((my test) (ice-9 root)))
my/test2 > a -> #f ; from my/test (note: #f!)
my/test2 > (go (access (my test))) ; go back to test
my/test > (create (ice-9 test)) ; create a new module (not possible, module is in primary repository)
-> error module exists but has not been loaded
my/test > (go (access (ice-9 test))) ; auto-load ice-9/test
> Here's one reason why it is good to have several modules in one file: I
> write a fairly large script that becomes much clearer if I split it up into
> several modules.
You can structure them into classes instead and put these classes into
your module. As in java. :> As I said earlier if you want to structure
your software logically, use classes, if you want to structure it
physically, use modules. This is why programming languages have both
modules *and* classes.
> high-level module system. I would really like to see an import-renaming
> facility added to the current module system ....
If you specify what import-renaming should do, I'll implement that.
Btw. that's where module and class concepts differ. Modules use
selective import while classes import all features and then rename them:
; in module (ice-9 test20)
(define handle-of-root-module (access (ice-9 root)))
(define handle-of-my-module (access (ice-9 test1))
(handle-of-root-module a) -> 11
(handle-of-my-module a) -> 13
a -> 20
; in some module
(define-class (a (import) (export x) ((define x 99))))
(define-class (b (import) (export x) ((define x 100))))
(define-class (c (import a (rename x y)) (import b (rename x z))))
(c x) -> error
(c y) -> 99
(c z) -> 100
As you can see modules and classes are orthogonal.
Jost