Libraries provide a way to organize klisp code with a clean & clear interface to the rest of the program. They are first class objects (as all manipulable entities in Kernel, and according to the guidelines in the Kernel report). A library has list of exported symbols and values for those symbols (generally combiners but may be any object). The library type is encapsulated.
In addition there’s a mechanism to refer to library objects by name (where a name is actually a unique list of symbols and numbers), with the ability to register new libraries, get the library object from a name, unregister libraries, etc.
These two ways of working with libraries conform the low level API to libraries and are orthogonal to each other. They are provided to allow klisp programs to construct their own interface to library definition and use, and to respect the guidelines and spirit of the Kernel Report.
There’s also a higher level API that is a combination of the lower level APIs and behaves more like traditional module systems. This is probably what most klisp programs will use. This API consist of the
$provide-library! operative to define (and register) new libraries and the
$import-library! operative to extract bindings out of existing libraries. This allows various forms of controlling which bindings are extracted from the libraries and allows various forms of renaming. It can be used both in the body of libraries or in the top level.
No association is made by klisp between source files and libraries. For a possible mechanism to handle this see
require in the ports module. Also no special meaning is assigned to the library names. This could be used by an even higher level API, for example to map to version numbers and/or to the underlying filesystem.
SOURCE NOTE: This is mostly an adaptation from the r7rs draft of scheme. There’s no mention of libraries in the Kernel Report, but they were deemed important for klisp in order to share and distribute code with a common interface. A number of adaptations were made to the scheme version to sit more comfortably with the Kernel way of doing things (first class status, exposing of the library register, etc).
The primitive type predicate for type library.
library?returns true iff all the objects in
objectsare of type library.
NOTE: This is part of the low level API to libraries. It won’t be needed to writers or users of libraries that stick to the higher level API (i.e.
bindingsshould be an acyclic list of
(symbol . value)pairs. Each symbol may only occur once in the list.
Constructs a new library object with the passed
bindingsas exported objects.
NOTE: This is part of the low level API to libraries, writers of libraries are encouraged to use
$provide-library!to define their libraries.
— Applicative: get-library-environment (get-library-environment library)
get-library-export-listreturns the list of symbols exported from the passed library.
get-library-environmentreturns a fresh empty environment whose parent has all exported symbols of the library bound to the exported objects.
NOTE: This is part of the low level API to libraries, users of libraries are encouraged to use
$import-library!to get bindings out of libraries (and into the current environment).
— Operative: $get-registered-library ($get-registered-library name)
— Operative: $register-library! ($register-library! name library)
— Operative: $unregister-library! ($unregister-library! name)
nameshould a an acyclic list of symbols and exact non-negative integers. Two registered libraries can’t have the same name (in the sense of
These operatives control the library registry that maps names to libraries.
$registered-library?returns true iff a library named
nameis already registered.
get-registered-libraryreturns the library object associated with
name(or throws an error if no library named
name(throws an error if
nameis already registered.
$unregister-library!removes the library registered as
namefrom the library register (throws an error if no such library was registered).
NOTE: This is part of the low level API to libraries, users & writers of libraries are encouraged to use
$provide-library!to create & register new libraries.
— Operative: $import-library! ($import-library! . imports)
nameshould be as for
register-library!and not already registered.
exportsshould be a list of
(#:export <export-spec> ...). Where
<export spec>is either:
(#:rename internal-symbol external-symbol)
A lone symbol has the same semantics as the pair with that symbol in both internal and external positions. No symbol can appear more than once as external.
bodyshould be an acyclic list of expressions.
importsshould be a list like
(#:only <import-spec> symbol ...)
(#:except <import-spec> symbol ...)
(#:prefix <import-spec> symbol)
(#:rename <import-spec> (orig-symbol new-symbol) ...)
These two operatives conform the higher level API for klisp libraries. They are what most users of klisp (both writers and users of libraries) will use.
$provide-library!creates and register a library with name
nameand exported symbols obtained from the
exportslist and values prepared by the
body. First a child of the dynamic environment is created. Then,
bodyis evaluated sequentially as if by
$sequencein that environment. Next a new library is created with a list of exported bindings that use the external symbols in
exportsas names and the values bound by the corresponding internal symbols in the created environment, as values. If a lone symbol is used in
exportsit is used both as internal and external symbol for that binding. Lastly, the new library object is registered as
name. This mechanism more or less follows the idea of operative
$provide!from the Kernel Report, but it also allows for renaming.
$import-library!imports to the current environment any combination of bindings from any number of named libraries, while allowing renaming of said bindings. It can be used in any context, as any other Kernel expression.
$import-library!looks for the named libraries and then extracts & renames the specified bindings according to each
<import-spec>and defines them (in the sense of
$set!) in the current dynamic environment. The set of bindings to import are generated in a recursive manner. This allows a great deal of control of the imported bindings and their names. The semantics for the set of bindings generated by the various
<import-spec>s are as follows:
<name>: All bindings from library
(#:only <import-spec> symbol ...): Only the named bindings from the set of bindings in
(#:except <import-spec> symbol ...): All bindings from the set in
<import-spec>except those named in the list.
(#:prefix <import-spec> symbol): All bindings from the set in
<import-spec>but renamed by prefixing each one with the specified prefix
(#:rename <import-spec> (orig-symbol new-symbol) ...): All bindings from the set in
<import-spec>but renaming all
orig-symbolto the corresponding
If two values are tried to be imported with the same name, they are checked for
eq?-ness, if they are deemed
eq?to each other they are imported, otherwise
$import-library!throws an error. This helps catch name collisions while allowing to reexport bindings from used libraries without conflict.