Namespaces
MzScheme supports multiple namespaces for top-level variable bindings, syntax bindings, module imports, and module declarations.
A new namespace is created with the
procedure,
which returns a first-class namespace value. A namespace is used by
setting the make-namespace
parameter value (see
section 7.9.1.5), by providing the namespace to
procedures such as current-namespace
and eval
eval-syntax
. The
MzScheme versions of the R5RS procedures
scheme-report-environment
and null-environment
produce namespaces.22
The current namespace is used by many procedures, including
, eval
, load
, and
compile
.23 After an expression is
expand
ed, the global variable references in the expression are
permanently attached to a particular namespace, so the current
namespace at the time that the code is executed is not used as
the namespace for referencing global variables in the expression.eval
Example:
(define x 'orig) ; define in the original namespace ;; The followinglet
expression is compiled in the original ;; namespace, so direct references tox
see'orig
. (let ([n (make-namespace
)]) ; make new namespace (parameterize ([current-namespace
n]) (eval
'(define x 'new)) ; evals in the new namespace (display
x) ; displays 'orig (display
(eval
'x)))) ; displays 'new
A namespace actually encapsulates three top-level environments: one for normal expressions, one for macro transformer expressions, and one for macro templates; see section 12 for more information about the transformer environment, and see section 12.3.4 for more information about the template environment. Module declarations are shared by the environments, but module instances, variable bindings, syntax bindings, and module imports are distinct. More precisely, the transformer environment never contains any syntax bindings, and its variables, module instances, and module imports are distinct from the variables, module instances, and module imports of the normal top-level environment. The template environment contains module imports, only.
Each namespace has a module registry that maps module names
to module declarations (see Chapter 5). The
module->namespace
procedure returns a namespace with the
same module registry as the current namespace, but whose environment
and bindings correspond to the body of an instantiated module. (This
facility is primarily useful for debugging, and its use is limited by
the current code inspector; see also section 9.4.)
8.1 Identifier Resolution in Namespaces
Identifier resolution in a namespace's top-level environment, for compilation or expansion, proceeds in two steps. First, the environment determines whether the identifier is mapped to a top-level variable, to syntax, or to a module import (which can be either syntax or a variable). Second, if the identifier is mapped to a top-level variable, then the variable's location is found; if the identifier is mapped to syntax, then the expansion-time binding is found; and if the identifier is mapped to an import, then the source module is consulted.
Importing a variable from a module with require
is not
the same as defining the variable; the import does not create a new
top-level variable in the environment, but instead maps an identifier
to the module's variable, in the same way that a syntax definition
maps an identifier to a transformer.
Redefining a previously-defined variable is the same as mutating the
variable with set!
. Rebinding a syntax-bound or import-bound
identifier (to syntax or an import) replaces the old binding with the
new one for future uses of the environment.
If an identifier is bound to syntax or to an import, then defining the identifier as a variable shadows the syntax or import in future uses of the environment. Similarly, if an identifier is bound to a top-level variable, then binding the identifier to syntax or an import shadows the variable; the variable's value remains unchanged, however, and may be accessible through previously evaluated expressions.
Example:
(define x 5) (define (f) x) x ; =>5
(f) ; =>5
(define-syntaxx
(syntax-rules ()))x
; => bad syntax (f) ; =>5
(define x 7) x ; =>7
(f) ; =>7
(module mmzscheme
(define x 8) (provide x)) (require m) x ; =>8
(f) ; =>7
8.2 Initial Namespace
In the stand-alone MzScheme application, the initial namespace's
module registry contains declarations for
and the
primitive mzscheme
#%
-named modules (see section 5.7). The
normal top-level environment of the initial namespace contains
imports for all MzScheme syntax, and it contains variable bindings
(as opposed to imports) for every built-in procedure and constant.
The transformer top-level environment of the initial namespace
imports all MzScheme syntax, procedures, and constants.
Applications embedding MzScheme may extend or modify the set of
initial bindings, but they will usually only add primitive modules
with #%
-prefixed names. (MrEd adds #%mred-kernel
for its graphical toolbox.)
8.3 Namespace Utilities
(make-namespace
[flag-symbol
])
creates a new namespace with a
new module registry; the flag-symbol
is an option that
determines the initial bindings in the namespace. The allowed values
for flag-symbol
are:
'initial
(the default) -- the new namespace contains the module declarations of the initial namespace (see section 8.2), and the new namespace's normal top-level environment contains bindings and imports as in the initial namespace. However, the namespace's transformer top-level environment is empty.'empty
-- creates a namespace with no initial bindings or module declarations.
(namespace?
v
)
returns #t
if v
is a namespace value,
#f
otherwise.
(namespace-symbol->identifier
symbol
)
is similar to
datum->syntax-object
(see section 12.2.2) restricted to
symbols. The lexical context of the resulting identifier corresponds
to the top-level environment of the current namespace; the identifier
has no source location or properties.
(namespace-variable-value
symbol
[use-mapping? failure-thunk
namespace
])
returns a value for symbol
in namespace
, where
namespace
defaults to the current namespace. The returned value
depends on use-mapping?
:
If
use-mapping?
is true (the default), and ifsymbol
maps to a top-level variable or an imported variable (see section 8.1), then the result is the same as evaluatingsymbol
as an expression. Ifsymbol
maps to syntax or imported syntax, theexn:fail:syntax
exception is raised (orfailure-thunk
is called; see below). Ifsymbol
is mapped to an undefined variable or an uninitialized module variable, theexn:fail:contract:variable
exception is raised (orfailure-thunk
is called).If
use-mapping?
is false, the namespace's syntax and import mappings are ignored. Instead, the value of the top-level variable namedsymbol
in namespace is returned. If the variable is undefined, theexn:fail:contract:variable
exception is raised (orfailure-thunk
is called).
If failure-thunk
is provided, namespace-variable-value
calls failure-thunk
to produce the return value in place of
raising an exn:fail:contract:variable
or exn:fail:syntax
exception.
(namespace-set-variable-value!
symbol v
[map? namespace
])
sets
the value of symbol
in the top-level environment of
namespace
(where namespace
defaults to the current
namespace) defining symbol
if it is not already defined. If
map?
is supplied as true, then the namespace's identifier
mapping is also adjusted (see section 8.1) so that
symbol
maps to the variable. The default value for
map?
is #f
.
(namespace-undefine-variable!
symbol namespace
)
removes the
symbol
variable, if any, in the top-level environment of the
namespace
, where namespace
defaults to the current
namespace. The namespace's identifier mapping is unaffected.
(namespace-mapped-symbols
[namespace
])
returns a list of all
symbols that are mapped to variables, syntax, and imports in
namespace
, where namespace
defaults to the current
namespace.
(namespace-require
quoted-require-spec
)
performs the import
corresponding to quoted-require-spec
in the top-level
environment of the current namespace (like a top-level
require
expression). See also Chapter 5. Module
paths in quoted-require-spec
are not resolved with respect to
any other module, even if the current namespace corresponds to a
module body.
(namespace-transformer-require
quoted-require-spec
)
performs the
import corresponding to quoted-require-spec
in the top-level
transformer environment (like a top-level require-for-syntax
expression). See also Chapter 5. Module paths in
quoted-require-spec
are not resolved with respect to any other
module, even if the current namespace corresponds to a module body.
(namespace-require/copy
quoted-require-spec
)
is like
namespace-require
for syntax exported from the module, but
exported variables are treated differently: the export's current
value is copied to a top-level variable in the current namespace.
(namespace-require/expansion-time
quoted-require-spec
)
is like
namespace-require
, but only the transformer part of the
module is executed. If the required module has not been invoked
before, the module's variables remain undefined.
(namespace-attach-module
src-namespace
module-path-v
[dest-namespace
])
attaches the instantiated
module named by module-path-v
in src-namespace
to
the registry of dest-namespace
(which is the current namespace
if dest-namespace
is not supplied). If module-path-v
is not a symbol, the current module name resolver is called to
resolve the path, but no module is loaded; the resolved form of
module-path-v
is used as the module name in
dest-namespace
. In addition to module-path-v
, every module that it imports
(directly or indirectly) is also recorded in the current namespace's
registry. If module-path-v
does not refer to an instantiated
module in src-namespace
, or if the name of any module to be
attached already has a different declaration or instance in
dest-namespace
, then the exn:fail:contract
exception is raised. The
inspector of the module invocation in dest-namespace
is the
same as inspector of the invocation in src-namespace
.
(namespace-unprotect-module
inspector module-path-v
)
namespace
changes the inspector for the instance of the module referenced by
module-path-v
in namespace
's registry so that it is
controlled by the current code inspector. If namespace
is not
supplied, it is the current namespace. The given inspector
must
currently control the invocation of the module in namespace
's
registry, otherwise the exn:fail:contract
exception is raised. See also
section 9.4.
(namespace-module-registry
namespace
)
returns the registry of the
given namespace. This value is useful only for identification via
.eq?
(module->namespace
module-path-v
)
returns a namespace that
corresponds to the body of an instantiated module in the current
namespace's registry. The returned namespace has the same module
registry as the current namespace. Modifying a binding in the
namespace changes the binding seen in modules that require the
namespace's module. Module paths in a top-level require
expression are resolved with respect to the namespace's module. New
provide
declarations are not allowed. If the current code
inspector does not control the invocation of the module in the
current namespace's registry, the exn:fail:contract
exception is raised; see
also section 9.4. Bindings in the namespace cannot be
modified if the compile-enforce-module-constants
parameter
was true when the module was declared, unless the module declaration
itself included assignments to the binding via set!
.
(namespace-syntax-introduce
stx
)
returns a syntax object like
stx
, except that the current namespace's bindings are included
in the syntax object's context (see section 12.3). The
additional context is overridden by any existing top-level context in
the syntax object, or by any existing or future module context. See
section 12.2 for more information about syntax objects.
(module-provide-protected?
module-path-index symbol
)
returns
#f
if the module declaration for module-path-index
defines symbol
and exports it unprotected, #t
otherwise (which may mean that the symbol corresponds to an
unexported definition, a protected export, or an identifier that is
not defined at all within the module). The module-path-index
argument can be a symbol; see section 5.4.2 for more information
on module path indices. Typically, the arguments to
correspond to the first two
elements of a list produced by module-provide-protected?
(see
section 12.3).identifier-binding
22 The resulting namespace contains syntax
imports for #%app
, #%datum
, and #%top
,
because syntax expansion requires them (see section 12.5), but
those names are not legal R5RS identifiers.
23 More precisely, the current namespace is
used by the evaluation and load handlers, rather than directly by
and eval
.load