# Additional Libraries

## Optional &SISC; Libraries

The optional &SISC; libraries are modules whose definition is included in the full &SISC; distribution, but not the lite distribution.

### Definitions

&requires; (import misc)

In addition to the standard &R5RS; definition syntaxes, &SISC; provides an additional value definition and syntax definition form.

First, `define-values`, which allows more than one binding to be created at once, given the multiple-value return of its body.

> &syntax; `undefined` `define-values` `(binding` `binding` `)` `expression`

> > Evaluates the expression in the body, which must return the same number of values as there are binding names. Each value is then bound (in an undefined order) to each binding name.

`define-values` behaves like `define` in terms of which environment the bindings are created. If the `define-values` statement is at the top-level then bindings are created in the top-level environment. If the statement is in a lexical environment, then it behaves just as an internal define.

Second, `define-simple-syntax` provides a shorthand for syntax definition when the syntactic form's appearance is similar to a function.

> &syntax; `undefined` `define-simple-syntax` `(name` `vars` `)` `body`

> > Creates a syntactic form with the given name, and any number of listed syntactic variables, which expands to the given body (with instances of the syntactic variables hygienically expanded).

Here is an example usage of `define-simple-syntax` to define the `when` macro:

    (define-simple-syntax (when condition body ...)
      (if condition
          (begin body ...)))

### Bitwise Logical Operations

&requires; (import logicops)

In addition to the &R5RS; set of procedures that deal with numbers, &SISC; provides operators for performing bitwise logic operations on exact integers.

> &procedure; `integer` `logand` `integer` `integer`

> > Performs the logical AND of all the provided arguments.

> &procedure; `integer` `logor` `integer` `integer`

> > Performs the logical OR of all the provided arguments.

> &procedure; `integer` `logxor` `integer` `integer`

> > Performs the logical exclusive-OR of all the provided arguments.

> &procedure; `integer` `lognot` `integer`

> > Performs the logical NOT of the provided integer.

> &procedure; `integer` `logcount` `integer`

> > Returns the count of the number of 1 bits in the representation of a given positive integer, or 0 bits in a negative integer.

In addition, two operators are provided to perform arithmetic shifts on any integer (these operators do not have the range limitation the previous logical functions do). The shift operators return a newly generated number formed by shifting the provided number left or right by the given number of bits.

> &procedure; `integer` `ashl` `integer` `bits`

> > Arithmetically shifts `integer` left by `bits` bits.

> &procedure; `integer` `ashr` `integer` `bits`

> > Arithmetically shifts `integer` right by `bits` bits.

Mathematically, if r is the number, and s is the number of bits, ashl calculates:

    r x 2s

while ashr calculates

    r / 2s

in the integer domain. Both ashl and ashr operate on exact integers and produce only exact integers.

### Records

&requires; (import record)

&SISC; provides a native implementation of record types as defined in SRFI-9. See for details. In addition to the `define-record-type` syntax provided by SRFI-9, a more compact (but less flexible) `define-struct` syntax is offered.

&syntax; `define-struct` `name` `(field ...)`

> Defines a SRFI-9 record type as follows:

>     (define-record-type (make-name field ...)
>       name?
>       (field name-field set-name-field!)
>       ...)

> i.e. naming conventions are used to determine the names of the record type constructor, predicate, field access and field modifier procedures.

Records are `eq?` and `eqv?` if and only if they are identical. Records are `equal?` if and only if they are instances of the same record type and all their fields are `equal?`.

It is also possible to define non-generative record types, using `define-nongenerative-record-type` and `define-nongenerative-struct`. Non-generative record types are associated with a user-specified guid. If an attempt is made to define a record type with a guid that is already bound to an existing record type then the existing record type is modified, instead of a new record type being created. Non-generative record types are serialised specially such that deserialising them also performs this check. By contract, deserialisation of ordinary, generative record types and their instances results in duplicate types being created, which is usually not desirable.

&syntax; `define-nongenerative-record-type` `name` `guid` `(constructor-name field ...)` `(predicate ...)` `(field-spec ...)`

> This is the same as `define-record-type`, except that the resulting record type is non-generative with `guid`, a symbol, as the unique identifier.

&syntax; `define-nongenerative-struct` `name` `guid` `(field ...)`

