R5RS had no module system: a program was a sequence of definitions in one global environment, and each implementation invented its own way to split code over files. R6RS (2007) and R7RS-small (2013) added libraries, and they did it differently, so the two are not interchangeable. This page describes both and then the older module systems that implementations still use.
R7RS libraries
A library is one define-library form:
(define-library (example grid)
(export make rows cols ref each
(rename put! set!))
(import (scheme base))
(begin
(define (make n m) ...)
(define (put! grid n m v) ...)))
The library name is a list of identifiers and exact non-negative integers, which identifies the library when other code imports it. Names whose first element is scheme are reserved for the report and its successors, and those starting with srfi for SRFI libraries ((srfi 1), (srfi 69)). Using the characters | \ ? * < " : > + [ ] / in a name is inadvisable but not an error, because they are unsafe in file names.
Library declarations
| Declaration | Meaning |
|---|---|
(export spec ...) | The bindings that other code can import. A spec is an identifier, or (rename internal external) |
(import set ...) | The bindings the library uses, as in a program |
(begin command-or-definition ...) | The body of the library, evaluated in order when it is loaded |
(include "file" ...), (include-ci "file" ...) | The body, read from files (the second with case folding) |
(include-library-declarations "file" ...) | Declarations read from files and spliced in, so that several libraries can share one export list |
(cond-expand clause ...) | Chooses declarations by feature, at expansion time |
When a library is loaded its expressions run in textual order. A library whose definitions are referenced by another must be loaded before it, and so on transitively; a syntax keyword needed to expand a library requires the library that defines it to be expanded and its syntax definitions evaluated first. A library imported by several others may possibly be loaded more than once, but each program or library that imports from it must do so from a single loading, so two import declarations of one library have the same effect as one. R7RS has no versions and no phases.
Programs and import
An R7RS program starts with one or more import declarations, then expressions and definitions. An import set is one of:
| Import set | Meaning |
|---|---|
(example grid), a library name | Every export of the library under its exported name. (R6RS also accepts (library (example grid)) for the same thing.) |
(only set id ...) | Only the listed identifiers; it is an error if one is not in the set |
(except set id ...) | All but the listed identifiers |
(prefix set id) | Every identifier with the prefix added |
(rename set (old new) ...) | Renames; the new names must not clash |
It is an error to import one identifier twice with different bindings, to redefine or set! an imported binding, or to use an identifier before it is imported (a REPL may allow all three). The initial environment of an R7RS program is empty, so at least (import (scheme base)) is usual. A REPL starts with the bindings of at least (scheme base).
(import (scheme base)
(only (example life) life)
(rename (prefix (example grid) grid-)
(grid-make make-grid)))
life only, and the grid library with a prefix and then one rename.R6RS libraries
(library (example grid (1 0))
(export make rows cols ref (rename put! set!))
(import (rnrs base) (rnrs lists))
(define (make n m) ...)
(define (put! grid n m v) ...))
- Name and version. A library name is a list of identifiers, optionally ending in a version, a list of exact non-negative integers:
(example grid (1 0)). The version of an empty list()is the default. - Body. After the
exportandimportclauses come definitions and then expressions, without abegin. Definitions are evaluated left to right as in an implicitletrec*, then the expressions. - Exports. An identifier or
(rename (internal external) ...). Exported variables are immutable, in the exporting and the importing library: aset!on one is a syntax violation. An exported macro may implicitly export an unexported identifier it inserts. - Imports. An import spec is an import set or
(for set level ...)where a level isrun(=(meta 0)),expand(=(meta 1)) or(meta n). An import set is a library reference (a name, optionally with a version reference), or(library reference),(only ...),(except ...),(prefix ...)or(rename ...), the same as R7RS. - Version references.
(example grid (1 0))matches versions that start 1 0;(example grid (>= 1 0))uses>=and<=on a sub-version; and(and ...),(or ...)and(not ...)combine version references and sub-version references. When several libraries match, which is chosen is implementation-dependent. - Phases. Run-time expressions are phase 0 and the right-hand sides of
define-syntaxare phase 1, so a macro transformer that calls a procedure of library A needs(for (A) expand)in its library. A visit evaluates the syntax definitions and an instantiation the variable definitions of a library in one phase. - No reserved words.
library,export,import,for,run,expand,meta,only,except,prefix,rename,and,or,not,>=and<=are part of the syntax of the form and are not reserved.
R6RS top-level programs
A top-level program is an import form and then the body, with no library wrapper; the report’s chapter 8 describes it as a sequence of forms where the first is the import. It may start with #!r6rs. The program’s exit is (exit) from (rnrs programs).
R6RS and R7RS libraries compared
| R6RS | R7RS-small | |
|---|---|---|
| Form | library | define-library |
| Body | Definitions and expressions directly after import | In begin, or included from files |
| Versions | Yes, with version references | No |
| Phases | Yes, for … run expand (meta n) | No |
| Conditional parts | None in the library form | cond-expand, include-library-declarations |
| Standard library names | (rnrs base), (rnrs lists) … | (scheme base), (scheme write) … |
| Program form | Top-level program | import then body |
A library for both is written twice, or an implementation that accepts both can read either; CHICKEN, Chez, Guile, Racket and others have different amounts of support. SRFI 97 names the SRFI libraries for R6RS as (srfi :1 lists) and similar; the :1 numeric form is one reason the viewer does not treat a leading colon as a keyword inside an import.
cond-expand and features
(cond-expand (feature body ...) ... (else body ...)) chooses at expansion time, in expressions, in bodies and in library declarations. A feature requirement is a feature identifier, (library name), or an and, or or not of requirements. The R7RS feature identifiers are r7rs, exact-closed, exact-complex, ieee-float, full-unicode, ratios, and, as implementations choose, posix, windows, the operating systems (unix, darwin, gnu-linux, bsd, freebsd, solaris), the processors (i386, x86-64, ppc, sparc, jvm, clr, llvm), the memory models (ilp32, lp64, ilp64), the byte order (big-endian, little-endian), and the implementation’s own name and name-version. SRFI 0 is the older cond-expand, SRFI 7 a configuration language, and SRFI 112 environment inquiry (implementation-name and the like). (features) returns the list.
Module systems of the implementations
| Implementation | How code is split |
|---|---|
| Guile | (define-module (a b) #:use-module (c d) #:export (f g)) and (use-modules (c d)), with the module name mapped to a path in %load-path; also R6RS libraries in .sls files and R7RS libraries |
| CHICKEN 5 | (module name (exports) body) and (import ...); the compiler writes an import library for each module; (use ...) loads an extension; R7RS libraries in .sld files are supported |
| Chez Scheme | R6RS libraries from a .sls file found through the library directories; also a (library ...) form typed at the REPL; top-level programs run by --program |
| Gambit | (##namespace ("pre#" f g)) to rename identifiers, (include "file") and (load "file"),; R7RS-style libraries in recent versions |
| MIT/GNU Scheme | Package descriptions in .pkg files that list files, exports and imports of each package; R7RS libraries in recent releases |
| Chibi-Scheme | R7RS libraries in .sld files found through the module path |
| Gauche | (define-module name ...), (select-module name), (use name) and (import name), files named by module name; R7RS libraries as well |
| Bigloo | (module name (import ...) (export ...)) in the first form of a file, with .sch header files |
| Racket | #lang racket or (module name lang body) with require and provide; R6RS and R7RS libraries by #lang r6rs and #lang r7rs |
Every entry in this table is from memory of the implementation’s documentation and was not checked against the manuals; see the note below. SRFI 83 and 103 proposed R6RS-style library syntaxes and were withdrawn; SRFI 138 describes compiling Scheme programs to executables.
The viewer colours the module-defining forms of these systems (define-module, use-modules, module, use, require-extension) as syntax and the module names after them as library names.
Not described
Known, not yet covered
- Reference: the expansion and instantiation order of R6RS libraries (the visit and instantiate rules of chapter 7 and the expansion process of chapter 10) is summarised, not described step by step.
- Reference: the table of module systems was written from memory of the manuals of Guile, CHICKEN, Chez, Gambit, MIT/GNU, Chibi, Gauche, Bigloo and Racket, none of which was read; details such as which versions of Gambit and MIT/GNU Scheme added R7RS libraries are not stated, and the table should be taken as indicative.
- Reference: how each implementation finds a library file from its name is not described.
See also
- Standard libraries – the libraries the reports define
- Macros – phases and macro export
- Implementations and dialects – what each implementation supports