1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
@node Using the module system
@section Using the module system
Scheme48 is deeply integrated with an advanced module system. For
complete detail of its module system, @pxref{Module system}. Briefly,
however:
@itemize
@item @dfn{Packages} are top-level environments suitable for
evaluating expressions and definitions, either interactively, from
files loaded on-the-fly, or as the bodies of modules. They can also
access bindings exported by structures by @dfn{opening} the
structures.
@item @dfn{Structures} are libraries, or implementations of
interfaces, exporting sets of bindings that packages can access.
Underlying structures are usually packages, in which the user can, in
some cases, interactively evaluate code during development.
@end itemize
Scheme48's usual development system, the command processor, provides a
number of commands for working with the module system. For complete
details, @pxref{Module commands}. Chief among these commands are
@command{,open} and @command{,in}. @samp{,open @var{struct} @dots{}}
makes all of the bindings from each of @var{struct} @dots{} available
in the interaction environment. Many of the sections in this manual
describe one or more structures with the name they are given. For
example, in order to use, or open, the multi-dimensional array library
in the current interaction environment, one would enter
@lisp
,open arrays@end lisp
@noindent
to the command processor. @samp{,in @var{struct}} sets the
interaction environment to be the package underlying @var{struct}.
For instance, if, during development, the user decides that the
package of the existing structure @code{foo} should open the structure
@code{bar}, he might type
@lisp
,in foo
,open bar@end lisp
Module descriptions, or code in the @embedref{Module configuration
language, module configuration language} should be loaded into the
special environment for that language with the @code{,config} command
(@pxref{Module commands}). @Eg{}, if @file{packages.scm} contains a
set of module descriptions that the user wishes to load, among which
is the definition of a structure @code{frobozz} which he wishes to
open, he will typically send the following to the command processor
prompt:
@lisp
,config ,load packages.scm
,open frobozz@end lisp
@strong{Note:} These are commands for the interactive command
processor, @emph{not} special directives to store in files to work
with the module system. The module language is disjoint from Scheme;
for complete detail on it, @pxref{Module system}.
@subsection Configuration mutation
@i{(This section was derived from work copyrighted (C) 1993-2005 by
Richard Kelsey, Jonathan Rees, and Mike Sperber.)}
@cindex code reloading
@cindex reloading code
@texonlyindent
During program development, it is often desirable to make changes to
packages and interfaces. In static languages, it is usually necessary
to re-compile and re-link a program in order for such changes to be
reflected in a running system. Even in interactive Common Lisp
systems, a change to a package's exports often requires reloading
clients that have already mentioned names whose bindings change. In
those systems, once @code{read} resolves a use of a name to a symbol,
that resolution is fixed, so a change in the way that a name resolves
to a symbol can be reflected only by re-@code{read}ing all such
references.
The Scheme48 development environment supports rapid turnaround in
modular program development by allowing mutations to a program's
configuration and giving a clear semantics to such mutation. The rule
is that variable bindings in a running program are always resolved
according to the current structure and interface bindings, even when
these bindings change as a result of edits to the configuration. For
example, consider the following:
@lisp
(define-interface foo-interface (export a c))
(define-structure foo foo-interface
(open scheme)
(begin (define a 1)
(define (b x) (+ a x))
(define (c y) (* (b a) y))))
(define-structure bar (export d)
(open scheme foo)
(begin (define (d w) (+ (b w) a))))@end lisp
This program has a bug. The variable named @code{b}, which is free in
the definition of @code{d}, has no binding in @code{bar}'s package.
Suppose that @code{b} was intended to be exported by @code{foo}, but
was mistakenly omitted. It is not necessary to re-process @code{bar} or
any of @code{foo}'s other clients at this point. One need only change
@code{foo-interface} and inform the development system of that change
(using, say, an appropriate Emacs command), and @code{foo}'s binding of
@code{b} will be found when the procedure @code{d} is called and its
reference to @code{b} actually evaluated.
Similarly, it is possible to replace a structure; clients of the old
structure will be modified so that they see bindings from the new one.
Shadowing is also supported in the same way. Suppose that a client
package @var{C} opens a structure @code{mumble} that exports a name
@code{x}, and @code{mumble}'s implementation obtains the binding of
@code{x} from some other structure @code{frotz}. @var{C} will see the
binding from @code{frotz}. If one then alters @code{mumble} so that it
shadows @code{bar}'s binding of @code{x} with a definition of its own,
procedures in @var{C} that refer to @code{x} will subsequently
automatically see @code{mumble}'s definition instead of the one from
@code{frotz} that they saw earlier.
This semantics might appear to require a large amount of computation on
every variable reference: the specified behaviour appears to require
scanning the package's list of opened structures and examining their
interfaces --- on every variable reference evaluated, not just at
compile-time. However, the development environment uses caching with
cache invalidation to make variable references fast, and most of the
code is invoked only when the virtual machine traps due to a reference
to an undefined variable.
@subsection Listing interfaces
@cindex interfaces
@stindex list-interfaces
The @code{list-interfaces} structure provides a utility for examining
interfaces. It is usually opened into the config package with
@code{,config ,open list-interfaces} in order to have access to the
structures & interfaces easily.
@deffn procedure list-interface struct-or-interface @returns{} unspecified
Lists all of the bindings exported by @var{struct-or-interface} along
with their @embedref{Static type system, static types}. For example,
@lisp
> ,config ,open list-interfaces
> ,config (list-interface condvars)
condvar-has-value? (proc (:condvar) :value)
condvar-value (proc (:condvar) :value)
condvar? (proc (:value) :boolean)
make-condvar (proc (&rest :value) :condvar)
maybe-commit-and-set-condvar! (proc (:condvar :value) :boolean)
maybe-commit-and-wait-for-condvar (proc (:condvar) :boolean)
set-condvar-has-value?! (proc (:condvar :value) :unspecific)
set-condvar-value! (proc (:condvar :value) :unspecific)@end lisp
@end deffn
|