Google

PLT MzScheme: Language Manual


Namespaces

MzScheme supports multiple namespaces for top-level variable bindings, syntax bindings, module imports, and module declarations.

A new namespace is created with the make-namespace procedure, which returns a first-class namespace value. A namespace is used by setting the current-namespace parameter value (see section 7.4.1.5), or providing the namespace as the second argument to eval. The MzScheme versions of the R5RS procedures scheme-report-environment and null-environment produce namespaces.12

The current namespace is used by eval, load, compile, expand, and expand-once.13 After an expression is evaled, 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.

Example:

(define x 'orig) ; define in the original namespace  
;; The following let expression is compiled in the original  
;; namespace, so direct references to x 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 two top-level environments: one for normal expressions, and one for macro transformer expressions; see section 12 for more information about the transformer 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 variable or syntax bindings, and its module instances and imports are distinct from the instances and imports of the normal top-level environment.

8.1  Identifier Resolution in Namespaces

Identifier resolution in the 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) xx ; => 5 
(f) ; => 5 
(define-syntax x (syntax-rules ())) 
x ; =>  bad syntax 
(f) ; => 5 
(define x 7x ; => 7 
(f) ; => 7 
(module m mzscheme (define x 8) (provide x)) 
(require mx ; => 8 
(f) ; => 7 

8.2  Initial Namespace

In the stand-alone MzScheme application, the initial namespace contains module declarations for mzscheme and the primitive #%-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; 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]) returns a value for symbol in the current namespace. The returned value depends on use-mapping?:

  • If use-mapping? is true (the default), and if symbol maps to a top-level variable or an imported variable (see section 8.1), then the result is the same as evaluating symbol as an expression. If symbol maps to syntax or imported syntax, the exn:syntax exception is raised (or failure-thunk is called; see below). If symbol is mapped to an undefined variable or an uninitialized module variable, the exn:variable exception is raised (or failure-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 named symbol in namespace is returned. If the variable is undefined, the exn:variable exception is raised (or failure-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:variable or exn:syntax exception.

(namespace-set-variable-value! symbol v [map?]) sets the value of symbol in the top-level environment of 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-mapped-symbols) returns a list of all symbols that are mapped to variables, syntax, and imports in the current namespace.

(namespace-require quoted-require-spec) performs the import corresponding to quoted-require-spec in the top-level environment (like a top-level require expression). See also Chapter 5.

(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.

(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-symbol) attaches the instantiated module named module-symbol in src-namespace to the current namespace, using module-symbol as the module name in the current namespace. In addition to the module-symbol module itself, every module that it imports (directly or indirectly) is also transferred into the current namespace. If module-symbol is not the name of an instantiated module in src-namespace, or if the name of any module to be transferred already has a different declaration or instance in the current namespace, then the exn:application:mismatch exception is raised.


12 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.

13 More precisely, the current namespace is used by the evaluation and load handlers, rather than directly by eval and load.