6.18.6 R6RS Libraries

In addition to the API described in the previous sections, you also have the option to create modules using the portable library form described in R6RS (see R6RS Library Form in The Revised^6 Report on the Algorithmic Language Scheme), and to import libraries created in this format by other programmers. Guile’s R6RS library implementation takes advantage of the flexibility built into the module system by expanding the R6RS library form into a corresponding Guile define-module form that specifies equivalent import and export requirements and includes the same body expressions. The library expression:

  (library (mylib (1 2))
    (export mybinding)
    (import (otherlib (3))))

is equivalent to the module definition:

  (define-module (mylib)
    #:version (1 2)
    #:use-module ((otherlib) #:version (3))
    #:export (mybinding))

Central to the mechanics of R6RS libraries is the concept of import and export levels, which control the visibility of bindings at various phases of a library’s lifecycle — macros necessary to expand forms in the library’s body need to be available at expand time; variables used in the body of a procedure exported by the library must be available at runtime. R6RS specifies the optional for sub-form of an import set specification (see below) as a mechanism by which a library author can indicate that a particular library import should take place at a particular phase with respect to the lifecycle of the importing library.

Guile’s library implementation uses a technique called implicit phasing (first described by Abdulaziz Ghuloum and R. Kent Dybvig), which allows the expander and compiler to automatically determine the necessary visibility of a binding imported from another library. As such, the for sub-form described below is ignored by Guile (but may be required by Schemes in which phasing is explicit).

Scheme Syntax: library name (export export-spec ...) (import import-spec ...) body ...

Defines a new library with the specified name, exports, and imports, and evaluates the specified body expressions in this library’s environment.

The library name is a non-empty list of identifiers, optionally ending with a version specification of the form described above (see Creating Guile Modules).

Each export-spec is the name of a variable defined or imported by the library, or must take the form (rename (internal-name external-name) ...), where the identifier internal-name names a variable defined or imported by the library and external-name is the name by which the variable is seen by importing libraries.

Each import-spec must be either an import set (see below) or must be of the form (for import-set import-level ...), where each import-level is one of:

  (meta level)

where level is an integer. Note that since Guile does not require explicit phase specification, any import-sets found inside of for sub-forms will be “unwrapped” during expansion and processed as if they had been specified directly.

Import sets in turn take one of the following forms:

  (library library-reference)
  (only import-set identifier ...)
  (except import-set identifier ...)
  (prefix import-set identifier)
  (rename import-set (internal-identifier external-identifier) ...)

where library-reference is a non-empty list of identifiers ending with an optional version reference (see R6RS Version References), and the other sub-forms have the following semantics, defined recursively on nested import-sets:

  • The library sub-form is used to specify libraries for import whose names begin with the identifier “library.”
  • The only sub-form imports only the specified identifiers from the given import-set.
  • The except sub-form imports all of the bindings exported by import-set except for those that appear in the specified list of identifiers.
  • The prefix sub-form imports all of the bindings exported by import-set, first prefixing them with the specified identifier.
  • The rename sub-form imports all of the identifiers exported by import-set. The binding for each internal-identifier among these identifiers is made visible to the importing library as the corresponding external-identifier; all other bindings are imported using the names provided by import-set.

Note that because Guile translates R6RS libraries into module definitions, an import specification may be used to declare a dependency on a native Guile module — although doing so may make your libraries less portable to other Schemes.

Scheme Syntax: import import-spec ...

Import into the current environment the libraries specified by the given import specifications, where each import-spec takes the same form as in the library form described above.