The Revised6 Report describes two units of portable code: libraries and top-level programs. A library is a named collection of bindings with a declared set of explicitly exported bindings, a declared set of imported libraries, and a body that initializes its bindings. A top-level program is a stand-alone program with a declared set of imported libraries and a body that is run when the top-level program is run. The bindings in a library are created and its initialization code run only if the library is used, directly or indirectly, by a top-level program.
The import declarations appearing within libraries and top-level programs serve two purposes: first, they cause the imported libraries to be loaded, and second, they cause the bindings of the imported libraries to become visible in the importing library or top-level program. Libraries are typically stored in the file system, with one library per file, and the library name typically identifies the file-system path to the library, possibly relative to a default or programmer-specified set of library locations. The exact mechanism by which top-level programs are run and libraries are loaded is implementation-dependent.
In Chez Scheme, a library to be loaded implicitly by import must reside in a file whose name reflects the name of the library. For example, if the library's name is (tools sorting), the base name of the file must be sorting with a valid extension, and the file must be in a directory named tools which itself resides in one of the directories searched by import. The set of directories searched by import is determined by the library-directories parameter, and the set of extensions is determined by the library-extensions parameter. So, if (library-directories) contains the pathnames "/usr/lib/scheme/libraries" and ".", and (library-extensions) contains the extensions .ss and .sls, the path of the (tools sorting) library must be one of the following.
/usr/lib/scheme/libraries/tools/sorting.ss
/usr/lib/scheme/libraries/tools/sorting.sls
./tools/sorting.ss
./tools/sorting.sls
A file containing a library or set of libraries can be explicitly loaded via load, in which case the file may have any name and may reside anywhere in the file system.
A file containing a library may be compiled with compile-file or compile-library. The only difference between the two is that the latter treates the source file as if it were prefixed by an implicit #!r6rs. Any libraries upon which the library depends must be compiled first. This can be done manually or by setting the parameter compile-imported-libraries to #t before compiling the importing library. If one of the libraries imported by the library is subsequently recompiled (say because it was modified), the importing library must also be recompiled.
In addition to the RNRS libraries mandated by the Revised6 Report:
(rnrs base (6))
(rnrs arithmetic bitwise (6))
(rnrs arithmetic fixnums (6))
(rnrs arithmetic flonums (6))
(rnrs bytevectors (6))
(rnrs conditions (6))
(rnrs control (6))
(rnrs enums (6))
(rnrs eval (6))
(rnrs exceptions (6))
(rnrs files (6))
(rnrs hashtables (6))
(rnrs io ports (6))
(rnrs io simple (6))
(rnrs lists (6))
(rnrs mutable-pairs (6))
(rnrs mutable-strings (6))
(rnrs programs (6))
(rnrs r5rs (6))
(rnrs records procedural (6))
(rnrs records syntactic (6))
(rnrs records inspection (6))
(rnrs sorting (6))
(rnrs syntax-case (6))
(rnrs unicode (6))
Chez Scheme also provides two additional libraries: (chezscheme) and (chezscheme csv7). The former can also be referenced as (scheme) and the latter can also be referenced as (scheme csv7).
The (chezscheme) library exports bindings for every identifier whose binding is described in this document, including those for keywords like lambda, auxiliary keywords like else, module names like scheme, and procedure names like cons. In most cases where an identifier exported from the (chezscheme) library corresponds to an identifier exported from one of the RNRS libraries, the bindings are identical. In some cases, however, the (chezscheme) bindings extend the rnrs bindings in some way. For example, the (chezscheme) syntax-rules form allows its clauses to have fenders (Section 11.2), while the (rnrs) syntax-rules form does not. Similarly, the (chezscheme) current-input-port procedure accepts an optional port argument that, when specified, sets the current input port to port (Section 9.8), while the (rnrs) current-input-port procedure does not. When the (chezscheme) library extends an RNRS binding in some way, the (chezscheme) library also exports the RNRS version, with the name prefixed by r6rs:, e.g., r6rs:syntax-rules or r6rs:current-input-port.
The (chezscheme csv7) Version 7 backward compatibility library contains bindings for a set of syntactic forms and procedures whose syntax or semantics directly conflicts with the RNRS bindings for the same identifiers. The following identifiers are exported from (chezscheme csv7).
record-field-accessible?
record-field-accessor
record-field-mutable?
record-field-mutator
record-type-descriptor
record-type-field-decls
record-type-field-names
record-type-name
record-type-symbol
The bindings of this library should be used only for old code; new code should use the RNRS variants. Each of these is also available in the (chezscheme) library with the prefix csv7:, e.g., csv7:record-type-name.
The interaction environment in which code outside of a library or RNRS top-level program is scoped contains all of the bindings of the (chezscheme) library, as described in Section 2.3.
A top-level program must reside in its own file, which may have any name and may reside anywhere in the file system. A top-level program residing in a file is run by one of three mechanisms: the scheme-script command, the --program command-line argument, or the load-program procedure.
The scheme-script command is used as follows:
scheme-script program-filename arg ...
It may also be run implicitly on Unix-based systems by placing the line
#! /usr/bin/env scheme-script
at the front of the file containing the top-level program, making the top-level program file executable, and executing the file. This line may be replaced with
#! /usr/bin/scheme-script
with /usr/bin replaced by the absolute path to the directory containing scheme-script if it is not in /usr/bin. The first form is recommended in the nonnormative appendices to the Revised6 Report [27], and works wherever scheme-script appears in the path.
The --program command is used similarly with the scheme or petite executables, either by running:
scheme --program program-filename arg ...
petite --program program-filename arg ...
or by including
#! /usr/bin/scheme --script
or
#! /usr/bin/petite --script
at the front of the top-level program file, making the file executable, and executing the file. Again, /usr/bin should be replaced with the absolute path to the actual directory in which scheme and/or petite resides, if not /usr/bin.
The load-program procedure, described in Section 12.4, is used like load:
(load-program string)
where string names the file in which the top-level program resides.
Regardless of the mechanism used, if the opening line is in one of the forms described above, or more generally, consists of #! followed by a space or a forward slash, the opening line is not considered part of the program and is ignored once the Scheme system starts up and begins to run the program. Thus, the line may be present even in a file loaded by load-program. In fact, load-program is ultimately used by the other two mechanisms described above, via the value of the scheme-program parameter described in Section 12.8, and it is load-program that scans past the #! line, if present, before evaluating the program.
A top-level program may be compiled with the compile-program procedure described in Section 12.4. compile-program copies the #! line from the source file to the object file, followed by a compiled version of the source code. Any libraries upon which the top-level program depends, other than built-in libraries, must be compiled first via compile-file or compile-library. This can be done manually or by setting the parameter compile-imported-libraries to #t before compiling the program. The program must be recompiled if any of the libraries upon which it depends are recompiled. A compiled top-level program can be run just like a source top-level program via each of the mechanisms described above.
In Chez Scheme, a library may also be defined in the REPL or placed in a file to be loaded via load or load-library. The syntax for a library is the same whether the library is placed in its own file and implicitly loaded via import, entered into the REPL, or placed in a file along with other top-level expressions to be evaluated by load. A top-level program may also be defined in the REPL or placed in a file to be loaded via load, but in this case, the syntax is slightly different. In the language of the Revised6 Report, a top-level program is merely an unwrapped sequence of subforms consisting of an import form and a body, delimited only by the boundaries of the file in which it resides. In order for a top-level program to be entered in the REPL or placed in a file to be evaluated by load, Chez Scheme allows top-level programs to be enclosed in a top-level-program form.
syntax: (library name exports imports library-body)
returns: unspecified
libraries: (chezscheme)
The library form defines a new library with the specified name, exports, imports, and body. Details on the syntax and semantics of the library form are given in Section 10.3 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.
Only one version of a library can be loaded at any given time, and an exception is raised if a library is implicitly loaded via import when another version of the library has already been loaded. Chez Scheme permits a different version of the library, or a new instance of the same version, to be entered explicitly into the REPL or loaded explicitly from a file, to facilitate interactive testing and debugging. The programmer should take care to make sure that any code that uses the library is also reentered or reloaded, to make sure that code accesses the bindings of the new instance of the library.
(library (test (1)) (export x) (import (rnrs)) (define x 3))
(import (test))
(define f (lambda () x))
(f)
3
(library (test (1)) (export x) (import (rnrs)) (define x 4))
(import (test))
(f)
3 ; oops---forgot to redefine f
(define f (lambda () x))
(f)
4
(library (test (2)) (export x) (import (rnrs)) (define x 5))
(import (test))
(define f (lambda () x))
(f)
5
As with module imports (Section 11.5), a library import may appear anywhere a definition may appear, including at top level in the REPL, in a file to be loaded by load, or within a lambda, let, letrec, letrec*, etc., body. The same import form may be used to import from both libraries and modules.
(library (foo) (export a) (import (rnrs)) (define a 'a-from-foo))
(module bar (b) (define b 'b-from-bar))
(let () (import (foo) bar) (list a b))
(a-from-foo b-from-bar)
The import keyword is not visible within a library body unless the library imports it from the (chezscheme) library.
syntax: (top-level-program imports body)
returns: unspecified
libraries: (chezscheme)
A top-level-program form may be entered into the REPL or placed in a file to be loaded via load, where it behaves as if its subforms were placed in a file and loaded via load-program. Details on the syntax and semantics of a top-level program are given in Section 10.3 of The Scheme Programming Language, 4th Edition and in the Revised6 Report.
The following transcript illustrates a top-level-program being tested in the REPL.
> (top-level-program (import (rnrs))
(display "hello!\n"))
hello!
The parameters described below control where import looks when attempting to load a library.
global parameter: library-directories
global parameter: library-extensions
libraries: (chezscheme)
The parameter library-directories determines where the files containing library source and object code are located in the file system, and the parameter library-extensions determines the filename extensions for the files holding the code. The values of both parameters are lists of pairs of strings. The first string in each library-directories pair identifies a source-file root directory, and the second identifies the corresponding object-file root directory. Similarly, the first string in each library-extensions pair identifies a source-file extension, and the second identifies the corresponding object-file extension. The full path of a library source or object file consists of the source or object root followed by the components of the library name prefixed by slashes, with the library extension added on the end. For example, for root /usr/lib/scheme, library name (app lib1), and extension .sls, the full path is /usr/lib/scheme/app/lib1.sls.
The initial values of these parameters are shown below.
(library-directories)
(("." . "."))
(library-extensions)
((".chezscheme.sls" . ".chezscheme.so")
(".ss" . ".so")
(".sls" . ".so")
(".scm" . ".so")
(".sch" . ".so"))
As a convenience, when either of these parameters is set, any element of the list can be specified as a single source string, in which case the object string is determined automatically. For library-directories, the object string is the same as the source string, effectively naming the same directory as a source- and object-code root. For library-extensions, the object string is the result of removing the last (or only) extension from the string and appending ".so". The library-directories and library-extensions parameters also accept as input strings in the format described in Section 2.7 for the --libdirs and --libexts command-line options.
R. Kent Dybvig /
Copyright © 2009 R. Kent Dybvig
Revised December 2009 for Chez Scheme Version 7.9.4
Cadence Research Systems / www.scheme.com
Cover illustration © 2009 Jean-Pierre Hébert
ISBN: 978-0-966-71392-3
to order this book /
about this book