Table of Contents
The optional SISC libraries are modules whose definition is included in the full SISC distribution, but not the lite distribution.
Requires: (import logicops)
In addition to the R5RS set of procedures that deal with numbers, SISC provides operators for performing bitwise logic operations on a limited range of integers. The domain of the logical operators are exact real integers of the range -2,147,483,648 to 2,147,483,647 inclusive. An error is raised if the logical operators are applied to integers outside this range, to a non-integer, or a non-real.
procedure:
(logand integer [integer] ...) => integer
Performs the logical AND of all the provided arguments.
procedure:
(logor integer [integer] ...) => integer
Performs the logical OR of all the provided arguments.
procedure:
(logxor integer [integer] ...) => integer
Performs the logical exclusive-OR of all the provided arguments.
procedure:
(lognot integer) => integer
Performs the logical NOT of the provided 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:
(ashl integer bits) => integer
Arithmetically shifts integer left by bits bits.
procedure:
(ashr integer bits) => integer
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.
Requires: (import record)
SISC provides a native implementation of record types as defined in SRFI-9. See http://srfi.schemers.org/srfi-9/ 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?.
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.
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:
(make-hashtable [eq?/eqv?/equal?] [thread-safe?]) => hashtable
Creates a hash table. The first optional argument supplies the equivalence test procedure that the hashtable should use. It must be one of eq?, eqv?, or equal?. The default is eqv?.
The second optional argument determines whether operations on the hash table should be made thread-safe. The default is #t. Thread synchronization (see Chapter 6, Threads and Concurrency ) 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 keys of hash tables using equal? must not be mutated.
procedure:
(hashtable? value) => #t/#f
Returns #t if value is a hash table, #f otherwise.
procedure:
(hashtable/size hashtable) => number
Returns the number of key/value pairs stored in hashtable.
procedure:
(alist->hashtable alist [eq?/eqv?/equal?] [thread-safe?]) => hashtable
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:
(hashtable->alist hashtable) => alist
Returns an association list comprising the elements of hashtable. The list contains pairs whose cars are they keys found in hashtable and whose cdrs contain the associated values.
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:
(hashtable/put! hashtable key val [nobinding]) => value
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:
(hashtable/get hashtable key [nobinding]) => value
Returns the value associated with key in hashtable, or nobinding, which defaults to #f, if key has no association.
procedure:
(hashtable/get! hashtable key thunk [unsafe?]) => value
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 the section called “ High-level Concurrency ”.
procedure:
(hashtable/remove! hashtable key val [nobinding]) => value
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 are operations that apply to all elements of a hash table.
procedure:
(hashtable/clear! hashtable)
Removes all elements from hashtable.
procedure:
(hashtable/keys hashtable) => list
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:
(hashtable/map proc hashtable) => list
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.
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:
(buffer? value) => #t/#f
Returns true if and only if the provided argument is a binary buffer.
procedure:
(make-buffer size [fill-value]) => buffer
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 [value] ...) => buffer
Creates a new buffer whose size is equal to the number of arguments given and whose contents are the bytes given as arguments.
procedure:
(buffer-length buffer) => fixed integer
Returns the capacity of the given buffer.
procedure:
(buffer-ref buffer index) => fixed integer
Returns the byte at offset index in the specified buffer. It is an error if index is out of range.
procedure:
(buffer-set! buffer index new-value) => undefined
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:
(buffer-copy! source-buffer source-offset dest-buffer dest-offset [count]) => undefined
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>.
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:
(procedure-property proc symbol [nobinding]) => value
Returns the value associated with the property symbol of procedure proc, or nobinding, which defaults to #f, if the property is not set.
procedure:
(set-procedure-property! proc symbol val [nobinding]) => value
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:
(procedure-property! proc symbol thunk [unsafe?]) => value
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 the section called “ High-level Concurrency ”.
Requires: (import libraries) [5]
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:
(require-library name) => undefined
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", ".sll", ".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:
(library-exists? name) => #t/#f
Returns #t if the library identified by name (a string) exists, #f otherwise.
procedure:
(library-loaded? name) => #t/#f
Returns #t if the library identified by name (a string) has been loaded, #f otherwise.
SISC provides hooks for accessing a number of third-party Scheme libraries.
This functionality has not undergone much testing.
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 http://srfi.schemers.org/ which describes the process and contains a list of all available SRFIs.
In SISC each SRFI is encapsulated in a module. See Chapter 10, Modules and Extensibility 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 the compiled code in srfi.scc, which is contained 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, the following command makes the SRFI modules available:
(require-library 'sisc/libs/srfi)
SISC currently supports SRFIs 0,1,2,5,6,7,8,9,11,13,14,16,18,19,22,23,24,25,26,27,28,29,30,31,34,35,37,38,39,42. Once the SRFI module definitions have been loaded as described above, an 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.
The SLIB portable scheme library provides compatibility and utility functions for standard Scheme implementations. It is supported by many Schemes, including SISC.
The latest version of SLIB is available from http://swissnet.ai.mit.edu/~jaffer/SLIB.html 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.
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.
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.
You also need access to the file slib.scm, which can be found in the scheme-src directory of the SISC distribution.
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
(load "path/slib.scm") (require 'new-catalog) (exit)
where path is the directory containing the slib.scm file.
The above should create a file slibcat in the sisc.home directory. It is a good idea to check that this has indeed happened.
Make sure the above system properties are set. Start SISC as you normally would. At the prompt load slib.scm as described above, i.e.
(load "path/slib.scm")
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.
Requires: (import compiled-libraries)
SISC allows the creation of compiled libraries which contain compiled scheme code. These libraries can then be linked 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 libraries must currently be generated from a Scheme module (see the section called “ Modules ”). First, the user creates such a module (usually by loading a source file that defines the module), then use the create-library-from-module function to create the library file and save it to disk. When loaded, the created library will have the same effect as defining the module from source code. That is, the module will be available for import but will not be imported.
procedure:
(create-library-from-module module-name library-filename) => undefined
Creates a library named module-name and stores it in the file named by the string library-filename. The library created will when loaded have the effect of defining the module named by module-name (a symbol).
procedure:
(create-library-from-module library-name library-filename module-name [module-name] ...) => undefined
Creates a library named library-name and stores it in the file named by the string library-filename. The library created will when loaded define the modules named by the module-name symbols.
In the first form, a library is created from the existing module named module-name, which will also become the name of the library. In the second form, the user is able to specify the name of the library, and have it include the definitions of several modules at once.