This section describes the semantics of Gauche modules and its API. See also Writing Gauche modules, for the conventions Gauche is using for its modules.
For R7RS programs, they are called “libraries” and have different syntax than Gauche modules. See R7RS library form, for the details.
• Module semantics: | ||
• Modules and libraries: | ||
• Defining and selecting modules: | ||
• Using modules: | ||
• Module inheritance: | ||
• Module introspection: | ||
• Predefined modules: |
Module is an object that maps symbols onto bindings, and affects the resolution of global variable reference.
Unlike CommonLisp’s packages, which map names to symbols,
in Gauche symbols are eq?
in principle if two have the
same name (except uninterned symbols; see Symbols).
However, Gauche’s symbol doesn’t have a ’value’
slot in it. From a given symbol, a module finds its binding that
keeps a value.
Different modules can associate different bindings
to the same symbol, that yield different values.
;; Makes two modules A and B, and defines a global variable 'x' in them (define-module A (define x 3)) (define-module B (define x 4)) ;; #<symbol 'x'> ---[module A]--> #<binding that has 3> (with-module A x) ⇒ 3 ;; #<symbol 'x'> ---[module B]--> #<binding that has 4> (with-module B x) ⇒ 4
A module can export a part or all of its bindings for other module to use. A module can import other modules, and their exported bindings become visible to the module. A module can import any number of modules.
(define-module A (export pi) (define pi 3.1416)) (define-module B (export e) (define e 2.71828)) (define-module C (import A B)) (select-module C) (* pi e) ⇒ 8.539748448
A module can also be inherited, that is, you can extend
the existing module by inheriting it and adding new bindings
and exports. From the new module, all ancestor’s bindings (including
non-exported bindings) are visible.
(A new module inherits the gauche
module by default, which is why
the built-in procedures and syntax of gauche
are available
in the new module).
From outside, the new module looks like having
all exported bindings of the original module plus the newly
defined and exported bindings.
;; Module A defines and exports deg->rad. ;; A binding of pi is not exported. (define-module A (export deg->rad) (define pi 3.1416) ;; not exported (define (deg->rad deg) (* deg (/ pi 180)))) ;; Module Aprime defines and exports rad->deg. ;; The binding of pi is visible from inside Aprime. (define-module Aprime (extend A) (export rad->deg) (define (rad->deg rad) (* rad (/ 180 pi)))) ;; Module C imports Aprime. (define-module C (import Aprime) ;; Here, both deg->rad and rad->deg are visible, ;; but pi is not visible. )
At any moment of the compilation, there is one "current module" available, and the global variable reference is looked for from the module. If there is a visible binding of the variable, the variable reference is compiled to the access of the binding. If the compiler can’t find a visible binding, it marks the variable reference with the current module, and delays the resolution of binding at the time the variable is actually used. That is, when the variable is referenced at run time, the binding is again looked for from the marked module (not the current module at the run time) and if found, the variable reference code is replaced for the the code to access the binding. If the variable reference is not found even at run time, an ’undefined variable’ error is signaled.
Once the appropriate binding is found for the global variable, the access to the binding is hard-wired in the compiled code and the global variable resolution will never take place again.
The definition special form such as define
and define-syntax
inserts the binding to the current module. Thus it may shadow
the binding of imported or inherited modules.
The resolution of binding of a global variable happens like this. First, the current module is searched. Then, each imported module is taken in the reverse order of import, and searched, including each module’s ancestors. Note that import is not transitive; imported module list is not chased recursively. Finally, ancestors of the current module are searched in order.
This order is important when more than one modules
defines the same name and your module imports both.
Assuming your module don’t define that name,
if you first import a module A
then a module B
,
you’ll see B
’s binding.
If you import A
, then B
, then A
again,
the last import takes precedence; that is, you’ll see A
’s
binding.
If two modules you want to use exports bindings of the same name and you want to access both, you can add prefix to either one (or both). See Using modules, for the details.
Modules are run-time data structure; you can procedurally create modules with arbitrary names at run-time.
However, most libraries use modules to create their own namespace, so that they can control which bindings to be visible from library users. (This “library” is a general term, broader than R7RS “library”).
Usually a library is provided in the form of one or more Scheme
source file(s), so it is convenient to have a convention to map
module names to file names, and vice versa; then, you can load a
library file and import its module by one action with use
macro, for example.
For the time being, Gauche uses a simple rules for this mapping:
Module names are organized hierarchically, using period ‘.
’
for separator, e.g. gauche.mop.validator
. If such a
module is requested and doesn’t exist in the current running
environment, Gauche maps the module name to a pathname by
replacing periods to directory separator, i.e.
gauche/mop/validator
, and look for
gauche/mop/validator.scm
in the load paths.
Note that this is just a default behavior.
Theoretically, one Scheme source file may contain multiple
modules, or one module implementation may span to multiple files.
In future, there may be some hook to customize this mapping
for special cases. So, when you are writing routines that
deal with modules and library files, do not apply the above
default rule blindly. Gauche provides two procedures,
module-name->path
and path->module-name
,
to do mapping for you (see Module introspection, for details).
Name must be a symbol. If a module named name does not exist, create one. Then evaluates body sequentially in the module.
Makes a module named name as the current module. It is an error if no module named name exists.
If select-module
is used in the Scheme file, its effect is
limited inside the file, i.e. even if you load/require a file that uses
select-module
internally, the current module of requirer is
not affected.
Evaluates body sequentially in the module named name. Returns the last result(s). If no module named name, an error is signaled.
Evaluates to the current module in the compile context. Note that this is a special form, not a function. Module in Gauche is statically determined at compile time.
(define-module foo
(export get-current-module)
(define (get-current-module) (module-name (current-module))))
(define-module bar
(import foo)
(get-current-module)) ⇒ foo ; not bar
[R7RS base] Makes bindings specified by each spec available to modules that imports the current module.
Each spec can be either one of the following forms, where name and exported-name are symbols.
name
The binding with name is exported.
(rename name exported-name)
The binding with name is exported under an alias exported-name.
Note: In Gauche, export
is just a special form
you can put in the middle of the program, whereas
R7RS defines export
as a library declaration,
that can only appear immediately below define-library
form.
See R7RS library form, for the details.
Makes all bindings in the current module available to modules that imports it.
Makes all or some exported bindings in the module specified by import-spec available in the current module. The syntax of import-spec is as follows.
<import-spec> : <module-name> | (<module-name> <import-option> ...) <import-option> : :only (<symbol> ...) | :except (<symbol> ...) | :rename ((<symbol> <symbol>) ...) | :prefix <symbol> <module-name> : <symbol>
The module named by module-name should exist when the compiler sees this special form.
Imports are not transitive. The modules that module-names are importing are not automatically imported to the current module. This keeps modules’ modularity; a library module can import whatever modules it needs without worrying about polluting the namespace of the user of the module.
import-option can be used to change how the bindings
are imported. With :only
, only the bindings with
the names listed in <symbol> …
are imported.
With :except
, the exported bindings except the ones
with the listed names are imported.
With :rename
, the binding of each name in the first
of two-symbol list is renamed to the second of it.
With :prefix
, the exported bindings are visible with
the names that are prefixed by the symbol to the original names.
Without import options, all the exported bindings are imported
without a prefix.
(define-module M (export x y) (define x 1) (define y 2) (define z 3)) (import M) x ⇒ 1 z ⇒ error. z is not exported from M (import (M :only (y))) x ⇒ error. x is not in :only list. (import (M :except (y))) y ⇒ error. y is excluded by :except. (import (M :prefix M:)) x ⇒ error M:x ⇒ 1 M:y ⇒ 2
If more than one import option are given, it is processed
as the order of appearance. That is, if :prefix
comes first, then :only
or :except
has to
list the name with prefix.
Note: R7RS has import
form, which has slightly different
syntax and semantics. See Three import forms, for the details.
A convenience macro that combines module imports and on-demand
file loading. Basically, (use foo)
is equivalent
to the following two forms:
(require "foo") (import foo)
That is, it loads the library file named “foo
” (if not yet
loaded) which defines a module named foo
in it,
and then import the module
foo
into the current module.
The keyword argument only, except, and prefix
are passed to import
as the import options.
(use srfi.1 :only (iota) :prefix srfi-1:) (srfi-1:iota 3) ⇒ (0 1 2)
Although the files and modules are orthogonal concept,
it is practically convenient to separate files by modules.
Gauche doesn’t force you to do so, and you can always use
require
and import
separately. However, all
modules provided with Gauche are arranged so that they can be
used by use
macro.
If a module is too big to fit in one file, you can split them into several subfiles and one main file. The main file defines the module, and either loads, requires, or autoloads subfiles.
Actually, the file pathname of the given module name is
obtained by the procedure module-name->path
below.
The default rule is to replace periods ‘.
’ in the name
for ‘/
’; for example,
(use foo.bar.baz)
is expanded to:
(require "foo/bar/baz") (import foo.bar.baz)
This is not very Scheme-ish way, but nevertheless convenient. In future, there may be some mechanism to customize this mapping.
The file to be use
’d must have explicit module selection
to have any toplevel definitions
(usually via define-module
/select-module
pair
or define-library
). If you get an error saying
“Attempted to create a binding in a sealed module:
module: #<module gauche.require-base>”, that’s because the file
lacks module selection. See Require and provide, for further
discussion.
The export-import mechanism doesn’t work well in some cases, such as:
You can use module inheritance in these cases.
Makes the current module inherit from named modules. The current inheritance information is altered by the inheritance information calculated from given modules.
A new module inherits from gauche
module when created.
If you put (extend scheme)
in that module, for example,
the module resets to inherit directly from scheme
module
that has only bindings defined in R5RS, hence, after the extend
form, you can’t use ’import’ or any other gauche
-specific
bindings in the module.
If a named module is not defined yet, extend
tries to load it, using the same convention use
macro does.
A module can inherit multiple modules, exactly the same way as a class can inherit from multiple classes. The resolution of order of inheritance needs to be explained a bit.
Each module has a module precedence list, which lists
modules in the order of how they are searched. When the module
inherits multiple modules, module precedence lists of inherited
modules are merged into a single list, keeping the constraints
that: (1) if a module A appears before module B in some module
precedence list, A has to appear before B in the resulting module
precedence list; and (2) if a module A appears before module B
in extend
form, A has to appear before B in the resulting
module precedence list. If no precedence list can be constructed
with these constraints, an error is signaled.
For example, suppose you wrote a library in modules
mylib.base
, mylib.util
and mylib.system
.
You can bundle those modules into one module by creating
a module mylib
, as follows:
(define-module mylib (extend mylib.system mylib.util mylib.base))
The user of your module just says (use mylib)
and
all exported symbols from three submodules become available.
This subsection lists procedures that operates on modules at run-time. With these procedures you can introspect the modules, create new modules procedurally, or check the existence of certain modules/libraries, for example. However, don’t forget that modules are primarily compile-time structures. Tweaking modules at run-time is only for those who know what they are doing.
A module class.
Returns true if obj is a module.
Returns a module object whose name is a symbol name.
If the named module doesn’t exist, #f
is returned.
Creates and returns a module that has symbol name.
If the named module already exists, the behavior is specified by
if-exists keyword argument. If it is :error
(default),
an error is signaled. If it is #f
, #f
is returned.
Note that creating modules on-the-fly isn’t usually necessary
for ordinal scripts, since executing already written program requires modules
to be specified by name, i.e. syntax define-module
, import
,
extend
, with-module
all take module names, not
module objects.
It is because module are inherently compile-time structures.
However, there are some cases that dynamically created modules
are useful, especially when the program itself is dynamically created.
You can pass a module to eval
to compile and
evaluate such dynamically created
programs in it (see Eval and repl).
You can also pass #f
to name to create
anonymous module. Anonymous modules can’t be
looked up by find-module
, nor can be imported
or inherited (since import
and extend
take
module names, not modules).
It is useful when you want to have a temporary, segregated namespace
dynamically—for example, you can create an anonymous module
to evaluate code fragments sent from other program, and
discards the module when the connection is terminated.
Anonymous modules are not registered in the system dictionary
and are garbage collected when nobody keeps reference to it.
R7RS provides another way to create a transient module
with environment
procedure. see scheme.eval
- R7RS eval for the
details.
Returns a list of all named modules. Anonymous modules are not included.
Accessors of a module object. Returns the name of the module (a symbol), list of imported modules, list of exported symbols, and a hash table that maps symbols to bindings, of the module are returned, respectively.
It is an error to pass a non-module object.
If you want to check if a specific symbol is exported from a module,
use module-exports?
below instead of taking all exported
symbols with module-exports
and search from it. It is much
faster to use module-exports?
.
Returns the information of module inheritance.
Module-parents
returns the modules module directly inherits
from. Module-precedence-list
returns the module precedence
list of module (see Module inheritance).
Returns #t
if symbol’s global binding is visible
from inside module, #f
otherwise. That is,
if (module-binds? 'M 'v)
returns #t
,
v
can be used as a globally bound identifier
(either a variable or a syntactic keyword)
in the module M
.
Module must be a module object or
a symbol name of an existing module.
This deals with the view from inside module, so it isn’t affected
whether the named variable is exported from module, or if so,
whether it is renamed on export. If you need to test a variable
from the viewpoint external to module,
see module-exports?
below.
Note: Lisp traditionally has symbol-bound?
procedure to
check whether a global variable is bound, but we feel the name
focuses too much on symbols, whereas global bindings are managed
by modules in Gauche. Previous versions of Gauche uses
the name global-variable-bound?
and it is still kept for
the backward compatibility, but we decided on the current name
to be clear that it is about modules, and it is not only about
variables.
Returns #t
if the binding of symbol is visible from outside
module, #f
otherwise.
That is, if (module-exports? 'M 'v)
returns #t
,
v
can be used as a globally bound identifier
(either as a variable or a syntactic keyword)
in the module that imports module M
.
Module must be a module object or
a symbol name of an existing module.
Unlike module-binds?
, this checks the outside appearance
of the binding. Suppose you have those modules:
(define-module M (export a (rename b bee)) (define a 1) (define b 2) (define c 3))
module-binds?
concerns how the binding are visible in M
.
So it returns #t
for a
, b
, and c
,
but not for bee
, as in the following example:
(module-binds? 'M 'a) ⇒ #t (module-binds? 'M 'b) ⇒ #t (module-binds? 'M 'c) ⇒ #t (module-binds? 'M 'bee) ⇒ #f ; renamed export doesn't affect in M
module-exports?
concerts how the bindings are visible outside of
M
. So it returns #t
for a
and bee
, but
not for b
and c
, as in the following example.
(module-exports? 'M 'a) ⇒ #t (module-exports? 'M 'b) ⇒ #f ; because of renamed export (module-exports? 'M 'c) ⇒ #f ; not exported (module-exports? 'M 'bee) ⇒ #t ; external name
Returns a value globally bound to the symbol inside module. Module must be a module object or a symbol name of an existing module. If there’s no visible global binding inside module for symbol, an error is signaled, unless the default argument is provided, in which case it is returned instead.
This used to be called as global-variable-ref
, but we changed
the name to be clear that it is module’s operation, and the binding
can be not only variables but also syntactic keywords.
You can still use the old name but it is deprecated.
Deprecated.
Old name for module-binds?
and module-binding-ref
,
respectively. Use new names for the new code.
Converts a module name symbol to a fragment of pathname string
(which you use for require
and provide
).
Reverse function of module-name->path
.
If you want to find out specific libraries and/or modules are installed in the system and available from the program, see Operations on libraries.
Several modules are predefined in Gauche.
This module corresponds to the null environment referred in R5RS. This module contains only syntactic bindings of R5RS syntax.
This module contains all the binding of null
module,
and the binding of procedures defined in R5RS.
Note that if you change the current module to null
or
scheme
by select-module
, there will be no way
to switch back to other modules, since module-related syntaxes
and procedures are not visible from null
and scheme
modules.
This module contains all the bindings of scheme
module,
plus Gauche specific built-in procedures.
This module is the default module the user code is compiled.
all the bindings of gauche
module is imported.
When Gauche is running with GAUCHE_KEYWORD_IS_SYMBOL
mode (default)
keywords (symbols beginning with :
) is automatically bound
to itself in these modules.
(see Keywords, for the details.)
The keyword
module doesn’t export those bindings, while
gauche.keyword
does. The former is intended to be
used internally; the programmer need to know the latter.
If you use the default module inheritance,
you don’t need to use this module, since
the keyword
module is included in the inheritance chain.
If you don’t inherit gauche
module, however, importing the
gauche.keyword
module gives you access to the keywords without quotes.
For example, R7RS programs
and libraries would require either (import (gauche keyword))
or (import (gauche base))
(the latter inherits
gauche.keyword
), or you have to quote all keywords.
The following R7RS program imports gauche.base
; it makes gauche
built-in identifiers, and all self-bound keywords, available:
;; R7RS program (import (scheme base) (gauche base)) ; import gauche builtins and keywords ;; You can use :directory without quote, for it is bound to itself. (sys-exec "ls" '("ls" "-l") :directory "/")
If you use more sophisticated import tricks, however, keep in mind
that keywords are just imported symbols by default.
The following code imports
Gauche builtin identifiers with prefix gauche/
. That causes
keywords, imported via inheritance, also get the same prefix; if
you don’t want to bother adding prefix to all keywords or
quote them, import gauche.keyword
separately.
;; R7RS program (import (scheme base) (prefix (gauche base) gauche/) ; use gauche builtin with gauche/ prefix (gauche keyword)) ; imports keywords ;; Without importing gauche.keyword, ;; you need to write ':directory (gauche/sys-exec "ls" '("ls" "-l") :directory "/")
This is a module when use
or require
load the file.
This is not meant to be use
d directly; just to prevent
library files lacking module switching from causing unexpected
side effects. See Using modules, for more details.