Some examples of the libraries and procedures in the slib namespace of r7rs-libs.
SLIB Introduction and Miscellaneous Libraries
SLIB is a collection of packages of Scheme code, mostly written by Aubrey
Jaffer, but some collected from other sources. Looking through the files, some
of the original dates go back to 1991, and the precedence parser into 1989. A
number of ideas now found in Scheme and captured in the SRFIs can be traced
back to SLIB. The repackaged files in r7rs-libs
have been adapted to work
with R7RS Scheme implementations: using R7RS functionality, the library system,
and operations now found in SRFIs.
SLIB’s official documentation is available at http://people.csail.mit.edu/jaffer/slib and is still applicable, with some minor adjustments, to the version provided here.
There are 91 libraries within the R7RS SLIB collection. These fall within four main groups of functionality:
-
Textual Conversion Packages, including a parser, I/O routines, html and xml processing, pretty-printing of Scheme objects, and procedures to handle times and dates.
-
Mathematical Libraries, including prime numbers, some random number distributions, plotting functions (to text and eps), root/limit finding libraries and a 3D modelling suite.
-
Database Packages, which implement a relational database system, and a library for weighted trees.
-
Other Packages
-
Data Structures: for enhancing arrays, working with pnm files, an object system and queues.
-
Sorting and Searching: trees, chapter-order, topological sort, along with some space filling curves and sequence comparisons.
-
Other Procedures: a library of metric units for computing conversions.
-
The "examples" and "tests" directories provide (some) examples of using SLIB. Limited documentation for some of the libraries follows.
This section introduces some of the smaller libraries in the SLIB collection. The following chapters go into some of the libraries into more depth, especially those libraries related with a common theme such as array handling or time.
Charplot: (import (slib charplot))
This library provides a way to quickly visualise some data in graphical or histogram
form from the REPL or command-line interface. There are two basic functions: histograph
and plot
, the latter drawing graphs of data or functions.
charplot:dimensions
This parameter allows you to change the size of display. The dimensions are a two-valued list: the height and width in characters. Example below.
histograph
histograph
is used to plot histograms of numeric data. Given a list or vector
of numbers, it will arrange them into a suitable set of bins and display:
> (histograph '(1 1 2 3 5 5 5 7 8 9) "sample") ________________________________________________________________ | | | | 3|- I | | I | | I | 2.5|- I | | I | | I | 2|-I I | | I I | | I I | 1.5|-I I | | I I | | I I | 1|-I I I I I I I | | I I I I I I I | | I I I I I I I | 0.5|-I I I I I I I | | I I I I I I I | | I I I I I I I | 0|-IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII---------------| |._____:_____._____:_____._____:_____._____:_____._____:_____.___| sample 2 4 6 8 10 > (charplot:dimensions '(10 50)) > (histograph '(1 1 2 3 5 5 5 7 8 9) "sample") ___________________________________ 3|- I | | I | 2|-I I | | I I | 1|-I I I I I I I | | I I I I I I I | 0|-IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII--| |_.____:____.____:____.____:____.___| sample 2.5 5 7.5 >
plot
plot
can be used in two ways: to display a function, or to display some data.
plot
will plot the values of a single argument function (taking and returning a number).
The function should be given as the first argument. The second and third arguments specify the
range of x values over which to plot the graph - be careful of infinite values from your
function, which will crash plot
. An optional fourth argument specifies how many points
to plot along the range of x values.
> (plot (lambda (x) (* x x x)) -5 5) _________________________________________________________________ 140|- : | | : | 120|- : * | | : * | 100|- : * | | : * | 80|- : * | | : ** | 60|- : * | | : ** | 40|- : * | | : *** | 20|- : ** | | *** : ***** | 0|---------------------*********************-----------------------| | ** : | -20|- ** : | | *** : | -40|- * : | | ** : | -60|- * : | | ** : | -80|- * : | | * : | -100|- * : | | * : | -120|-* : | |_._____:_____._____:_____._____:_____._____:_____._____:_____.___| -4 -2 0 2 4 > (plot (lambda (x) (* x x x)) -5 5 30) _________________________________________________________________ 140|- : | | : | 120|- : * | | : | 100|- : * | | : | 80|- : * | | : | 60|- : * | | : * | 40|- : * | | : * | 20|- : * | | * : * * | 0|----------------------*-*-*-*-*:*-*-*-*-*------------------------| | * : | -20|- * : | | * : | -40|- * : | | * : | -60|- * : | | : | -80|- * : | | : | -100|- * : | | : | -120|-* : | |_._____:_____._____:_____._____:_____._____:_____._____:_____.___| -4 -2 0 2 4
This second form of plot
directly plots a list or vector of pairs of (x, y)
coordinates. Second and third arguments give labels to the two axes.
> (define data (map (lambda (x) (list x (* x x x))) (iota 11 -5))) > data ((-5 -125) (-4 -64) (-3 -27) (-2 -8) (-1 -1) (0 0) (1 1) (2 8) (3 27) (4 64) (5 125)) > (plot data "x-values" "y-values") y-values _________________________________________________________________ 140|- : | | : | 120|- : * | | : | 100|- : | | : | 80|- : | | : | 60|- : * | | : | 40|- : | | : * | 20|- : | | * : * | 0|-------------------------*-----*-----*---------------------------| | : | -20|- : | | * : | -40|- : | | : | -60|- * : | | : | -80|- : | | : | -100|- : | | : | -120|-* : | |_._____:_____._____:_____._____:_____._____:_____._____:_____.___| x-values -4 -2 0 2 4
Database
SLIB includes a relational database system, written entirely in Scheme. This is a complex and inter-related set of libraries. The following example (from "slib-examples/db-1.sps") provides an introduction to creating, opening and using a simple database.
More information on SLIB’s database system is available at: http://people.csail.mit.edu/jaffer/slib/Using-Databases.html. After understanding the example below, work through section 6.1.2 on Table Operations.
Creating a database
A database can be created using one or more "backends". Currently, only an association list
backend is supported, as provided by (slib alist-table)
. A database is created to a given filename:
(import (scheme base)
(slib databases)
(slib alist-table))
(define db (create-database "mydb" 'alist-table))
The above code imports the necessary libraries, and creates a database in the file "mydb" using
an association-list backend. A reference to this database is stored in db
.
Next, the database can be opened:
(define rdb (open-database! db))
As we will see below, a database can be opened using either the database reference from the create-database
command, or from the filename. So (open-database! "mydb")
works just as well.
Databases can be opened in mutable or immutable modes: opened to be changed, or just for reading. The exclamation mark ! indicates that the database is mutable.
Data in a database is stored within tables. Before we can use our new database, we need to create at least one table. A table is defined from three elements:
-
its name
-
its primary key field(s)
-
its other fields
In our example, we make an example with name "testit", a single primary key "id", and two fields "first" and "second". Each field is defined with an associated type (allowed types are described in the online documentation). In this case, our "id" field will be a number, and the two other fields strings.
The basic definition is:
(testit ; the table name ((id number)) ; list of primary key field (name type) pairs ((first string) (second string))) ; list of other field (name type) pairs
When defining a table, we can also provide a list of data to add. The data are simply given in rows, with values for all fields:
((1 "Peter" "Lane") ; row 1: (id first second) (2 "Joe" "Smith")) ; row 2: (id first second)
Putting the definitions together, the following line of code creates the testit
table, and adds some initial data:
(define-tables rdb '(testit ((id number)) ((first string) (second string))
((1 "Peter" "Lane")
(2 "Joe" "Smith"))))
Finally, don’t forget to close the database, which ensures everything is saved on disk:
(close-database rdb)
You can examine the file "mydb" to read the definition and data.
Working with a database
Databases should only need constructing once. Afterwards, you will open and work with the existing file. To open an existing database, you need to know its filename:
(define mydb (open-database! "mydb")) ; open a mutable database
To access information in a table, you need to extract the table of interest:
(define table (open-table! mydb 'testit))
If you were to examine table
, you would find it is a procedure. The table
procedure takes an operation definition as its argument, and returns a new procedure
to perform that operation on some data.
For example, if we wish to retrieve a row of data. The operation definition is 'row:retrieve
.
The returned procedure then takes the primary key(s) to locate in the database:
((table 'row:retrieve) 1) ; returns the row with id 1: (1 "Peter" "Lane")
Try displaying all rows (note, the third case will return #f
):
(display "Retrieving 1: ") (display ((table 'row:retrieve) 1)) (newline)
(display "Retrieving 2: ") (display ((table 'row:retrieve) 2)) (newline)
(display "Retrieving 3: ") (display ((table 'row:retrieve) 3)) (newline)
A new row can be inserted in a similar way:
((table 'row:insert) '(3 "Jane" "Wheeler"))
Further row operations exist to update and delete.
Operations are also available to work on multiple rows. A useful case is for-each-row
:
((table 'for-each-row) (lambda (row) (display "Row: ") (display row) (newline)))
Finally, don’t forget to close the database, which ensures everything is saved on disk:
(close-database mydb)
Dynamic: (import (slib dynamic))
Provides a kind of name-value store, which can be accessed globally. (This is essentially the same as R7RS parameters, with a different syntax.)
make-dynamic
creates a dynamic object wrapping a given object.
dynamic?
returns true only if the given object is a dynamic.
dynamic-ref
returns the value of a given dynamic object.
dynamic-set!
changes the value of the given dynamic object.
call-with-dynamic-binding
temporarily rebinds a given dynamic
object to a new value within the given procedure.
(let ((x (make-dynamic 'a)) ;
(y (make-dynamic 'b)))
(dynamic? x) ;
(eq? 'a (dynamic-ref x)) ;
(eq? 'b (dynamic-ref y))
(dynamic-set! x 'c) ;
(call-with-dynamic-binding x 'd ;
(lambda () (eq? 'd (dynamic-ref x))))
(eq? 'c (dynamic-ref x))) ;
Names x as the dynamic object with value 'a |
|
Returns #t as x is a dynamic object |
|
Retrieves the value of the given dynamic object, and checks it is correct | |
Changes the value of the given dynamic object | |
Within the lambda x is now bound to 'd |
|
and x reverts to holding 'c after the call |
Format: (import (slib format))
This library provides an almost complete implementation of Common Lisp’s
format
function.
The format string syntax is complex. Good descriptions are:
-
SLIB’s documentation: http://people.csail.mit.edu/jaffer/slib/Format.html
-
in Peter Seibel’s Practical Common Lisp: http://www.gigamonkeys.com/book/a-few-format-recipes.html
-
in Guy Steele’s Common Lisp: The Language, 2nd edition: https://www.cs.cmu.edu/Groups/AI/util/html/cltl/clm/node200.html
Soundex: (import (slib soundex))
This implementation of the Russell Soundex] algorithm is based on
Knuth, Vol. 3 "Sorting and searching", pp.391-2: note, reexported by (robin text)
The soundex algorithm returns a code for a word, and equivalent sounding words should return equivalent codes:
> (soundex "pair")
"P600"
> (soundex "pare")
"P600"
> (soundex "rabbit")
"R130"
> (soundex "racket")
"R230"
> (soundex "smith")
"S530"
> (soundex "smythe")
"S530"
String ports: (import (slib string-port))
Provides procedures to use strings as the current input port, rather like
call-with-input-file
and call-with-output-file
.
call-with-input-string
takes a string and a procedure, which must accept a port
as its single argument; the string will be used as the input source for that port:
$ (call-with-input-string "(1 2 3)"
(lambda (ip) (let ((vals (read ip))) (apply + vals))))
6
call-with-output-string
takes a procedure, which must accept a port as its single
argument; output written to that port is returned as a string on exit.
$ (call-with-output-string (lambda (ip) (show ip "first" nl "second" nl)))
"first\nsecond\n"
(The show
procedure is from the (scheme show)
library.)
SSAX XML Parser: (import (slib xml-parse))
This SLIB library exposes various levels of the XML parsing process.
For more details, see http://people.csail.mit.edu/jaffer/slib/Parsing-XML.html#Parsing-XML
More information on SSAX parsing is available at http://ssax.sourceforge.net/
The main top-level function is ssax:xml→sxml
. This takes two
arguments: an input port, and an (optionally empty) association list of
namespace prefixes to URIs. The function returns an s-expression containing
the contents of the XML document read from the input port.
#|kawa:2|# (|ssax:xml->sxml| (open-input-string "<tag>content</tag>") '())
(*TOP* (tag content))
#|kawa:3|# (define *str* "<person gender=\"male\"><name>Peter</name><number>1234</number></person>")
#|kawa:4|# (|ssax:xml->sxml| (open-input-string *str*) '())
(*TOP* (person (@ (gender male)) (name Peter) (number 1234)))
(The vertical bars around the function calls are sometimes required in Kawa.)
Notice the XML strings are converted to s-expressions. Attributes are marked "@". All values are strings.
URIs: (import (slib uri))
A package for creating, decoding and testing various forms of URI.
absolute-path
absolute-path?
returns true if the given filename is an absolute
path, or false if it depends on the current directory.
> (absolute-path? "/usr/local/bin/scheme")
#t
> (absolute-path? "../filename")
#f
absolute-uri?
absolute-uri?
returns true if the given uri is an absolute uri (containing
a complete description of the named resource), or false otherwise.
> (absolute-uri? "ftp://example.org/resource.txt")
#t
> (absolute-uri? "resource.txt")
#f
glob-pattern?
glob-pattern?
returns true if the given string contains any symbol typically
used in a glob, i.e. * ? [ ]
> (glob-pattern? "/home/dir/*/file.txt")
#t
> (glob-pattern? "/home/dir/x/file?.txt")
#t
> (glob-pattern? "/home/dir/x/fil[e].txt")
#t
> (glob-pattern? "/home/dir/x/file.txt")
#f
html syntax
The following four functions generate html text for different purposes:
-
html:anchor
creates a named location given a name as a string. -
html:base
returns a string representing the base of given uri. -
html:isindex
creates a string for a search prompt (now deprecated for html forms). -
html:link
takes a uri and title, and returns a link to uri displaying the title.
> (html:anchor "location")
<A NAME="location"></A>
> (html:base "http:peterlane.info")
<BASE HREF="http:peterlane.info">
> (html:isindex "Search term: ")
<ISINDEX PROMPT="Search term: ">
> (html:link "http://peterlane.info" "home page")
<A HREF="http://peterlane.info">home page</A>
Use "<A HREF=#location>" to link back to this location. |
make-uri
make-uri
constructs a URI given from 0 to 5 arguments. These are: scheme, authority,
path, query, fragment. These are optional from the front, so a single argument will be treated as the
fragment; two arguments as a query and then a fragment, etc.
> (make-uri) ;
> (make-uri "xyz") ;
#xyz
> (make-uri "query" "xyz") ;
?query#xyz
> (make-uri "http" "peterlane.info" "/files/location" "query" "xyz") ;
http://peterlane.info/files/location?query#xyz
Returns the empty string | |
Single argument is a Fragment | |
Query and Fragment | |
All components: the authority in this case is the web address, and the path the relative location of files |
null-directory?
null-directory?
takes a string and returns true if the string
names the current directory (so changing to it would not make any change).
parse-ftp-address
parse-ftp-address
converts a string, representing an ftp address, into a list of up
to four values: the username, password, remote site, and remote directory. #f
is returned if any
of these values is not present, or #f
instead of a list if the string is not an ftp address.
> (parse-ftp-address "ftp://username@ftp.someplace.site/")
("username" #f "ftp.someplace.site" #f)
> (parse-ftp-address "ftp://username:password@ftp.someplace.site/dir")
("username" "password" "ftp.someplace.site" "dir")
path→uri
path→uri
converts a given path (as a string) into a URI with an absolute address.
> (path->uri "filename.txt")
file:/home/NAME/CURRENT-DIRECTORY/filename.txt
> (path->uri "/usr/local/filename.txt")
file:/usr/local/filename.txt
uri→tree
uri→tree
takes a URI and returns a list of five values corresponding to the scheme, authority, path, query, fragment:
> (uri->tree "file:/usr/local/filename.txt")
(file #f ("" "usr" "local" "filename.txt") #f #f)
uri:decode-query
uri:decode-query
converts a given query string into an association list
of key-value pairs:
> (uri:decode-query "name=XXX&date=32")
((date "32") (name "XXX"))
uri:make-path
uri:make-path
takes a list of strings, and returns a path component by joining
the strings together with a suitable separator:
> (uri:make-path '("a" "b" "c"))
"a/b/c"
uri:splitfields
uri:splitfields
splits a string at a given character.
> (uri:splitfields "some text to split" #\space)
'("some" "text" "to" "split")
uric:decode/encode
uric:decode
and uric:encode
convert a string to and from a form
with certain characters rewritten using % octal values:
> (uric:decode "xxx%20yyy")
"xxx yyy"
> (uric:encode "xxx yyy")
"xxx%20yyy"
An optional second argument to uric:encode
provides a string of characters to allow.
SLIB Common
This library contains some core functions required throughout the SLIB
collection. Apart from (slib:version)
users of SLIB probably do not need to
call these functions.
add-base-table-implementation
Internal support for database library: adds a supported base implementation to the list of such implementations.
base-table-implementations
Internal support for database library: contains a list of supported base implementations.
call-with-open-ports
char-code-limit
A constant 256: One greater than the largest integer which can be returned by
char→integer
gentemp
Returns a new symbol.
identity
A single-parameter identity function.
make-exchanger
Provides mutually exclusive access to its resource: when called, it returns its current content replacing it with its argument.
most-positive-fixnum
Constant #xFFFFFFFF
open-file
A general method to open a port to read or write.
output-port-height
A constant 24: default display height (used e.g. in char-plot)
output-port-width
A constant 79: default display width (used e.g. in char-plot)
provided?
Checks if features, such as big integers, are supported by the current implementation.
slib:version
Returns the current version SLIB.
slib:warn
Displays a warning to the current-error-port
before proceeding.
software-type
Returns a symbol indicating the generic operating system type: the choice of possible return types has been reduced for R7RS to 'windows, 'posix or 'unix.
system
Calls the operating system.
tmpnam
A unique string name, used for temporary files.
with-load-pathname
Takes a path
and a thunk
, evaluates thunk
with an internal variable
bound to the path.
SLIB Array Libraries
SLIB provides a number of libraries for defining and working with arrays. The array type used is SRFI 63, which was originally a package in SLIB. SRFI 63 provides functions to create, modify and examine arrays.
The collection includes:
-
array-for-each
: Functions for applying functions to arrays. -
array-interpolate
: Functions to reduce/resample arrays. -
byte
: A library for arrays of small integers (although R7RS includesbytevector
, several libraries in SLIB make use of byte). -
determinant
: A number of standard matrix-algebra functions. -
subarray
: Functions to reduce or access sub-arrays.
SRFI 63: (import (srfi 63))
SLIB uses the array data type from SRFI 63. This section covers some simple examples to illustrate basic use of the array data type. For more details, refer to the SLIB documentation: http://people.csail.mit.edu/jaffer/slib/Arrays.html
There are two basic ways of creating arrays:
-
an empty array, using
make-array
-
an array with pre-determined content:
-
using
list→array
, or -
using
vector→array
-
An empty array is constructed from a prototype, which is the initial value in a given array, vector or string; an empty prototype will leave the initial value unspecified. Following the prototype are the dimensions of the array.
For example, to construct a 3x2 array filled with 0:
#|kawa:65|# (define a (make-array #(0) 3 2)) ;
#|kawa:66|# a
srfi.63$array@7e6f74c
#|kawa:68|# (array->list a) ;
((0 0) (0 0) (0 0)) ;
The prototype #(0) is used to fill the array with 0s. |
|
array→list is provided to convert our array into a list-of-lists form. |
|
We end up with 3 rows, each of size two, filled with 0s. |
To construct an array with pre-determined content from a list of lists:
list→array
must also be given the "rank" (number of dimensions) of the
array and, as above, a prototype.
#|kawa:71|# (define b (list->array 2 #(0) '((1 2) (3 4) (5 6)))) ;
#|kawa:72|# b
srfi.63$array@bcec361
#|kawa:73|# (array->list b)
((1 2) (3 4) (5 6))
Constructs an array of rank 2, with 0 as the prototype, and the given values |
To construct an array with pre-determined content from a vector. The input vector is simply a vector of the values. The second argument is the prototype, as above. The remaining arguments give the required dimensions of the array.
#|kawa:92|# (define c (vector->array #(1 2 3 4 5 6 7 8 9 10 11 12) #(0) 3 4))
#|kawa:93|# (array->list c)
((1 2 3 4) (5 6 7 8) (9 10 11 12))
#|kawa:94|# (array->vector c) ;
#(1 2 3 4 5 6 7 8 9 10 11 12)
#|kawa:95|# (define c (vector->array #(1 2 3 4 5 6 7 8 9 10 11 12) #(0) 2 3 2))
#|kawa:96|# (array->list c)
(((1 2) (3 4) (5 6)) ((7 8) (9 10) (11 12)))
array→vector is an alternative way to retrieve the elements of an array,
this time into a vector in row-major order. |
Access elements in an array using array-ref
and array-set!
:
#|kawa:75|# (array->list a)
((0 0) (0 0) (0 0))
#|kawa:78|# (array-ref a 2 1) ;
0
#|kawa:79|# (array-set! a 'x 2 1)
#|kawa:80|# (array-ref a 2 1)
x
#|kawa:81|# (array->list a)
((0 0) (0 0) (0 x))
Note order of indexes is the same as in make-array |
Information about the array can be found using array-rank
to find the number of dimensions of
an array, array-dimensions
to return a list of the dimensions, and array-in-bounds?
returns
true if its indices are valid for the given array:
#|kawa:82|# (array-rank a)
2
#|kawa:83|# (array-dimensions a)
(3 2)
#|kawa:84|# (array-in-bounds? a 2 1)
#t
#|kawa:85|# (array-in-bounds? a 1 2)
#f
Finally, array?
is used to tell if an object is of this array type or not, and
equal?
is extended to test if two arrays are equal.
#|kawa:86|# (array? 2)
#f
#|kawa:87|# (array? a)
#t
#|kawa:88|# (array->list a)
((0 0) (0 0) (0 x))
#|kawa:89|# (equal? a 2)
#f
#|kawa:90|# (equal? a '((0 0) (0 0) (0 x)))
#f
#|kawa:91|# (equal? a (list->array 2 #(0) '((0 0) (0 0) (0 x))))
#t
The following libraries provide more functionality when working with arrays.
Array Mapping: (import (slib array-for-each))
This library provides implementations of for-each
and map
for arrays, as well as functions
to work on the indices of an array.
array-for-each
array-for-each
takes a procedure and one or more arrays. The procedure
is applied to the equivalent elements of each array in row-major order.
The example below simply displays each element in the given array and returns #t
.
sash[r7rs]> (define x (list->array 2 #() '((1 2) (3 4))))
#<unspecified>
sash[r7rs]> (array-for-each display x)
1234#t
array-indexes
array-indexes
takes an array as an argument and returns a new array
of the same dimensions with lists of indexes in each element position.
sash[r7rs]> (define x (list->array 2 #() '((1 2) (3 4))))
#<unspecified>
sash[r7rs]> (array-indexes x)
#<<array> 0x2b52960>
sash[r7rs]> (matrix->lists (array-indexes x))
(((0 0) (0 1)) ((1 0) (1 1)))
array-index-for-each
array-index-for-each
takes an array and a procedure and applies
the procedure to the indices of each element in the array.
sash[r7rs]> (define x (list->array 2 #() '((1 2) (3 4))))
#<unspecified>
sash[r7rs]> (array-index-for-each x (lambda args (map display args)))
11011000#t
Notice the order of application is not specified.
array-index-map!
array-index-map!
takes an array and a procedure and applies
the procedure to the indices of each element in the array storing the return
value in the corresponding element of the array.
sash[r7rs]> (define a (vector 0 0 0))
#<unspecified>
sash[r7rs]> a
#(0 0 0)
sash[r7rs]> (array-index-map! a (lambda args (apply + args)))
#t
sash[r7rs]> a
#(0 1 2)
In this case, the original array a
has the sum of its indices placed into its elements.
array-map!
array-map!
takes a result array, a procedure and one or more source arrays.
The procedure is applied to the equivalent elements of each source array in row-major order.
The return values of the procedure are placed into the respective element of the result array.
In the example below x
is used as both the result array and the first source array.
sash[r7rs]> (define x (list->array 2 #() '((1 2) (3 4))))
#<unspecified>
sash[r7rs]> (define y (list->array 2 #() '((5 6) (7 8))))
#<unspecified>
sash[r7rs]> (array-map! x + x y)
#t
sash[r7rs]> (matrix->lists x) ;
((6 8) (10 12))
matrix→lists is from (slib determinant) |
array-map
array-map
takes an array prototype, a procedure and one or more arrays.
The procedure is applied to the equivalent elements of each array in row-major order.
The return values of the procedure are placed into the respective element of a new array
built using the type of the given prototype.
sash[r7rs]> (define x (list->array 2 #() '((1 2) (3 4))))
#<unspecified>
sash[r7rs]> (define y (list->array 2 #() '((5 6) (7 8))))
#<unspecified>
sash[r7rs]> (matrix->lists (array-map #() + x y)) ;
((6 8) (10 12))
matrix→lists is from (slib determinant) |
array:copy!
array:copy!
copies the elements of the second vector or array into the
corresponding positions of the first vector or array; the destination must be at least
as large as the source in each dimension.
sash[r7rs]> (define v (vector 1 2 3))
#<unspecified>
sash[r7rs]> (define w (vector 4 5 6))
#<unspecified>
sash[r7rs]> v
#(1 2 3)
sash[r7rs]> (array:copy! v w)
#t
sash[r7rs]> v
#(4 5 6)
Array Interpolation: (import (slib array-interpolate))
This library provides two functions to obtain interpolated values or arrays formed from interpolated values of a source array.
interpolate-array-ref
interpolate-array-ref
takes an array and a sequence of index
positions as real numbers. This is very similar to array-ref
, however the
index positions need not be integers and so define a point within the array.
The function returns an interpolated value based on the coordinates nearest
to that point.
For example:
> (define arr (list->array 2 #() '((1 2 3) (4 5 6))))
> (interpolate-array-ref arr 1 0.1)
4.1
The call to interpolate-array-ref
selects the row of index 1, which is (4 5
6), and position 0.1 within that row. The value returned is (+ (* 0.9 4) (* 0.1 5)) = 4.1,
the intermediate value between 4 and 5 lying a tenth of the way from 4.
Similarly:
> (define arr (list->array 2 #() '((1 2 3) (4 5 6))))
> (interpolate-array-ref arr 0.5 0.25)
2.75
The first index is mid-way between rows index 0 and index 1, and the second index is between the columns index 0 and index 1.
The interpolated value is calculated as:
-
(+ (* 0.75 4) (* 0.25 5)) = 4.25, a quarter of the way between the 4 and 5 (columns 0 and 1 in row 1)
-
(+ (* 0.75 1) (* 0.25 2)) = 1.25, a quarter of the way between the 1 and 2 (columns 0 and 1 in row 2)
-
(+ (* 0.5 4.25) (* 0.5 1.25)) = 2.75, midway between these two values (rows 1 and 2)
resample-array!
resample-array!
takes two arrays of equal rank but unequal dimension. The first array is
filled with values formed by interpolating its values from the second array.
> (define arr1 (list->array 2 #() '((1 2 3 4) (5 6 7 8))))
> (define arr2 (make-array #() 2 3))
> (array->list arr2)
((0 0 0) (0 0 0))
> (resample-array! arr2 arr1)
> (array->list arr2)
((1 5/2 4) (5 13/2 8))
The interpolation process retains the outer corners. So arr2
preserves the 1, 4, 5 and 8 in its corners.
The value of 5/2 in the first row is obtained from the middle value of the first row,
computed as: (interpolate-array-ref arr1 0 1.5)
Determinant: (import (slib determinant))
This library is a little misnamed. Apart from determinants, it also provides a range of functions on single and pairs of arrays, here treating the arrays as matrices.
All the functions take either a SRFI-63 array or a list of lists as the matrix definition.
determinant
determinant
returns the determinant of a given matrix.
sash[r7rs]> (determinant '((1 2) (3 4)))
-2
matrix→array
matrix→array
returns a SRFI-63 array from given matrix
definition (e.g. list-of-lists):
sash[r7rs]> (matrix->array '((1 2) (3 4)))
#<<array> 0x2a6a400>
matrix→lists
matrix→lists
converts a given matrix definition into a list of lists:
sash[r7rs]> (matrix->lists (matrix->array '((1 2) (3 4))))
((1 2) (3 4))
sash[r7rs]> (matrix->lists '((1 2) (3 4)))
((1 2) (3 4))
matrix:difference
matrix:difference
takes two matrices of numbers and
returns their element-wise difference. If the matrices are not of equal dimension,
returns a matrix of the smallest size.
sash[r7rs]> (matrix:difference '((1 2) (3 4)) '((5 6) (7 8)))
((-4 -4) (-4 -4))
sash[r7rs]> (matrix:difference '((1 2) (3 4)) '((5 6 7) (8 9 10)))
((-4 -4) (-5 -5))
matrix:inverse
matrix:inverse
returns the inverse of a given square matrix. If the
matrix is singular, the function returns #f
.
sash[r7rs]> (matrix:inverse '((1 2) (3 4)))
((-2 1) (3/2 -1/2))
sash[r7rs]> (matrix:inverse '((0 0) (0 0)))
#f
matrix:product
matrix:product
takes two arguments, at least one of which must be
a matrix. If the other argument is a scalar, returns the element-wise product
of the scalar with the matrix. If the other argument is a matrix, returns the
matrix product.
sash[r7rs]> (matrix:product '((1 2) (3 4)) '((5 6) (7 8)))
((19 22) (43 50))
sash[r7rs]> (matrix:product '((1 2) (3 4)) 2)
((2 4) (6 8))
sash[r7rs]> (matrix:product 2 '((1 2) (3 4)))
((2 4) (6 8))
matrix:sum
matrix:sum
takes two matrices of numbers and
returns their element-wise sum. If the matrices are not of equal dimension,
returns a matrix of the smallest size.
sash[r7rs]> (matrix:sum '((1 2) (3 4)) '((5 6) (7 8)))
((6 8) (10 12))
sash[r7rs]> (matrix:sum '((1 2 3) (4 5 6)) '((7 8) (9 10)))
((8 10) (13 15))
transpose
transpose
returns a copy of the given matrix with
entries flipped about the diagonal.
sash[r7rs]> (transpose '((1 2 3) (4 5 6) (7 8 9)))
((1 4 7) (2 5 8) (3 6 9))
Subarray: (import (slib subarray))
The subarray library is used to identify smaller components of arrays. The returned array shares storage with the original, so a copy should be made if required.
array-trim
array-trim
is a simplified version of subarray
. Its first
argument should be a vector or array. The following arguments, one per
dimension of the array, indicate how much to remove from one or other end.
Positive values take from the "left", low-index, side and negative values from
the "right", high-index side.
#|kawa:46|# (define a (list->array 2 #() '((1 2 3) (4 5 6) (7 8 9))))
#|kawa:47|# (array->list (array-trim a 1 0)) ;
((4 5 6) (7 8 9))
#|kawa:48|# (array->list (array-trim a 0 1)) ;
((2 3) (5 6) (8 9))
#|kawa:49|# (array->list (array-trim a 2 -1)) ;
((7 8))
Trim the first row | |
Trim the first column | |
Trim the first two rows and last column |
As with subarray
, the trimmed array shares storage with the source array.
subarray
subarray
precisely selects contiguous subsets of a given array. Its first argument should be
an array. There follow one argument per dimension of the array. Each argument is either:
-
an integer: selecting that index of the given dimension
-
a pair of integers: selecting that range of indices in the given dimension
-
#f
: making no selection, and so that dimension is not altered.
If there are less arguments than dimensions, the remainder are treated as #f
.
#|kawa:4|# (define a (list->array 2 #() '((1 2 3) (4 5 6) (7 8 9))))
#|kawa:11|# (array->list (subarray a 1 #f)) ;
(4 5 6)
#|kawa:12|# (array->list (subarray a #f 1)) ;
(2 5 8)
#|kawa:14|# (array->list (subarray a #f '(0 1))) ;
((1 2) (4 5) (7 8))
#|kawa:15|# (array->list (subarray a '(1 0) #f)) ;
((4 5 6) (1 2 3))
#|kawa:17|# (array->list (subarray a '(2 1) '(0 1))) ;
((7 8) (4 5))
Selects a single row in the array: the second row | |
Selects a single column in the array: the second column | |
Selects the first and second columns | |
Selects the last two rows, but in reverse order | |
Selects the last two rows in reverse, and the first two columns |
Although the arrays are shared, information is reported as appropriate:
#|kawa:18|# (define b (subarray a '(2 1) '(0 1)))
#|kawa:19|# (array-dimensions a)
(3 3)
#|kawa:20|# (array-dimensions b)
(2 2)
#|kawa:21|# (array-rank b)
2
#|kawa:25|# (array-set! b 'X 0 0)
#|kawa:26|# (array->list a) ;
((1 2 3) (4 5 6) (X 8 9))
#|kawa:27|# (array->list b)
((X 8) (4 5))
The source array, a , has also been changed in the appropriate place |
There is no array-copy function in SLIB. The following can be used:
#|kawa:39|# (define c (array-map #() identity b)) ;
#|kawa:40|# (array->list c)
((X 8) (4 5))
#|kawa:42|# (array-set! c 'y 1 1)
#|kawa:43|# (array->list c) ;
((X 8) (4 y))
#|kawa:44|# (array->list a) ;
((1 2 3) (4 5 6) (X 8 9))
#|kawa:45|# (array->list b)
((X 8) (4 5))
array-map from (slib array-for-each) , identity from (slib common) |
|
c is updated |
|
a and b are not updated, as c is no longer shared |
SLIB Colour Libraries
SLIB includes a number of libraries for defining, storing and manipulating colours.
-
color
: defines a datatype for colours -
color-name
: a framework to store/retrieve colour names in SLIB’s database implementation -
color-space
: conversions in colour spaces -
daylight
: models the sun and sky colours -
nbs-iscc
: mapping of colour names to colours -
resene
: mapping of colour names to colours -
saturate
: mapping of colour names to colours
The following are good references for:
-
an overview of these libraries: http://people.csail.mit.edu/jaffer/Color/Color-Scheme
-
more about colours and their names: http://people.csail.mit.edu/jaffer/Color/
NBS/ISCC Colour System: (import (slib nbs-iscc))
This library provides a mapping of colour names to colour values (as defined in (slib color)
)
based on the NBS/ISCC colour system. For more information see http://tx4.us/nbs-iscc.htm
Two functions are provided:
-
nbs-iscc-names
returns a list of all the names -
nbs-iscc
returns the named colour
sash[r7rs]> (length (nbs-iscc-names))
267
sash[r7rs]> (list-ref (nbs-iscc-names) 0)
"vivid yellowish green"
sash[r7rs]> (list-ref (nbs-iscc-names) 100)
"vivid purplish red"
sash[r7rs]> (nbs-iscc "vivid yellowish green")
#<<color> 0x2f629a0>
sash[r7rs]> (color->string (nbs-iscc "vivid yellowish green")) ;
"sRGB:39/166/76"
sash[r7rs]> (nbs-iscc (list-ref (nbs-iscc-names) 100))
#<<color> 0x226a900>
sash[r7rs]> (color->string (nbs-iscc (list-ref (nbs-iscc-names) 100)))
"sRGB:206/70/118"
sash[r7rs]> (nbs-iscc "rnd") ;
#f
color→string is available from the (slib color) library |
|
nbs-iscc returns #f if the name is not recognised |
Resene Colour System: (import (slib resene))
This library provides a mapping of colour names to colour values (as defined in (slib color)
)
based on the Resene colour system. For more information see http://www.resene.co.nz
Two functions are provided:
-
resene-names
returns a list of all the names -
resene
returns the named colour
sash[r7rs]> (import (slib resene))
#<unspecified>
sash[r7rs]> (length (resene-names))
1379
sash[r7rs]> (list-ref (resene-names) 0)
"mantis"
sash[r7rs]> (list-ref (resene-names) 100)
"st tropaz"
sash[r7rs]> (resene "mantis")
#<<color> 0x2d78ea0>
sash[r7rs]> (color->string (resene "mantis")) ;
"sRGB:127/193/92"
sash[r7rs]> (resene (list-ref (resene-names) 100))
#<<color> 0xd6fa40>
sash[r7rs]> (color->string (resene (list-ref (resene-names) 100)))
"sRGB:50/84/130"
sash[r7rs]> (resene "rnd") ;
#f
color→string is available from the (slib color) library |
|
resene returns #f if the name is not recognised |
Note, if you include the Resene RGB Values List in binary form in a program, then you must include its license with your program:
-
Resene RGB Values List
-
For further information refer to http://www.resene.co.nz
-
Copyright Resene Paints Ltd 2001
-
Permission to copy this dictionary, to modify it, to redistribute it, to distribute modified versions, and to use it for any purpose is granted, subject to the following restrictions and understandings.
-
Any text copy made of this dictionary must include this copyright notice in full.
-
Any redistribution in binary form must reproduce this copyright notice in the documentation or other materials provided with the distribution.
-
Resene Paints Ltd makes no warranty or representation that this dictionary is error-free, and is under no obligation to provide any services, by way of maintenance, update, or otherwise.
-
There shall be no use of the name of Resene or Resene Paints Ltd in any advertising, promotional, or sales literature without prior written consent in each case.
-
These RGB colour formulations may not be used to the detriment of Resene Paints Ltd.
-
Saturated Colour System: (import (slib saturate))
This library provides a mapping of saturated colour names to colour values (as
defined in (slib color)
).
Two functions are provided:
-
saturate-names
returns a list of all the names -
saturate
returns the named colour
sash[r7rs]> (import (slib saturate))
#<unspecified>
sash[r7rs]> (length (saturate-names))
19
sash[r7rs]> (saturate-names)
("green" "greenish blue" "reddish purple" "purplish blue" "yellow green" "bluish purple" "yellow" "blue" "blue green" "purplish red" "red purple" "yellowish orange" "bluish green" "reddish orange" "purple" "red" "yellowish green" "greenish yellow" "orange")
sash[r7rs]> (saturate "red")
#<<color> 0x35c02c0>
sash[r7rs]> (color->string (saturate "red")) ;
"CIEXYZ:0.735484/0.264516/0"
sash[r7rs]> (saturate "rnd") ;
#f
color→string is available from the (slib color) library |
|
saturate returns #f if the name is not recognised |
SLIB Mathematics Libraries
SLIB provides a lot of valuable support for various mathematical tasks; Aubrey Jaffer, the main implementor and maintainer of SLIB, also wrote JACAL, a symbolic mathematics program relying heavily on features provided by SLIB.
Factor: (import (slib factor))
Functions for testing if numbers are primes, generating prime numbers, and to factor numbers.
These functions use the Solovay-Strassen primality test:
-
Robert Solovay and Volker Strassen, A Fast Monte-Carlo Test for Primality, SIAM Journal on Computing, 1977, pp 84-85.
factor
factor
takes one argument and returns a list of the prime factors of that
number: the numbers are in no guaranteed order.
> (factor 5)
(5)
> (factor 100)
(5 5 2 2)
jacobi-symbol
The jacobi-symbol
is used in modular arithmetic with one application, as here,
being tests for primality. The function returns 0, -1 or 1 given two integers.
> (jacobi-symbol 15 7)
1
> (jacobi-symbol 63 7)
0
> (jacobi-symbol 7 15)
-1
prime:trials
prime:trials
controls the likelihood that prime?
will accept a composite
number as a prime. The probability is 2^(- prime:trials
)^
prime:trials
is a parameter object, so you can change it to a higher value, if required:
> (prime:trials)
30
> (prime:trials 100)
> (prime:trials)
100
prime?
prime?
returns true or false depending on if the given number passes the
Solovay-Strassen primality test.
> (prime? 17)
#t
> (prime? 1)
#f
primes<
primes<
accepts two arguments: a start value and a count. It returns a list
of count
prime numbers less than the start value.
> (primes< 18 2)
(13 17)
primes>
primes>
accepts two arguments: a start value and a count. It returns a list
of count
prime numbers greater than the start value.
> (primes> 18 2)
(19 23)
Maths Integer Functions: (import (slib math-integer))
Using the functions in this library means that integer values will return integer results. Using non-integer values generates errors.
Further documentation: http://people.csail.mit.edu/jaffer/slib/Irrational-Integer-Functions.html#Irrational-Integer-Functions
For example:
sash[r7rs]> (expt 2.1 3)
9.261000000000001
sash[r7rs]> (integer-expt 2.1 3)
Unhandled exception
Condition components:
1. &error
2. &message integer-expt
3. &irritants (2.1 3)
4. &stack-trace
...
sash[r7rs]> (integer-expt 2 3)
8
Additionally, in cases where an inexact result might be expected, these functions will return the nearest integer equivalent:
For example:
sash[r7rs]> (sqrt 9)
3
sash[r7rs]> (sqrt 10)
3.1622776601683795
sash[r7rs]> (integer-sqrt 9)
3
sash[r7rs]> (integer-sqrt 10)
3
Maths Real Functions: (import (slib math-real))
The aim of this library is to prevent non-real numbers creeping into calculations. An error is raised if non-real arguments are given to functions, or if non-real results are returned.
Further documentation: http://people.csail.mit.edu/jaffer/slib/Irrational-Real-Functions.html#Irrational-Real-Functions
For example:
sash[r7rs]> (sqrt -2)
0.0+1.4142135623730951i
sash[r7rs]> (real-sqrt -2)
Unhandled exception
Condition components:
1. &error
2. &message real-sqrt
3. &irritants (-2)
4. &stack-trace
sash[r7rs]> (sin 0+i)
0.0+1.1752011936438014i
sash[r7rs]> (real-sin 0+i)
Unhandled exception
Condition components:
1. &error
2. &message real-sin
3. &irritants (0+1i)
4. &stack-trace
Minimize: (import (slib minimize))
The Golden Section Search algorithm can find minima of functions where derivatives are expensive to compute or unavailable.
golden-section-search
golden-section-search
takes four arguments:
-
the function to minimize (of one argument)
-
the lowest value of
x
to search from -
the highest value of
x
to search to -
a stopping condition for the search, which is one of
-
a positive number defines a target tolerance
-
a negative number is negated to define the number of iterations
-
a function of
(x0 x1 a b fa fb count)
ends the search by returning#t
-
The function returns a dotted pair: the value of x
for the minimum and f(x)
sash[r7rs]> (golden-section-search square -10 10 -100) ;
(4.258043576850981e-21 . 1.8130935102361897e-41) ;
Find the minimum of the square value in range (-10, 10) for 100 iterations |
|
The minimum is x=0 and (square x)=0 |
The following example minimizes its function to within the specified tolerance:
sash[r7rs]> (golden-section-search (lambda (x) (+ (* x x x) (* -2 x) -5)) 0 1 (/ 10000)))
(0.8164883855245578 . -6.0886621077391165)
Further documentation: http://people.csail.mit.edu/jaffer/slib/Minimizing.html
Random Inexact Numbers: (import (slib random-inexact))
A set of functions for generating random inexact numbers. This library is built on top of SRFI 27. All the functions take an optional last argument to define the state. The state is implementation dependent.
The functions all use the default random source, which you can randomise before use using SRFI 27’s:
> (random-source-randomize! default-random-source)
random:exp
random:exp
returns an inexact real in an exponential distribution with mean 1.
sash[r7rs]> (random:exp)
0.34154536262153173
sash[r7rs]> (random:exp)
0.05480703829750473
sash[r7rs]> (random:exp)
3.949150883906155
random:hollow-sphere!
random:hollow-sphere!
fills a given vector with numbers
generated by random:normal
, but ensures the vector is on the n-dimensional
unit sphere, where n is the length of the given vector.
sash[r7rs]> (define v (vector 0 0 0))
#<unspecified>
sash[r7rs]> (random:hollow-sphere! v)
#t
sash[r7rs]> v
#(0.15379204615082398 0.8499736823380848 0.5038777092443952)
sash[r7rs]> (+ (square (vector-ref v 0)) (square (vector-ref v 1)) (square (vector-ref v 2)))
0.9999999999999999
random:normal
random:normal
returns an inexact real in a normal distribution, mean 0 and
standard deviation 1.
sash[r7rs]> (random:normal)
0.7092759009436378
sash[r7rs]> (random:normal)
1.0895040600796109
sash[r7rs]> (random:normal)
-0.03239748330944343
random:normal-vector!
random:normal-vector!
fills a given vector with numbers generated by random:normal
.
sash[r7rs]> (define v (vector 0 0 0))
#<unspecified>
sash[r7rs]> (random:normal-vector! v)
1.838805009717658
sash[r7rs]> v
#(-0.6720177712702253 -0.9211383829955655 0.7339626722027299)
random:solid-sphere!
random:solid-sphere!
fills a given vector with numbers generated
by random:normal
, but ensures the vector fits within the n-dimensional unit
sphere, where n is the length of the given vector.
sash[r7rs]> (define v (vector 0 0 0))
#<unspecified>
sash[r7rs]> (random:solid-sphere! v)
0.810489476742576
sash[r7rs]> v
#(-0.7899861662963674 -0.09111554959314132 -0.15656629775645328)
sash[r7rs]> (+ (square (vector-ref v 0)) (square (vector-ref v 1)) (square (vector-ref v 2)))
0.6568931919104545
random:uniform
random:uniform
is the same as SRFI 27’s random-real
, and returns
a uniformly distributed inexact number in the range (0,1).
sash[r7rs]> (random:uniform)
0.7868209548678019
sash[r7rs]> (random:uniform)
0.2504803406880286
Rationalize: (import (slib rationalize))
R7RS includes the function rationalize
which takes
two arguments, x
and y
, and returns the simplest rational number
differing from x
by no more than y
.
Note that rationalize
only works for rational values of x
and y
. With
inexact values of x
or y
it returns an inexact value differing from x
by
no more than y
.
> (rationalize 355/113 1/10)
16/5
> (inexact 355/113)
3.14159292035398
> (inexact 16/5)
3.2
> (rationalize 3.14159729 1/10)
3.2
The first example shows an approximation to a value with a 0.1 difference.
However, notice the last example, where an inexact number is returned when seeking an approximation for PI.
The library includes the following two functions:
-
find-ratio
which returns a list of the simplest numerator and denominator whose quotient gives a rational number differing fromx
by no more thany
. -
find-ratio-between
which returns a list of the simplest numerator and denominator whose quotient gives a rational number between the givenx
andy
.
These two functions work equally well with exact or inexact values for x
and y
.
For example, find-ratio
can be used to find increasingly better approximations to PI:
#|kawa:1|# (import (slib rationalize))
#|kawa:2|# (find-ratio 3.14159729 0.01)
(22 7)
#|kawa:3|# (find-ratio 3.14159729 0.001)
(201 64)
#|kawa:4|# (find-ratio 3.14159729 0.0001)
(333 106)
#|kawa:5|# (find-ratio 3.14159729 0.00001)
(355 113)
find-ratio-between
is used as follows:
#|kawa:6|# (find-ratio-between 2/7 3/5)
(1 2)
SLIB Time/Date Libraries
The R7RS standard has a library (scheme time)
which contains three functions:
current-second
, to obtain the current time in seconds since 1/1/1970;
current-jiffy
, which returns an implementation-defined fraction of a second
from an implementation-specific start point; and jiffies-per-second
, which
returns the implementation-specific number of "jiffies" per second. The
libraries provided in SLIB help convert to and from larger units of time (such
as days and years), and also take account of time-zones. SRFI 19]
provides a useful standard library for working with dates and times, where
available.
SLIB provides a small set of libraries for managing times, dates and time-zones. These reflect Lisp and Posix treatments of time. The libraries use a variety of data formats:
- Calendar Time
-
number of seconds since 1st January 1970 (as used by R7RS
current-second
) - Decoded Time
-
nine values for second, minute, hour, date, month, year, day-of-week, daylight-saving-time? and time-zone. Note that months start with January = 1, days of week start with Monday = 0
- TM Time
-
(C’s
struct tm
) nine values for seconds, minutes, hours, date, month, year, day-of-week, days-in-year, daylight-saving-time?. Note that months start with January = 0, years start with 1900 = 0, days of week start with Sunday = 0 - Universal Time
-
number of seconds since 1st January 1900
The libraries themselves are:
-
(slib common-lisp-time)
: From Lisp, using Decoded Time and Universal Time. -
(slib posix-time)
: From C/Posix, using TM Time and Calendar Time. -
(slib time-core)
: main time conversion functions -
(slib time-zone)
: computes time-zones and daylight-saving times from the time-zone environment variable or files -
(slib tzfile)
: reads from a time-zone file
Time zone information is ultimately read via tzfile
which looks for either the
environment variable "TZ" or in one of a specified set of paths. (This
currently does not appear to support Windows.)
None of these libraries handles leap seconds.
(slib common-lisp-time)
These functions are based on those in Common Lisp to convert between Decoded Time and Universal Time.
get-decoded-time
returns the current time in Decoded Time format,
as nine values. (get-decoded-time)
is short for (decode-universal-time (get-universal-time))
.
> (get-decoded-time)
((values) 58 15 18 18 4 2017 1 #f 0)
get-universal-time
returns the current time of day as a single
integer in Universal Time format representing the number of seconds since
1/1/1900: note for comparison how R7RS’s (current-second)
returns a much smaller
value (Calendar Time, the number of seconds since 1/1/1970).
> (get-universal-time)
3701527370.61162
> (current-second)
1492540922.30859
decode-universal-time
converts a universal time (with an optional time-zone) into the nine values of Decoded Time format.
> (decode-universal-time (get-universal-time))
((values) 41 2 18 18 4 2017 1 #f 0)
The optional time-zone is the number of hours away from GMT. This is backwards from what you might expect: British Summer Time, one hour ahead of GMT, is given by -1.
> (decode-universal-time (get-universal-time) -1) ; current time in London (BST = GMT+1)
((values) 26 4 19 18 4 2017 1 #f -1)
> (decode-universal-time (get-universal-time) -5.5) ; current time in New Delhi (GMT+5.5)
((values) 54 35 23 18 4 2017 1 #f -11/2)
encode-universal-time
takes the first six values of Decoded Time
format, and returns a Universal Time representation.
> (encode-universal-time 8 50 21 18 3 2017)
3698862608.0
(slib time-core)
A collection of functions to help in time conversions based around TM Time.
current-time
is the same as current-second
. This is the Calendar Time
,
defined relative to 1/1/1970.
> (current-time)
1492540922.30859
difftime
subtracts two times, given as seconds.
leap-year?
returns true if given year is a leap-year, false otherwise.
> (leap-year? 2000)
#t
> (leap-year? 2004)
#t
> (leap-year? 1900)
#f
offset-time
adds two times together, given as seconds.
time:gmtime
takes a time in seconds and returns the TM Time information,
assuming the location is GMT:
> (time:gmtime (current-time))
#(39 45 18 18 3 117 2 107 0 0 "GMT") ;
time is 18:45 39s, 18 is the date, month is April (3), year is 2017 (117+1900), day of week is Tuesday (2), 108 days from 1st January. The last 0 is for the offset due to the time zone. |
Note that time:gmtime
calls time:split
: (time:gmtime tm)
= (time:split tm 0 0 "GMT")
(slib posix-time)
This library provides data structures and functions similar to those in C’s "time.h".
asctime
converts a TM time into a string representation:
> (asctime (gmtime (current-time)))
"Tue Apr 18 20:18:15 2017\n"
gmtime
takes a Calendar time (in seconds) and returns the TM Time information, assuming
the location is GMT (the same as time:gmtime
).
gtime
is short for (asctime (gmtime ..))
> (gtime (current-time))
"Tue Apr 18 20:38:28 2017\n"
localtime
converts a Calendar time into a TM Time. An optional second
argument specifies the time zone.
> (localtime (current-time) (read-tzfile "Asia/Calcutta"))
#(51 16 2 19 3 117 3 108 0 -19800 #(73 83 84))
> (localtime (current-time))
#(8 47 21 18 3 117 2 107 1 -3600 #(66 83 84))
ctime
is short for (asctime (localtime …))
> (ctime (current-time))
"Tue Apr 18 21:44:32 2017\n"
> (ctime (current-time) (read-tzfile "Asia/Calcutta"))
"Wed Apr 19 02:16:20 2017\n"
mktime
converts the TM Time to Calendar time:
> (current-time)
1492548597.89966
> (localtime (current-time))
#(8 50 21 18 3 117 2 107 1 -3600 #(66 83 84))
> (mktime (localtime (current-time)))
1492552289.0
gmktime
is the same as mktime
, except it assumes a GMT time zone.
(slib time-zone)
read-tzfile
takes a path or, if given #f
, uses a known path to a time-zone file.
The function then calls tzfile:read
from (slib tzfile)
and returns the result (see below).
read-tzfile
is used by time-zone
to read the specific time-zone information for a given
locality:
> (read-tzfile "Asia/Dili")
#(tz:file "/usr/share/zoneinfo/Asia/Dili" #(#(#(76 77 84) 30140 #f #f #f) #(#(84 76 84) 28800 #f #f #f) #(#(74 83 84) 32400 #f #f #f) #(#(84 76 84) 32400 #f #f #f) #(#(87 73 84 65) 28800 #f #f #f) #(#(84 76 84) 32400 #f #f #f)) #() #(-2147483648 -1830414140 -879152400 -766054800 199897200 969120000) #(0 1 2 3 4 3))
> (read-tzfile "GMT")
#(tz:file "/usr/share/zoneinfo/GMT" #(#(#(71 77 84) 0 #f #f #f)) #() #() #())
time-zone
will either:
-
return its argument, if it is a vector (i.e. already a time-zone description)
-
use
read-tzfile
if the argument is#f
or a time-zone file name prefixed with ":" -
use
string→time-zone
if the argument is a string without ":" at start-
The string is in POSIX format for a time zone, see https://www.ibm.com/developerworks/aix/library/au-aix-posix/
-
-
return
#f
if it could not read the time-zone
> (time-zone #(tz:file "/usr/share/zoneinfo/GMT" #(#(#(71 77 84) 0 #f #f #f)) #() #() #()))
#(tz:file "/usr/share/zoneinfo/GMT" #(#(#(71 77 84) 0 #f #f #f)) #() #() #())
> (time-zone ":Asia/Dili")
#(tz:file "/usr/share/zoneinfo/Asia/Dili" #(#(#(76 77 84) 30140 #f #f #f) #(#(84 76 84) 28800 #f #f #f) #(#(74 83 84) 32400 #f #f #f) #(#(84 76 84) 32400 #f #f #f) #(#(87 73 84 65) 28800 #f #f #f) #(#(84 76 84) 32400 #f #f #f)) #() #(-2147483648 -1830414140 -879152400 -766054800 199897200 969120000) #(0 1 2 3 4 3))
> (time-zone "CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00")
#(tz:rule "CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00" "CST" "CDT" 21600 18000 (3 2 0 7200) (11 1 0 7200))
(slib tzfile)
There is only one exported function: tzfile:read
. This function reads time-zone
information from a system-specified file. For example, on Linux, the file may be "/etc/localtime":
> (import (slib tzfile))
> (tzfile:read "/etc/localtime")
("/etc/localtime" #(#(#(76 77 84) -75 #f #f #f) #(#(66 83 84) 3600 #t #t #f)
#(#(71 77 84) 0 #f #t #f) #(#(66 68 83 84) 7200 #t #t #f) #(#(66 83 84) 3600 #f
#f #f) #(#(66 83 84) 3600 #t #t #t) #(#(71 77 84) 0 #f #t #t) #(#(71 77 84) 0
#f #f #f)) #() #(-2147483648 -1691964000 -1680472800 -1664143200 -1650146400
-1633903200 -1617487200 -1601848800 -1586037600 -1570399200 -1552168800
-1538344800 -1522533600 -1507500000 -1490565600 -1473631200 -1460930400
-1442786400 -1428876000 -1410732000 -1396216800 -1379282400 -1364767200
-1348437600 -1333317600 -1315778400 -1301263200 -1284328800 -1269813600
-1253484000 -1238364000 -1221429600 -1206914400 -1189980000 -1175464800
-1159135200 -1143410400 -1126476000 -1111960800 -1095631200 -1080511200
-1063576800 -1049061600 -1032127200 -1017612000 -1001282400 -986162400
-969228000 -950479200 -942012000 -904518000 -896050800 -875487600 -864601200
-844038000 -832546800 -812588400 -798073200 -781052400 -772066800 -764805600
-748476000 -733356000 -719445600 -717030000 -706748400 -699487200 -687996000
-668037600 -654732000 -636588000 -622072800 -605743200 -590623200 -574293600
-558568800 -542239200 -527119200 -512604000 -496274400 -481154400 -464220000
-449704800 -432165600 -417650400 -401320800 -386200800 -369266400 -354751200
-337816800 -323301600 -306972000 -291852000 -276732000 -257983200 -245282400
-226533600 -213228000 -195084000 -182383200 -163634400 -150933600 -132184800
-119484000 -100735200 -88034400 -68680800 -59004000 -37242000 57722400 69818400
89172000 101268000 120621600 132717600 152071200 164167200 183520800 196221600
214970400 227671200 246420000 259120800 278474400 290570400 309924000 322020000
341373600 354675600 372819600 386125200 404269200 417574800 435718800 449024400
467773200 481078800 499222800 512528400 530672400 543978000 562122000 575427600
593571600 606877200 625626000 638326800 657075600 670381200 688525200 701830800
719974800 733280400 751424400 764730000 782874000 796179600 814323600 820454400
828234000 846378000 859683600 877827600 891133200 909277200 922582800 941331600
954032400 972781200 985482000 1004230800 1017536400 1035680400 1048986000
1067130000 1080435600 1099184400 1111885200 1130634000 1143334800 1162083600
1174784400 1193533200 1206838800 1224982800 1238288400 1256432400 1269738000
1288486800 1301187600 1319936400 1332637200 1351386000 1364691600 1382835600
1396141200 1414285200 1427590800 1445734800 1459040400 1477789200 1490490000
1509238800 1521939600 1540688400 1553994000 1572138000 1585443600 1603587600
1616893200 1635642000 1648342800 1667091600 1679792400 1698541200 1711846800
1729990800 1743296400 1761440400 1774746000 1792890000 1806195600 1824944400
1837645200 1856394000 1869094800 1887843600 1901149200 1919293200 1932598800
1950742800 1964048400 1982797200 1995498000 2014246800 2026947600 2045696400
2058397200 2077146000 2090451600 2108595600 2121901200 2140045200) #(2 1 2 1 2
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 3 1 3 1 3 1 3 1 3 1 2 1 2 1 3 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 4 6 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1
2 1 2 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 7 5 6 5 6 5 6
5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6
5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6 5 6))