> This is the same as `define-struct`, except that the resulting struct is non-generative with `guid`, a symbol, as the unique identifier.

### Hash Tables

&requires; (import hashtable)

Hash tables store mappings of keys to values. Hence they are similar to association lists, except that hash tables allow retrieval, addition and modification in constant time whereas association lists typically perform these operations in linear time based on the number of elements.

#### Creation and Introspection

Hash tables are a distinct data type. They can be created empty or filled with the contents of an association list. The converse, creating an association list from a hash table, is also supported.

> &procedure; `hashtable` `make-hashtable` `equivalence-predicate` `hash-function` `thread-safe?` `weak?`

> > Creates a hash table. The first optional argument supplies the equivalence test procedure that the hashtable should use for comparison of keys. This must be a function accepting two arguments and returning a boolean. It defaults to `equal?`.

> > The second optional argument supplies the hash function, which must accept one argument and return a numeric value. For the equivalence predicates `eq?`, `eqv?`, `equal?`, `string=?`, `string-ci=?` it defaults to `hash-by-eq`, `hash-by-eqv`, `hash-by-equal`, `hash-by-string=`, `hash-by-string-ci=?` respectively, and `hash-by-equal` otherwise.

> > The third optional argument determines whether operations on the hash table should be made thread-safe. The default is #t. Thread synchronization (see Threads) is required if there are potentially several threads operating concurrently on the hash table and one of these threads performs a structural modification (i.e. adds or removes an entry; merely changing the value of an entry is not a structural modification). Failure to enforce proper thread synchronization has unpredicatable results.

> > The fourth optional argument determines whether the keys in the hash table are held with weak references, allowing them to be garbage collected, and automatically removed from the hashtable when they are not referenced from elsewhere. The default is #t.

> > For reasons of disambiguation, the hash function argument can only be supplied if the preceeding equivalence predicate was also supplied, and the weakness argument can only be supplied if the preceeding thread-safety argument was also supplied.

> > The equivalence and hash function must produce stable results for the keys in a hash table.

> > The effects of invoking an escaping continuation inside the equivalence predicate or hash function, or invoking a continuation captured inside the equivalence predicate or hash function after that function has returned, are unspecified.

> &procedure; `hashtable` `alist->hashtable` `alist` `equivalence-predicate` `hash-function` `thread-safe?` `weak?`

> > Creates a hashtable and initializes it with the keys and values found in `alist`. `alist` must be a list of pairs, with the `car` of each pair representing a key and the `cdr` representing its associated value. The optional arguments are the same as for `make-hashtable`.

> > If there are multiple pairs which contain the same key (with respect to chosen equivalence test) then the resulting hash table will associate the key with the value of the last such pair.

> &procedure; `#t/#f` `hashtable?` `value`

> > Returns #t if `value` is a hash table, #f otherwise.

> &procedure; `procedure` `hashtable/equivalence-function` `hashtable`

> > Returns the equivalence predicate of `hashtable`.

> &procedure; `procedure` `hashtable/hash-function` `hashtable`

> > Returns the hash function of `hashtable`.

> &procedure; `#t/#f` `hashtable/thread-safe?` `hashtable`

> > Returns #t if `hashtable` is thread safe, #f otherwise.

> &procedure; `#t/#f` `hashtable/weak?` `hashtable`

> > Returns #t if the keys in `hashtable` are held by weak references, #f otherwise.

> &procedure; `number` `hashtable/size` `hashtable`

> > Returns the number of key/value pairs stored in `hashtable`.

> &procedure; `alist` `hashtable->alist` `hashtable`

> > Returns an association list comprising the elements of `hashtable`. The list contains pairs whose `car`s are they keys found in `hashtable` and whose `cdr`s contain the associated values.

#### Hash Functions

Several hash functions that return results consistent with common equivalence predicates are predefined.

> &procedure; `number` `hash-by-eq` `value`

> &procedure; `number` `hash-by-eqv` `value`

> &procedure; `number` `hash-by-equal` `value`

> &procedure; `number` `hash-by-string=` `string`

> &procedure; `number` `hash-by-string-ci=` `string`

> These procedures return a hash code of their argument that is consistent with `eq?`, `eqv?`, `equal?`, `string=?`, `string-ci=?`, respectively.

