Next: , Previous: , Up: scheme library   [Index]


3.7.2 Import and export levels

Expanding a library may require run–time information from another library. For example, if a macro transformer calls a procedure from library A, then the library A must be instantiated before expanding any use of the macro in library B. Library A may not be needed when library B is eventually run as part of a program, or it may be needed for run time of library B, too. The library mechanism distinguishes these times by phases, which are explained in this section.

Every library can be characterized by expand–time information (minimally, its imported libraries, a list of the exported keywords, a list of the exported variables, and code to evaluate the transformer expressions) and run–time information (minimally, code to evaluate the variable definition right–hand–side expressions, and code to evaluate the body expressions). The expand–time information must be available to expand references to any exported binding, and the run–time information must be available to evaluate references to any exported variable binding.

A phase is a time at which the expressions within a library are evaluated. Within a library body, top–level expressions and the right–hand sides of define forms are evaluated at run time, i.e. phase 0, and the right–hand sides of define-syntax forms are evaluated at expand time, i.e. phase 1. When define-syntax, let-syntax, or letrec-syntax forms appear within code evaluated at phase n, the right–hand sides are evaluated at phase n+1.

These phases are relative to the phase in which the library itself is used. An instance of a library corresponds to an evaluation of its variable definitions and expressions in a particular phase relative to another library—a process called instantiation. For example, if a top–level expression in a library B refers to a variable export from another library A, then it refers to the export from an instance of A at phase 0 (relative to the phase of B). But if a phase 1 expression within B refers to the same binding from A, then it refers to the export from an instance of A at phase 1 (relative to the phase of B).

A visit of a library corresponds to the evaluation of its syntax definitions in a particular phase relative to another library; a process called visiting. For example, if a top–level expression in a library B refers to a macro export from another library A, then it refers to the export from a visit of A at phase 0 (relative to the phase of B), which corresponds to the evaluation of the macro’s transformer expression at phase 1.

A level is a lexical property of an identifier that determines in which phases it can be referenced. The level for each identifier bound by a definition within a library is 0; that is, the identifier can be referenced only at phase 0 within the library. The level for each imported binding is determined by the enclosing for form of the import in the importing library, in addition to the levels of the identifier in the exporting library. Import and export levels are combined by pairwise addition of all level combinations. For example, references to an imported identifier exported for levels p_a and p_b and imported for levels q_a, q_b, and q_c are valid at levels p_a + q_a, p_a + q_b, p_a + q_c, p_b + q_a, p_b + q_b, and p_b + q_c. An ?import-set without an enclosing for is equivalent to (for ?import-set run), which is the same as (for ?import-set (meta 0)).

The export level of an exported binding is 0 for all bindings that are defined within the exporting library. The export levels of a reexported binding, i.e. an export imported from another library, are the same as the effective import levels of that binding within the reexporting library.

For the libraries defined in the library report, the export level is 0 for nearly all bindings. The exceptions are syntax-rules, identifier-syntax, ..., and _ from the (rnrs base (6)) library, which are exported with level 1, set! from the (rnrs base (6)) library, which is exported with levels 0 and 1, and all bindings from the composite (rnrs (6)) library, which are exported with levels 0 and 1.

Macro expansion within a library can introduce a reference to an identifier that is not explicitly imported into the library. In that case, the phase of the reference must match the identifier’s level as shifted by the difference between the phase of the source library (i.e., the library that supplied the identifier’s lexical context) and the library that encloses the reference. For example, suppose that expanding a library invokes a macro transformer, and the evaluation of the macro transformer refers to an identifier that is exported from another library (so the phase 1 instance of the library is used); suppose further that the value of the binding is a syntax object representing an identifier with only a level n binding; then, the identifier must be used only at phase n+1 in the library being expanded. This combination of levels and phases is why negative levels on identifiers can be useful, even though libraries exist only at non–negative phases.

If any of a library’s definitions are referenced at phase 0 in the expanded form of a program, then an instance of the referenced library is created for phase 0 before the program’s definitions and expressions are evaluated. This rule applies transitively: if the expanded form of one library references at phase 0 an identifier from another library, then before the referencing library is instantiated at phase n, the referenced library must be instantiated at phase n. When an identifier is referenced at any phase n greater than 0, in contrast, then the defining library is instantiated at phase n at some unspecified time before the reference is evaluated. Similarly, when a macro keyword is referenced at phase n during the expansion of a library, then the defining library is visited at phase n at some unspecified time before the reference is evaluated.

An implementation may distinguish instances/visits of a library for different phases or to use an instance/visit at any phase as an instance/visit at any other phase. An implementation may further expand each library form with distinct visits of libraries in any phase and/or instances of libraries in phases above 0. An implementation may create instances/visits of more libraries at more phases than required to satisfy references. When an identifier appears as an expression in a phase that is inconsistent with the identifier’s level, then an implementation may raise an exception either at expand time or run time, or it may allow the reference. Thus, a library whose meaning depends on whether the instances of a library are distinguished or shared across phases or library expansions may be unportable.


Next: , Previous: , Up: scheme library   [Index]