#### Access and Modification

All hash table access operations follow a similar pattern. They return the value that was associated with the the given key at the time the operation was invoked. If no binding for the key existed, an optionally supplied value is returned that defaults to #f. This allows the programmer to associate keys with #f values and distinguish this case from not having any association for a key.

> &procedure; `value` `hashtable/put!` `hashtable` `key` `val` `nobinding`

> > Associates `key` with `val` in `hashtable`. Returns the previous association of `key` or `nobinding`, which defaults to #f, if `key` has no previous association.

> &procedure; `value` `hashtable/get` `hashtable` `key` `nobinding`

> > Returns the value associated with `key` in `hashtable`, or `nobinding`, which defaults to #f, if `key` has no association.

> &procedure; `value` `hashtable/get!` `hashtable` `key` `thunk` `unsafe?`

> > Returns the value associated with `key` in `hashtable`. If `key` has no association then `thunk` is called and the result is associated with `key` in `hashtable` and also returned. The `unsafe?`, which defaults to #t, indicates whether `thunk` may invoke escaping continuations or raise errors. Setting `unsafe?` to #f results in more efficient execution but may cause deadlocks if `thunk` is unsafe. See also `mutex/synchronize-unsafe` in highlevelconcurrency.

> > When `hashtable` is thread-safe this operation is atomic.

> &procedure; `#t/#f` `hashtable/contains?` `hashtable` `key`

> > Returns the #t if `hashtable` contains an entry for `key`, #f otherwise.

> &procedure; `value` `hashtable/remove!` `hashtable` `key` `nobinding`

> > Removes the association of `key` in `hashtable`. Returns the associated value of `key` or `nobinding`, which defaults to #f, if `key` has no association.

#### Bulk Operations

Bulk operations are operations that apply to all elements of a hash table.

> &procedure; `hashtable/clear!` `hashtable`

> > Removes all elements from `hashtable`.

> &procedure; `list` `hashtable/keys` `hashtable`

> > Returns the keys contained in `hashtable`.

> &procedure; `hashtable/for-each` `proc` `hashtable`

> > Applies `proc` to each element of `hashtable`. `proc` is called with two parameters - the key and the value of the element.

> &procedure; `list` `hashtable/map` `proc` `hashtable`

> > Applies `proc` to each element of `hashtable`. `proc` is called with two parameters - the key and the value of the element. The results of calling `proc` are returned as a list.

### Binary Buffers

&requires; (import buffers)

Binary buffers provide an opaque container for a fixed amount of binary data. The binary buffer library provides a number of functions for creating and accessing those buffers. The buffer is very similar to a vector, in that it is a randomly accessable, zero-based structure. But as a tradeoff for space efficiency, binary buffers are only capable of storing bytes. The bytes are stored as 8-bit, unsigned fixed integers (of the range 0-255).

> &procedure; `#t/#f` `buffer?` `value`

> > Returns true if and only if the provided argument is a binary buffer.

> &procedure; `buffer` `make-buffer` `size` `fill-value`

> > Creates a new buffer capable of storing `size` bytes. `size` must be a fixed non-negative integer. If provided, the value of all bytes in the buffer is initialized to `fill-value`. If not provided, the contents of the buffer is unspecified.

> &procedure; `buffer` `buffer` `value`

> > Creates a new buffer whose size is equal to the number of arguments given and whose contents are the bytes given as arguments.

> &procedure; `fixed integer` `buffer-length` `buffer`

> > Returns the capacity of the given buffer.

> &procedure; `fixed integer` `buffer-ref` `buffer` `index`

> > Returns the byte at offset `index` in the specified buffer. It is an error if `index` is out of range.

> &procedure; `undefined` `buffer-set!` `buffer` `index` `new-value`

> > Sets the byte at offset `index` of the specified buffer to the given fixed integer `new-value`. It is an error if `index` is out of range.

> &procedure; `undefined` `buffer-copy!` `source-buffer` `source-offset` `dest-buffer` `dest-offset` `count`

> > Copies `count` bytes starting from index `source-offset` in the source buffer to successive bytes starting at index `dest-offset` in the destination buffer. If `count` is unspecified, it is assumed to be the length of the source buffer. It is an error to copy more bytes from the source buffer than are available, or to copy more bytes into the destination buffer than its capacity allows.

Buffers are serializable (can exist in loadable libraries or a &SISC; heap), but are not representable in an s-expression. For this reason, they bear the printed representation of `#<buffer>`.

### Procedure Properties

&requires; (import procedure-properties)

&SISC; allows key/value bindings to be associated with procedures. This has a number of applications. For instance, generic procedures store their methods in a procedure property.

Keys must be symbols. Values are any valid Scheme value. All operations are thread-safe.

> &procedure; `value` `procedure-property` `proc` `symbol` `nobinding`

> > Returns the value associated with the property `symbol` of procedure `proc`, or `nobinding`, which defaults to #f, if the property is not set.

> &procedure; `value` `set-procedure-property!` `proc` `symbol` `val` `nobinding`

> > Sets the property `symbol` of procedure `proc` to the value `val`. Returns the previous value of the property or `nobinding`, which defaults to #f, if the property was unset.

> &procedure; `value` `procedure-property!` `proc` `symbol` `thunk` `unsafe?`

> > Returns the value associated with the property `symbol` of procedure `proc`. If the property is unset then `thunk` is called and the property is set to the result, which is also returned. The `unsafe?`, which defaults to #t, indicates whether `thunk` may invoke escaping continuations or raise errors. Setting `unsafe?` to #f results in more efficient execution but may cause deadlocks if `thunk` is unsafe. See also `mutex/synchronize-unsafe` in highlevelconcurrency.

### Loadable Scheme Libraries

&requires; (import libraries)

This module gets imported by default.

Scheme code can be packaged into libraries that can have dependencies on other libraries and can be loaded as required. Libraries are identified by a name that follows Java package file naming conventions, i.e. using path-style names typically containing domain, organisation name, project name and library name. For instance, if company Foo produces a library Baz for project Bar and that library contains three files, the file structure might look as follows:

    com/foo/bar/baz.scm
    com/foo/bar/baz/baz1.scm
    com/foo/bar/baz/baz2.scm
    com/foo/bar/baz/baz3.scm

This library can be made accessible from &SISC; by adding the base directory or a jar file containing these files to the Java class path. Libraries are loaded by the following procedure.

> &procedure; `undefined` `require-library` `name`

> > Checks whether the library identified by `name` (a string), has already been loaded and, if not, loads it. An error is raised if the library cannot be found.

> > Libraries are loaded using the `load` procedure from a resource located by the `find-resource` procedure. The name of the resource is derived from the name of the library by appending ".scc", ".sce" and, if that does not succeed, ".scm".

Note that `require-library` only loads a single file. The definition of dependencies on other libraries and the loading of other files therefore needs to happen within that file. For instance, the file `com/foo/bar/baz.scm` from the above example might contain the following:

    (require-library 'com/foo/bar/boo)
    (load "baz/baz1.scm")
    (load "baz/baz2.scm")
    (load "baz/baz3.scm")

It is possible to programmatically check whether a particular library exists and whether it has been loaded:

> &procedure; `#t/#f` `library-exists?` `name`

> > Returns #t if the library identified by `name` (a string) exists, #f otherwise.

> &procedure; `#t/#f` `library-loaded?` `name`

> > Returns #t if the library identified by `name` (a string) has been loaded, #f otherwise.

### Operating System Interface

&requires; (import os)

The operating system interface currently contains functions for spawning external processes on the host operating system, obtaining input/output ports to the resulting process, and monitoring their status.

Two procedures exist for spawning processes:

> &procedure; `process` `spawn-process` `program/commandline` `arglist`

> > Spawns a process, returning a process handle. If the optional argument list is provided, then the first argument is the binary to run with those arguments. If omitted, the first argument is tokenized as a commandline and used to spawn the process.

> &procedure; `process` `spawn-process-with-environment` `program` `arglist` `environment` `working-directory`

> &procedure; `process` `spawn-process/env` `program` `arglist` `environment` `working-directory`

> > Spawns a process named by `program` with the arguments given in `arglist`, in the given `environment`. The environment is an association list of strings to strings. The key in the association list is an environment variable name, and the corresponding value is the value to assign to that environment variable. If the environment parameter is `#f`, the environment variables of the current &SISC; instance are used.

> > The optional parameter `working-directory` specifies the directory which will be set as the current directory when the process is spawned. If ommited, the value of the `current-directory` parameter (i.e. the current directory of the running Scheme program) is used instead.

> &procedure; `#t/#f` `process?` `value`

> > Returns `#t` if the given value is a process handle.

Once started, a process will run in parallel to the current Scheme program according to the usual scheduling of the host platform. The process handle obtained can be used to obtain the input, output, and error streams of the process using the following functions:

> &procedure; `binary-input-port` `get-process-stdout` `process`

> > Returns a binary input port which will read bytes which the given process has written to its standard output stream.

> &procedure; `binary-input-port` `get-process-stderr` `process`

> > Returns a binary input port which will read bytes which the given process has written to its standard error stream.

> &procedure; `binary-output-port` `get-process-stdin` `process`

> > Returns a binary output port which when written to will send bytes to the given process' standard input stream.

Finally, functions are provided to check the status of a spawned process, and to wait for a process to complete:

> &procedure; `integer or #f` `process-terminated?` `process`

> > Checks to see if the given process has terminated, and returns the process' return code if so. If the process is still running, `#f` is returned.

> &procedure; `integer or #f` `wait-for-process` `process`

> > Waits for the given process to terminate, and returns the process' return code if so. The wait operation may be interrupted by other code, in which `#f` is returned.

## Third-Party Libraries

&SISC; provides hooks for accessing a number of third-party Scheme libraries.

This functionality has not undergone much testing.

### SRFIs

The Scheme Requests For Implementation (SRFI) process aims to coordinate libraries and other additions to the Scheme language between different Scheme implementations. For details see which describes the process and contains a list of all available SRFIs.

#### SRFI Modules

In &SISC; each SRFI is encapsulated in a module. See Modules for details of &SISC;'s module system. The definitions for SRFI modules are not included in the standard &SISC; heap build and hence must be loaded separately from various compiled library files in the `sisc-lib.jar` jar file in the root directory of the &SISC; binary distribution. As long as this jar file is on the classpath, which is the case by default, any SRFI's module definition may be loaded with the expression `(require-library 'sisc/libs/srfi/srfi-`n`)`, where `n` is the SRFI's number. For example:

    (require-library 'sisc/libs/srfi/srfi-9)

All SRFI's may be loaded at once by requiring `sisc/libs/srfi`.

#### Using SRFIs

&SISC; currently supports SRFIs 0, 1, 2, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 22, 23, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 42, 43, 45, 48, 51, 54, 55, 59, 60, 61, 62, 66, 67, 69 and 78. Once the SRFI module definitions have been loaded as described above, a SRFI `n` can be imported using

    (import srfi-n)

e.g.

    (import srfi-1)
    (xcons 1 2) ;=> (2 . 1)

SRFI modules, like all modules in &SISC;, can be imported/used by other modules. Doing so does not pollute the top-level environment with the definitions exported by the module, i.e. any code outside the importing module remains unaffected.

If, however, an SRFI is to be imported into the top-level, one can use the `require-extension` mechanism (see SRFI55).

#### SRFI Extensions

Some SRFIs have built-in extension points that Scheme implementations can use to augment a SRFI's functionality. It is also the case that some SRFIs would benefit from slightly extended APIs.

This section documents the SRFI extensions implemented by &SISC;.

##### SRFI 69 (Basic hash tables)

The `make-hash-table` function takes two additional optional arguments: `thread-safe?` and `weak?`. See `make-hashtable` in hashtablecreation for details.

The basic hash table API is extended in a separate module:

> &requires; (import srfi-69-ext)

> &procedure; `#t/#f` `hash-table-thread-safe?` `hashtable`

> > Returns #t if `hashtable` is thread safe, #f otherwise.

> &procedure; `#t/#f` `hash-table-weak?` `hashtable`

> > Returns #t if the keys in `hashtable` are held by weak references, #f otherwise.

> &procedure; `value` `hash-table-ref!` `hashtable` `key` `thunk`

> > Returns the value associated with `key` in `hashtable`. If `key` has no association then `thunk` is called and the result is associated with `key` in `hashtable` and also returned.

> > When `hashtable` is thread-safe this operation is atomic.

> &procedure; `value` `hash-table-ref!` `hashtable` `key` `default`

> > Returns the value associated with `key` in `hashtable`. If `key` has no association then `default` is associated with `key` in `hashtable` and also returned.

> > When `hashtable` is thread-safe this operation is atomic.

### SLIB

The SLIB portable scheme library provides compatibility and utility functions for standard Scheme implementations. It is supported by many Schemes, including &SISC;.

#### Downloading and Installation

The latest version of SLIB is available from as both a zip file and RPM. The site also hosts an online version of the SLIB manual.

Download SLIB and install it in a convenient location. The RPM will by default be installed in `/usr/share/slib/`. Do not worry when you see some errors about missing programs such as mzscheme and scheme48 when installing the RPM - these happen because SLIB tries to auto-configure itself for various Schemes that you may not have installed on your system.

#### Environment

Using SLIB in &SISC; requires two Java system properties to be set:

- #### `sisc.home`

  This should (but does not actually have to) point to the location where you have installed &SISC;. If you are using one of the scripts from the binary &SISC; distribution in order to run &SISC; then this property will automatically be set to the value of the `SISC_HOME` environment variable.

- #### `sisc.slib`

  This must point to the location where you installed SLIB. Other Schemes supporting SLIB tend to use an environment variable `SCHEME_LIBRARY_PATH`, so it is advisable to define that (if it is not already defined) and run Java with a `-Dsisc.slib=...` option based on the environment variable. If you are using the scripts from the binary $SISC; distribution in order to run &SISC; then you can set the property by adding the `-Dsisc.slib=...` to the `JAVAOPT` environment variable.

  Note that the value of this property should be a fully qualified url, e.g. `file:///usr/share/slib`

You need to ensure that all potential users of SLIB have read permissions to files in the directories referred to by the above system properties.

#### Building the Catalog

Make sure that the above system properties are set and that you have write permissions to the `sisc.home` directory; often this means you need to be logged in as a privileged user.

Start &SISC; as you normally would. At the prompt type

    (require-library 'sisc/libs/slib)
    (require 'new-catalog)
    (exit)

The above should create a file `slibcat` in the `sisc.home` directory. It is a good idea to check that this has indeed happened.

#### Using SLIB

Make sure the above system properties are set. Start &SISC; as you normally would. At the prompt load the &SISC; SLIB as described above, i.e.

    (require-library 'sisc/libs/slib)

You can now load SLIB modules using `require`, e.g.

    (require 'tsort)
    (tsort '((shirt tie belt)
             (tie jacket)
             (belt jacket)
             (watch)
             (pants shoes belt)
             (undershorts pants shoes)
             (socks shoes))
           eq?)

loads the topological sorting module and invokes one of the procedures defined by it.

Please refer to the SLIB manual for further details of what modules are available. Note however that, as with most other Schemes supported by SLIB, there will be some modules that are not available or do not work in &SISC;.

## Creating Libraries

&requires; (import libraries)

&SISC; allows the creation of compiled libraries which contain compiled scheme code. These libraries can then be executed into a running &SISC; session in order to extend the functionality without processing or possessing the original source. Such libraries can be loaded using `load` as would any ordinary Scheme source file.

Compiled code files (`.scc`) are created using the `compile-file` function, which takes a Scheme source file and a target output file, and processes the Scheme source through the various expansion and compilation phases, and then serializes the resulting &SISC; microexpressions to the given target file. The resulting file may then be loaded with `load` as any ordinary Scheme file would, or can be placed in the library path and resolved using `require-library`.

> &procedure; `undefined` `compile-file` `source-file` `target-file`

> > Compiles the Scheme source present in `source-file`, writing the resulting micro-expressions into `target-file`, suitable for loading.

> > As a side effect, the micro-expressions are also evaluated, i.e. in effect `compile-file` compiles and evaluates the `source-file`. The latter is necessary because the compilation of an expression may depend on the results of evaluating a previous expression, e.g. as is typically the case for libraries that depend on other libraries.

### `.sll` Deprecation

Scheme Loadable Libraries (`.sll` files) were deprecated in version 1.9. This was due to unresolvable incompatibilities in the engine's closure representation and the `.sll` functionality.