LISP9
Reference Manual
____ _______________________
/ / / / / / \
/ / / / __/ - / - \
/ /__/ /_\ \ __/\__ /
/ / / / / / /
/______/___/______/____/ /____/
2019-06-26
By Nils M Holm, in the public domain
LISP9 is a lexically scoped LISP-1 with tail call elimination.
It is a retro LISP in the sense that it does not add any new
ideas, but merely implements concepts that have been established
long ago. LISP9 is similar to R4RS Scheme to a degree that many
trivial Scheme programs can probably be converted to LISP9 by
performing a few simple substitutions, like SET! -> SETQ, etc.
The LISP9 system consists of a read-eval-print loop (REPL), a
bytecode compiler, and an ad-hoc, SECD-like abstract machine.
LISP9 is also a retro LISP in the sense that its heap space
would roughly fit in the core memory of a moderately sized KL10,
but the default size of the heap space can be extended easily.
Although the name of LISP9 may suggest that it runs on Plan 9,
it currently doesn't (unless you use APE). It may at some point,
though.
** INTRODUCTION ************************************************
-- PROGRAMS ----------------------------------------------------
A program is a sequence of forms that will be evaluated from
top to bottom. When typed in at the REPL ("Read-Eval-Print Loop,
the interpreter prompt), the value of each form will print.
When loaded from a file, forms will evaluate silently.
The following program computes the mean of a list of numbers:
(defun (mean a)
(let loop ((p a)
(s 0))
(if (null p)
(div s (length a))
(loop (cdr p) (+ s (car a))))))
(mean '(1 2 3 4 5))
The first form (using DEFUN) defines the MEAN function and the
second form applies the function to a list of numbers from one
to five.
If the program is to be run in batch mode, without user
interaction, the second form should print its result:
(print (mean '(1 2 3 4 5)))
While the above program is perfectly workable, there are many
ways to implement the MEAN function, for example using a DO loop:
(defun (mean a)
(do ((p a (cdr p))
(s 0 (+ s (car p))))
((null p) (div s (length a)))))
or using the higher-order function FOLD:
(defun (mean a)
(div (fold + 0 a)
(length a)))
-- FORMS -------------------------------------------------------
A LISP9 program is a set of "forms", where each form is either
- a variable
- a data object
- a function applications
- or a special form
A variable is represented by its name, which is a sequence of
symbolic characters, mostly letters, digits, and some special
characters. See the FORMAL SYNTAX for details.
Examples: foo x123 * a+b
Data objects include numbers, characters (chars), strings of
chars, vectors, lists, ordered pairs, symbols, and functions.
There are also some special objects. All types of data objects
will be explained in the next chapter.
Examples: 123 '(1 2 3) 'foo
#\x #(4 5 6) cons
"hello!" '(a . b) nil
Function applications apply a function to values (data objects
or variables). Functions themselves are typically bound to
variables. The application itself has the shape of a list, with
the function in the first position and the arguments in
subsequent positions. See the following sections for details.
Examples: (+ 1 2 3)
(cons 'a 'b)
(cdr '(a b))
(gensym)
Special forms have the same shape as function applications, but
different semantics. They are mostly used to define variables
and macros, bind variables to values, and control the flow of
program evaluation.
Examples: (def foo 17)
(let ((bar 18))
(if (= 1 1) foo bar))
-- EXPRESSIONS -------------------------------------------------
The terms "form" and "expression" are often used as synonyms,
but it is important to distinguish between special forms and
(non-special) forms.
Every expression evaluates to a value, which is written, for
example, as
5 => 5 ; five evaluates to itself
(+ 1 2) => 3 ; + applied to 1 and 3 evaluates to 3
(if 1 2 3) => 2 ; IF applied to 1, 2, 3 evaluates to 2
cons => #<function>
; the variable CONS evaluates to some
; function
The latter is an example for a variable evaluating to the value
that is bound to it.
-- SPECIAL FORMS -----------------------------------------------
Even special forms, like IF, evaluate to a value. Some special
forms have a syntax that deviates from that which was described
in the previous section. For instance, the first argument in
(cond ((foo) bar) (else baz))
looks like the application of the value of (foo) to BAR. However,
this is part of COND's syntax rather than a function application.
What COND really does it to evaluate (foo) and, if it returns a
"true" value, evaluate BAR. Else it evaluates BAZ.
In general, special forms do not evaluate their arguments, but
do something special with them. Hence their name. The arguments
of special forms are often written in angle bracket in their
descriptions to indicate that something special happens. E.g.:
(COND <CLAUSE> ...) => OBJ
-- DEFINITIONS -------------------------------------------------
Top-level (global) variables are defined by the DEF special form:
(DEF <VAR> EXPR)
Here <VAR> denotes a symbol that will be used as a variable and
EXPR denotes an expression of any type. The DEF special form
evaluates EXPR, but not <VAR>, which would be impossible anyway,
because it is not yet defined. It then defines <VAR> and binds
it to the value of EXPR. For example:
(def helpfile "lisp9.txt")
(def square (lambda (x) (* x x)))
DEF forms can only appear at the top level of a program, i.e.
they cannot appear as arguments in any other forms. They
evaluate to (the value of) EXPR, but since that value cannot be
used for anything, their value is specified as "unspecific".
Note that everything (except for MACROS and local variables,
which will be explained later) is defined using DEF -- even
functions. The second example above creates a function that
computes the square of its argument and binds it to the newly
created variable SQUARE. Note that the DEFUN special form is
normally used to define functions, though:
(defun (square x) (* x x))
DEFUN is a convenient abbreviation for the combination of DEF
and LAMBDA.
A variable can be redefined by using DEF with the same name
again. Doing so will change the binding of the variable:
(def foo 'zzz)
foo => zzz
(def foo 'bar)
foo => bar
Local functions are defined by LAMBDA special forms, which will
be explained below.
-- TYPE SIGNATURES ---------------------------------------------
A type signature describes the data types expected by a function
and the type of object returned by it. A signature generally
looks like this:
(FUNCTION TYPE1 TYPE2 ...) => TYPE
meaning that FUNCTION expects TYPE1, TYPE2, etc, and returns
TYPE. When there are multiple arguments of the same type, they
use an index to distinguish them, e.g.
(= N1 N2 ...) => T/NIL
The ellipsis (...) indicates that the preceding type occurs
zero or more times. I.e. the above signature says that the "="
function expects one or more fixnums.
The following type names will be used in the remainder of this
document:
EXPR Any type of data object can be used in the place of
OBJ EXPR, which is used to describe arguments. OBJ is used
for return types, meaning that any type of object may
be returned.
LIST These are different types of lists and pairs, which
DLIST will be described later. They indicate the list,
ALIST dotted list, association list, and ordered pair,
PAIR respectively. These types are ordered by generality
as follows: PAIR > DLIST > LIST > ALIST.
CHAR A char (character) is expected or returned.
Cn
FIXNUM A fixnum (small integer) is expected or returned.
Nn
FUN A function is expected or returned. The notation FUN^N
FUN^N indicates that a function of N arguments is expected.
STRING A string is expected or returned.
Sn
SYMBOL A string is expected or returned.
T/NIL Used to indicate that a function returns either T
(truth) or NIL (falsity). Such functions are called
predicates.
UNSPECIFIC Indicates that the value returned by a function is
uninteresting and should not be used.
VECTOR A vector (one-dimensional array) is expected or
Vn returned.
-- FUNCTIONS ---------------------------------------------------
Functions are created by the LAMBDA special form:
(LAMBDA <FORMALS> EXPR1 EXPR2 ...)
The special form contains a formal argument list, which names
the variables of the function (see LAMBDA), and a body comprised
of any positive number of expressions.
A function is applied by evaluating its arguments, binding each
of its variables for the corresponding argument and with these
bindings in effect evaluating the body of the function. Before
the value of the body is returned, the bindings will be
destroyed.
For instance, the function application
((lambda (a b) (* a b b)) (+ 1 1) 5)
will
- evaluate (+ 1 1), giving 2
- evaluate 5, giving 5
- bind 2 to A
- bind 5 to B
- evaluate (* a b b) = (* 2 5 5), giving 50
- unbind A and B, restoring their previous values
- return the result, 50
-- LEXICAL SCOPE -----------------------------------------------
Variable bindings have lexical scope in LISP9, which means that
the bindings of free variables (variables that are not defined
by a function) will be closed over and "remembered" in the
resulting function object. For instance:
(let ((a 1))
(lambda (b) (+ a b))) ; remember a=1
will return a function that adds 1 to its argument, even if the
value bound to A should change at a later time. In the lexical
(textual) context of (lambda (b) (+ a b)), A has the value 5,
so the function will use exactly that value:
(let ((a 1))
(let ((f (lambda (b) (+ a b)))) ; remember a=1
(let ((a 0))
(f 5)))) => 6
Even though in the lexical context of the application of F, A
has the value 0, the value remembered in F will be used.
Note that the binding of a variable can be changed (by using
SETQ) inside of the *same* lexical scope (indicated by LET),
even *after* defining a function:
(let ((a 1))
(let ((f (lambda (b) (+ a b))))
(setq a 2)
(f 5))) => 7
This is particularly important at the top level, because it
allows to create mutually recursive functions:
(defun (even n) (if (= 0 n) t (odd (- n 1))))
(defun (odd n) (if (= 0 n) nil (even (- n 1))))
Here the binding of ODD in EVEN is changed when defining ODD.
-- RECURSION ---------------------------------------------------
Recursion -- a function applying itself -- is a fundamental
principle in LISP9. All special forms that implement iteration
(loops) use recursion internally. Recursion is cheap in LISP9
and tail-recursive functions are guaranteed to evaluate in
constant space. For instance, given:
(defun (f x) (if (= 0 x) t (f (- x 1))))
the applications (f 1) and (f 1000) will both require the same
amount of space while evaluating. Given the functions
(def (g x) x)
(def (f x) (if (= 0 x) t (g (f (- x 1)))))
however, (f 1000) will use much more space than (f 1), because
F is not tail-recursive. A function is tail-recursive only if
no function is applied to the result of its recursive
application. In the second example, G is applied to the value
of (f (- x 1)), so F is not tail-recursive.
Tail recursion also applies to mutually recursive functions.
When F tail-applies G and G tail-applies F, both functions are
tail-recursive. E.g.:
(def (f x) (if (= 0 x) t (g x)))
(def (g x) (f (- x 1)))
are both tail-recursive.
Applications in the following positions in core special forms
are tail applications (T):
(IF x T T)
(IF* x T)
(PROG x ... T)
(LAMBDA <FORMALS> x ... T)
The same is valid for some derived special forms. Such positions
will be called "tail positions" in the descriptions of derived
special forms.
-- SYNTAX ------------------------------------------------------
The core syntax of the LISP9 language consists of the data
external representations of the data object (see next chapter),
function application, and the following special forms:
APPLY DEF IF IF* MACRO PROG QUOTE SETQ LAMBDA
There are additional syntactic constructs, which are derived
from the above, which will be listed in the next section.
-- DERIVED SYNTAX (MACROS) -------------------------------------
A macro is used to define new special forms based on existing
ones. The special form
(macro <keyword> fun)
defines a new special form introduced by the symbol in the place
of <keyword> and binds it to the macro expander FUN. FUN is a
function that takes the arguments of the corresponding special
form as arguments and transforms them to a derived form that
implements the semantics of the special form. For instance,
(macro when (lambda (p . xs) @(if ,p (prog . ,xs))))
creates a new derived special form WHEN that is like IF without
an alternative branch, but with any number of expressions in the
consequent branch. I.e. the derived syntax
(when 1 2 3 4 5)
is transformed to the core syntax
(if 1 (prog 2 3 4 5))
by the WHEN macro. Predefined derived special forms of LISP9
include:
LET LET* LABELS AND OR COND CASE DO QQUOTE
-- EVALUATION --------------------------------------------------
Evaluation of expressions comprises the following steps, in
exactly this order
(1) reading the expression (via READ)
(2) expansion of abbreviations and derived syntax
(3) compilation to bytecode
(4) interpretation by an abstract machine
Of course, the expansion of derived syntax in turn involves the
application of a macro expander, which is a function that is
already compiled to bytecode. I.e. step (4) takes places two
times, once while expanding macros in an expression, and another
time when interpreting the expanded form.
Hence the entire LISP9 language is available when writing macros.
-- COMMENTS ----------------------------------------------------
A comment starts with a semicolon and extens up to the end of
the line in which it started:
; this is a comment
Comments are ignored at the reader level, i.e. they may occur
anywhere in a program where non-relevant white space may occur.
(I.e., not in string literals, char literals, fixnum literals,
symbolic names, etc).
In earlier versions of LISP9 comments were data objects. This
approach turned out to impose too many restrictions on the
placement of comments and has hence been abandoned.
** DATA OBJECTS ************************************************
-- T -----------------------------------------------------------
T is a special object that indicates logical truth. Although all
objects exept for NIL indicate truth, T is the canonical "true"
value. It is returned by predicates in order to signal success
(a positive result). T is self-quoting and 'T equals T.
Examples:
(listp '(1 2 3)) => t
(if t 'con 'alt) => con
-- NIL ---------------------------------------------------------
NIL is a special object that indicates both the end of a list
and logical falsity. It is returned by predicates to indicate
failure (a negative result). NIL is also the only value that
will select the alternative value when passed to IF and IF*.
NIL is self-quoting and 'NIL equals NIL.
Examples:
(null nil) => t
(not nil) => t
(listp 5) => nil
(if nil 'con 'alt) => alt
(if* nil 'alt) => alt
-- SYMBOLS -----------------------------------------------------
A symbol is a sequence of characters that represents itself. The
characters that may be used to construct symbols include
- the letters a-z
- the letters a-z (but the reader will fold them to lower case)
- the decimal digits 0-0
- all special ASCII characters except for these:
( ) [ ] { } ; # ' @ ` ,
A symbol that has the form of a FIXNUM will be interpreted as a
fixnum and not as a symbol. E.g. 0, -1, and +123 are not symbol
names, because they look like fixnums.
A symbol must be quoted (see QUOTE) in expressions in order to
distinguish it from a VARIABLE.
Examples:
'foo => foo
'* => *
x^2 => x^2
-- LISTS -------------------------------------------------------
A list is a heterogenous, forward-linked data structure that
consists of a head (also called "car part") and tail (also
called "cdr part"). The external representation of a list is
(x1 x2 ... xN)
where the X's are the elements of the list. List elements can
only be extracted and removed from the head of a list:
(car '(1 2 3)) => 1
(cdr '(1 2 3)) => (2 3)
There are also functions for accessing random elements of a
list, concatenating lists, etc, but note that all these
functions are based on the above CAR and CDR operations.
Hence all list operations have linear time complexity.
The empty list () is a synonym for NIL.
Non-empty list objects have to be quoted in expressions in order
to distinguish them from function applications and special forms.
E.g.
(cons 1 2) ; is the application of CONS to 1 and 2
'(cons 1 2) ; is a list containing CONS, 1, and 2
Examples:
() => nil
'(foo bar baz) => (foo bar baz)
(cons (- 2 1) nil) => (1)
(list 1 2 (+ 1 2)) => (1 2 3)
-- PAIRS -------------------------------------------------------
A (dotted) "pair" is an ordered pair of the form (A . B) where A
is called the CAR and B the CDR part of the pair. A fresh pair
is created by the CONS function and its respective parts are
extracted by the CAR and CDR functions. The following equations
hold (where = indicates EQUAL):
(car (cons x y)) = x
(cdr (cons x y)) = y
(cons (car z) (cdr z)) = z ; given that Z is a pair
A "list" is either the empty list NIL or a pair whose CDR part
is another list. Note that this definition is recursive, so
(A . NIL)
(B . (A . NIL))
(C . (B . (A . NIL)))
etc
are all lists. A list of the form (A . list) is normally written
as (A list). Hence
(A . NIL) = (A)
(B . (A . NIL)) = (B . (A)) = (B A)
(C . (B . (A . NIL))) = (C . (B . (A))) = (C . (B A)) = (C B A)
A "dotted list" is a list whose rightmost element is not NIL. It
is a generalization of the dotted pair. E.g.:
(D C B . A)
(B C . A)
(B . A)
Examples:
'(a . b) => (a . b)
(cons 'a 'b) => (a . b)
(cons 'a (cons 'b nil)) => (a b)
(cons 'a '(b c)) => (a b c)
(cons 'a '(b . c)) => (a b . c)
(cons '(a) '(b c)) => ((a) b c)
-- ASSOCIATION LISTS -------------------------------------------
-- A-LISTS -----------------------------------------------------
An association list (or A-list) is a list of pairs:
((<key1> . <value1>) (<key2> . <value2>) ...)
where the car part of each pair is a key associated with a
value, which is stored in the CDR part of the same key. Hence
A-lists implement a very simple (and O(n)) form of associative
storage. Value are retrieved from them using the ASSOC, ASSV,
and ASSQ functions
Examples:
'((a . 1) (b . 2) (c . 3))
'(("I" . 1) ("V" . 5) ("X" . 10) ("L" . 50) ("C" . 100)
("D" . 500) ("M" . 1000))
-- VECTORS -----------------------------------------------------
A vector is a one-dimensional heterogenous array of fixed size.
Elements of a vector can be accessed via their index (position)
within the vector. The external representation of a vector is
#(x1 x2 ... xN)
where the X's are the elements of the vector. Vector elements
can be retrieved using the VREF function and changed by VSET.
There are more functions for for manipulating vectors, which
will be explained in the section about vector functions.
Vector literals are self-quoting and immutable.
Examples:
#(foo 123 "bar") => #(foo 123 "bar")
(vector 1 2 (+ 1 2)) => #(1 2 3)
-- STRINGS -----------------------------------------------------
A string is a one-dimensional homogeneous array of characters.
It has a fixed size. Individual chars of a string can be
accessed via their index (position) within the string. The
external representation of a string is
"<char>..."
where the <char> indicates any ASCII character. Chars can be
retrieved using the SREF function and changed by SSET. There
are more functions for for manipulating strings, which will be
explained in the section about string functions.
To include a quote character (") in a string, it has to be
prefixed with a backslash (\\). A backslash can be included by
prefixing it with another backslash. Any 8-bit value can be
included in a string using the notation \O, where O is an octal
number of three places at most. Furthermore, the following
abbreviations exist:
Abbr. Octal ASCII
\t \11 horizontal tabulator
\n newline sequence, CR, LF, or CRLF
The three-digit limit on \O codes exists in order to distinguish
character sequences from digit characters. For instance, "\123"
denotes the character #\S, but "\0123" denotes a newline char
(\012) followed by the digit "3".
String literals are self-quoting and immutable.
Examples:
; contains the characters
"hello" => "hello" ; h e l l o
"\"foo\"" => "\"foo\"" ; " f o o "
"a\\b" => "a\\b" ; a \ b
"0\0121" => "0\n1" ; 0 <newline> 1
"0\121" => "0Q" ; 0 Q
"\33[H" => "\33[H" ; <ESC> [ H
-- FIXNUMS -----------------------------------------------------
A fixnum is a small integer number. Its range depends on the
implementation, but on a two's complement 32-bit machine it
extends from -2^31 to 2^31-1 (-2,147,483,648 to 2,147,483,647).
The external representation of a fixnum object consists of the
decimal digits of the fixnum with an optional sign (+ or -)
attached. Optionally, it may be prefixed with #<radix>r,
specifying a base different than ten for reading the fixnum.
<Radix> must be in the range from 2 to 36. For instance,
#16rfff => 4095 ; hexa-decimal
#2r101010 => 42 ; binary
#8r177 => 127 ; octal
Examples:
0 => 0
-1 => -1
+123 => 123
0099 => 99
#8r+20 => 16
#36r-z => -35
-- CHARS -------------------------------------------------------
A char is a small integer representing a code point in the
extended ASCII alphabet (where no particular glyphs are
associated with the values 127 to 255).
The external representation is
#\<charname>
where the <charname> can be any of the following:
- a printable ASCII character, representing itself
- \O, where O is an octal number representing the
corresponding code point
Furthermore, the following abbreviated <charname>'s exist:
Abbr. Octal ASCII
#\ht #\\11 HT, horizontal tab
#\nl #\\12 LF (newline)
#\sp #\\40 space
Char literals are self-quoting.
Examples:
#\a => #\a
#\A => #\A
#\\40 => #\sp
#\sp => #\sp
** BINDING FORMS ***********************************************
-- (DEF <VAR> EXPR) => UNSPECIFIC ------------------------------
Bind the value of EXPR to the variable <VAR>. DEF forms must
only appear in the following contexts:
- at the top level of a program
- in a PROG form that appears at the top level of a program
- at the beginning of the body of DEFUN
Examples:
(def foo 'bar)
(def 2^16 (expt 2 16))
(def square (lambda (x) (* x x)))
-- (DEFUN (<VAR> . <FORMALS>) EXPR1 EXPR2 ...) => UNSPECIFIC ---
The DEFUN form is an abbreviation for
(def <var> (lambda <formals> expr1 expr2 ...))
where <formals> is a formal argument list as specified in the
FORMAL SYNTAX section. Note that the dot in the above form only
serves to formalize the equivalence between DEF and DEFUN. You
would normally write
(defun (foo . (x y)) (bar x y))
as
(defun (foo x y) (bar x y))
although the former would also work.
The body of a function defined by DEFUN may contain nested
applications of DEF and DEFUN at its beginning. Such nested
occurrences will be translated to LABELS (q.v.).
Examples:
(defun (square x) (* x x))
(defun (compose f g) (lambda (x) (f (g x))))
(defun (sqsum . x) (fold + 0 (mapcar square x)))
(defun (length a)
(defun (length2 a n)
(if (null a)
n
(length2 (cdr a) (+ 1 n))))
(length2 a 0))
-- (LET ((<VAR1> <ARG1>) ...) EXPR1 EXPR2 ...) => OBJ ----------
Evaluate all arguments <ARGi> and then bind each argument to its
corresponding variable <VARi>. With these bindings in effect,
evaluate the given expressions EXPRi from the left to the right.
Return the value of the last EXPR. When LET has returned its
value, the bindings will no longer be in effect.
The last EXPR in LET is a tail position.
Formally,
(let ((v1 a1) (v2 a2) ...) x)
is equal to
((lambda (v1 v2 ...) x) a1 a2 ...)
Because of this equivalence, all variables <VARi> of LET must be
different. Because all <ARGi>s are evaluated before binding them
to their variables, arguments of LET cannot refer to variables
of LET. In cases where either of these restriction is not
acceptable, LET* should be used instead.
Examples:
(let ((a 1) (b 2)) (+ a b)) => 3
(let ((x 'foo)) (let ((x 'bar)) x)) = > bar
-- (LET* ((<VAR1> <ARG1>) ...) EXPR1 EXPR2 ...) => OBJ ---------
Evaluate the first argument <ARG1> and bind it to the variable
<VAR1>. With this binding in effect, evaluate <ARG2> and bind it
to the variable <VAR2>. Proceed until all variables are bound to
arguments. With all of the above bindings in effect, evaluate
the given expressions and return the value of the last EXPR.
LET* differs from LET in two points:
- each argument <ARGi> can refer to any variable <VARj>
given that j<i
- The <VAR>s do not have to be different
Therefore LET* can be used to write expressions that evaluate
like procedural programs, by evaluating the left to the right,
assigning a value to a variable in each step.
The last EXPR in LET* is a tail position.
Examples:
(let* ((x nil)
(x (cons 'c x))
(x (cons 'b x)))
(cons 'a x)) => (a b c)
(let* ((s "*foobar*")
(k (ssize s))
(k (- k 1))
(s (substr s 1 k)))
s) => "foobar"
-- (LABELS ((<VAR1> <ARG1>) ...) EXPR1 EXPR2 ...) => OBJ -------
Bind each given <VARi> to an unspecific value and with these
bindings in effect, evaluate each argument <ARGi> and bind it
to its corresponding variable <VARi>. Arguments will be
evaluated and bound from the left to the right, so each
argument <ARGi> can refer to any <VARj> as long as j<i. The
following program is valid and evaluates to B:
(labels
((compose (lambda (f g) (lambda (x) (f (g x)))))
(kadr (compose car cdr)))
(kadr '(a b c)))
Hence LABELS is a cross between Scheme's LETREC and LET* and
equal to what is sometimes referred to as LETREC*. This is
particularly interesting because nested DEF and DEFUN translate
to LABELS, so the following function would also be valid and
evaluate to "foobar":
| ; Expanded form:
(defun (foobar) | (defun (foobar)
(def x "foo") | (labels
(def y (sconc x "bar")) | ((x "foo")
y) | (y (sconc x "bar")))
| y))
Because LABELS binds values to variables in a context where
variable bindings are already established, it can define
functions that are mutually recursive. In this way it can be
though of a creating a local "top-level". Each function <ARGi>
defined by LABELS can refer to all <VARj> defined by the same
LABELS form without any restrictions.
The last EXPR in LABELS is a tail position.
Examples:
(labels
((pow (lambda (x y)
(if (= 0 y)
1
(* x (pow x (- y 1)))))))
(pow 2 9)) => 512
(labels
((even (lambda (n)
(if (= 0 n) t (odd (- n 1)))))
(odd (lambda (n)
(if (= 0 n) nil (even (- n 1))))))
(list (even 5) (odd 5))) => (nil t)
-- (WITH ((<VAR1> <ARG1>) ...) EXPR1 EXPR2 ...) => OBJ ---------
Save the values of all <VAR>'s in temporary locations. Then
evaluate arguments <ARGi> sequentially, like LET*, but rather
than binding their values to new variables, alter pre-existing
variables using SETQ. With the modified bindings in effect,
evaluated the <EXPR>'s. Before returning the value of the last
expression, restore the original values of the <VAR>'s from the
temporary locations.
The variables <VARi> must exist prior to evaluating WITH.
WITH implements what is widely known as "dynamic scoping", i.e.
the WITH form alters the value of existing variables inside of
its dynamic extent:
(let ((a 'lexical))
(let ((f (lambda () a)))
(with ((a 'dynamic))
(f)))) => dynamic
Replacing the WITH in the above program by LET would result in
"lexical scoping", which is the default.
Examples:
(def *barchar* #\#)
(defun (plotbar n)
(cond ((> n 0)
(writec *barchar*)
(plotbar (- n 1)))))
(plotbar 10) ; prints ##########
(with ((*barchar* #\:))
(plotbar 10)) ; prints ::::::::::
** FUNCTIONS AND FUNCTION APPLICATION **************************
-- (LAMBDA <FORMALS> EXPR1 ... EXPRn) => FUN -------------------
Create a function expecting the given formal arguments and
returning the value of EXPRn. <FORMALS> can be
- a list of variables
- a dotted list of variables
- a single variable
In the first case, when applying the function to some arguments,
there must be exactly one argument per variable and variables
will be bound to arguments pairwise. The list may be empty,
creating a function of no variables.
When <FORMALS> is a single variable, all arguments passed to the
function will be collected in a list and bound to that variable.
A dotted argument list is a cross between the above. First all
variables to the left of the dot will be bound to individual
arguments and then any remaining arguments will be collected in
a list and bound to the last variable.
The expressions EXPR1 ... EXPRn-1 are evaluated for effect from
the left to the right (i.e., the body of a function is an
implied PROG form). Only the value of EXPRn will be returned.
Examples:
(lambda (x y) (- y x))
(lambda (x . y)
(apply princ x y)
(apply terpri y)
x)
(lambda x x)
-- APPLICATION -------------------------------------------------
-- (EXPR1 ...) => OBJ ------------------------------------------
Apply the function EXPR1 to some arguments and evaluate to the
value returned by that function. The number of expressions
passed to the function must match its number of formal arguments
(variables). See LAMBDA for details.
Examples:
((lambda (x) x) 1) => 1
((lambda (x y z)
(list x y z)) 'a 'b 'c) => (a b c)
((lambda () 'foo 'bar)) => bar
((lambda (x . y) y) 1 2 3)) => (2 3)
-- (APPLY EXPR1 EXPR2 ... EXPRn) => OBJ ------------------------
Apply the function EXPR1 to the arguments in EXPRn. EXPRn must
be a list. I.e.
(apply f x) == (f . x)
Note that EXPRn will be evaluated before applying APPLY, but the
arguments of EXPR1 will not be evaluated, so
(apply cons '(a b)) => (a . b)
although A and B are not individually quoted.
When there are any expressions EXPR2 ... EXPRn-1 between the
function and its arguments, they will be consed to EXPRn before
applying EXPR1, i.e.:
(apply princ x (list (errport)))
== (apply princ (cons x (list (errport))))
Examples:
(apply cons '(a (b))) => (a b)
(apply mapcar list '((1 2 3) (4 5 6))) => ((1 4) (2 5) (3 6))
(apply list 1 2 3 '(4 5)) => (1 2 3 4 5)
** CONDITIONAL EVALUATION **************************************
-- (AND EXPR1 ...) => OBJ -------------------------------------
-- (OR EXPR1 ...) => OBJ -------------------------------------
-- (PROG EXPR1 ...) => OBJ -------------------------------------
All of these forms evaluate their expressions from the left to
the right. PROG evaluates all of them and returns the value of
the last expression. The value of (PROG) is NIL.
AND evaluates expressions until one of them evaluates to NIL.
In this case it does not evaluate any subsequent expressions
and returns NIL immediately. When all expressions evaluate to
non-NIL values, it returns the value of the last expression.
AND implements the short-circuit logical "and". (AND) evaluates
to T, the neutral element of the and operation.
OR evaluates expressions until one of them evaluates to a
non-NIL value. In this case, it returns that value immediately
and does not evaluate any subsequent expressions. When all
expressions evaluate to NIL, it returns NIL. OR implements the
short-circuit logical "or". (OR) evaluates to NIL, the neutral
element of the "or" operation.
The last expression in each of these special forms is a tail
position.
Examples:
(and 1 2 3) => 3
(or 1 2 3) => 1
(prog 1 2 3) => 3
(and nil (div 1 0)) => nil
(or t (div 1 0)) => t
(let ((x #\5))
(or (c<= #\0 x #\9)
(c<= #\a x #\f))) => t
(let ((x '(a b c)))
(and (pair x)
(pair (cdr x))
(cadr x))) => b
-- (IF EXPR1 EXPR2 EXPR3) => OBJ -------------------------------
-- (IF EXPR1 EXPR2) => OBJ -------------------------------
First evaluate EXPR1. When the value of EXPR1 is not NIL,
evaluate EXPR2 and return its value. When EXPR1 is NIL and a
third expression is given, evaluate that expression and
return its value. When EXPR1 is NIL and no EXPR3 is present,
return NIL.
If EXPR1 is true (not NIL), EXPR3 (if present) will never be
evaluated. If EXPR1 is NIL, EXPR2 will never be evaluated.
Examples:
(if t 'yes 'no) => yes
(if nil 'yes 'no) => no
(if nil 'yes) => nil
(if nil (div 1 0)) => nil
-- (IF* EXPR1 EXPR2) => OBJ ------------------------------------
First evaluate EXPR1. When EXPR1 is not NIL, return its value.
When EXPR1 is NIL, evaluate EXPR2 and return its value. When
EXPR1 is not NIL, EXPR2 will never be evaluates. EXPR1 will
only be evaluated once. Formally,
(if* a b)
is equivalent to
(let ((g a)) (if g g b))
Rationale: IF* is trivial to implement and useful for
implementing derived forms, such as OR and COND. The
relationship between IF and IF* becomes obvious in the
following disassembled code:
; (if 1 2) ; (if* 1 2)
0 (quote 1) 0 (quote 1) ; load A with 1
2 (brf 6) 2 (brt 6) ; branch on false / true
4 (quote 2) 4 (quote 2) ; load A with 2
6 6 ; result in A
Examples:
(if* 1 2) => 1
(if* nil 2) => 2
(if* (memq 'c '(a b c d e f)) 'no) => (c d e f)
-- (COND <CLAUSE> ...) => OBJ ----------------------------------
Each <clause> has one of the following forms:
(<predicate> EXPR1 EXPR2 ...)
(<predicate>)
(<predicate> => FUN^1)
The COND form first evaluates the predicate of the first clause.
When it evaluates to a non-NIL value, the rest of the clause
will be evaluated and otherwise the next clause will be tried.
When COND runs out of clauses, it will return an unspecific
value.
The evaluation of the rest of a clause depend on the shape of
the clause. When there are some expressions following the
predicate, they will be evaluated from the left to the right
(like in PROG) and the value of the last of them will be
returned.
When there is only a predicate in the clause, the value of the
predicate will be returned.
When the second member of the clause is a double right arrow,
the third member must be a function of one argument. That
function will be applied to the predicate and the value of the
function will be the value of the entire COND form.
In either of the three cases, no more clauses will be evaluated
after finding one with a true (non-NIL) predicate.
The last clause of COND may have the form ELSE, introducing a
catch-all clause whose predicate is always true.
The last expression in every clause of COND is a tail position.
This does not apply to predicate-only clauses, though.
position.
Examples:
(cond (t 1) (t 2)) => 1
(cond (nil 1) (t 2)) => 2
(let ((c #\*))
(cond ((c<= #\0 c #\0) 'digit)
((c<= #\a c #\z) 'letter)
(else 'unknown))) => unknown
(cond ('true)) => true
(cond ((assq 'b '((a 1) (b 2) (c 3))) => cdr)) => (2)
-- (CASE <KEY> <CLAUSE> ...) => OBJ ----------------------------
Each <clause> has the following form:
((<member> ...) EXPR1 ...)
First the <key> is evaluated, which must be an expression that
evaluates to T, nil, a symbol, a number, or a character. The
value of <key> is then compared to each member of the first
<clause> (using MEMV). When <key> is contained in the list of
members, the corresponding EXPRs will be evaluated and the value
of the last expression is returned. Otherwise CASE will continue
to test clauses from the left. When no clause has <key> as a
member, CASE will return an unspecific result.
<Key> is only evaluated once, so
(case (print 'FOO) ((a)) ((b)) ((c)))
will only print FOO once.
The last <clause> may have the keyword ELSE in the place of its
member list. In this case, the expressions of that clause will
be evaluated when no other clause matches.
The last expression in every clause of CASE is a tail position.
Examples:
(case 'b ((a) 1) ((b) 2) ((c) 3)) => 2
(case 5
((0 2 4 6 8) 'even)
((1 3 5 7 9) 'odd)
(else 'not-a-digit)) => odd
** LOOPS ******************************************************
-- (DO <BINDINGS> (<TEST> EXPR1 ...) <BODY>) => OBJ ------------
<Bindings> is similar to the bindings of LET, but each clause
has an optional third argument, so it may have the following
forms:
((<var1> <arg1>) ...)
((<var1> <arg1> <update1>) ...)
DO implements a loop, <TEST> is the exit condition of the loop,
and <BODY> is a set of expressions that will be evaluated in
each iteration of the loop.
DO first evaluates all <arg>'s and binds the resulting values to
the corresponding variables, just like LET. With these bindings
in effect, it evaluates <TEST>. When the value of <TEST> is NIL,
it evaluates the expressions following <TEST> from the left to
the right and returns the value of the last of them.
When <TEST> evaluates to NIL, <BODY> is evaluated. <BODY> is a
sequence of expressions that will evaluated from the left to
the right. After evaluating the expressions, all <update>'s will
be evaluates and their values will be bound to the corresponding
<var>'s. With these bindings in effect, DO will start over with
evaluating <TEST>.
<Update> is often used to increment or decrement a numeric value
or collect values in a list, but in fact <update> can be any
expression, it does not even have to reference the corresponding
variable.
The last expression in <BODY> is a tail position.
Examples:
(do ((i 32 (+ 1 i)))
((= 127 i) (terpri))
(writec (char i))) ; writes the ASCII alphabet
(do ((i 10 (- i 1))
(a nil (cons i a)))
((= 0 i) a)) => (1 2 3 4 5 6 7 8 9 10)
(do () (nil)) ; never terminates
-- (LET <NAME> ((<VAR1> <ARG1>) ...) EXPR1 EXPR2 ...) => OBJ ---
The "named LET" is a very general loop construct. It binds its
variables to arguments in the same was as LET does, but instead
of evaluating its body immediately, it creates a function <NAME>
with all <VAR>s as variables and (PROG EXPR1 EXPR2 ...) as its
body. It then applies this function to the given <ARG>s.
As long as no EXPR applies <NAME>, named LET behaves in the same
way as LET, but when <NAME> is applied to some values in the
body of named LET, then the body of named LET will be reentered
with the new values as arguments. The loop is exited by just
evaluating to a value (and not applying <NAME>).
The last EXPR in LET is a tail position.
Examples:
(let loop ((i 0))
(cond ((= 127 i) (terpri))
(else
(writec (char i))
(loop (+ 1 i))))) ; writes the ASCII alphabet
(let loop ((a '(1 2 3 4 5))
(e nil))
(cond ((null a) e)
((evenp (car a))
(loop (cdr a)
(cons (car a) e)))
(else
(loop (cdr a) e)))) => (4 2)
** QUOTATION ***************************************************
-- (QUOTE EXPR) => OBJ -----------------------------------------
Return EXPR without evaluating it. The form (quote expr) may be
abbreviated as
'expr
List and vector structures returned by QUOTE will be immutable,
so modifying them with SSET, SETCAR, VFILL, etc, will result
in an error.
Applying QUOTE to a self-quoting object will not add another
level of quotation, e.g. (quote 123) is the same as 123.
However, (quote (quote 123)) will yield (quote 123).
Example:
'foo => foo
''foo => 'foo
'(1 2 3) => (1 2 3)
'(cons a b) => (cons a b)
-- (QQUOTE <TEMPLATE>) => OBJ ----------------------------------
-- (UNQUOTE EXPR) ----------------------------------------------
-- (SPLICE EXPR) -----------------------------------------------
QQUOTE ("quasi-quote") creates an (often nested) list or vector
structure from a template. The QUOTE, UNQUOTE, and SPLICE forms
can be abbreviated as follows:
`x == (qquote x) ; ` is a backtick (ASCII 96) character
@x == (qquote x)
,x == (nqquote x)
,@x == (splice x)
When the template is just an ordinary list or vector, QQUOTE
is similar to QUOTE, but the resulting object will be mutable.
E.g.
(setcdr @(1 . 0) 2) => (1 . 2)
The <template> may contain applications of the UNQUOTE or SPLICE
special forms, which can be used to insert dynamic values into
otherwise static structures. (Unquote expr) "unquotes" the given
expression and inserts its value, rather than its lexical form,
into the resulting structure. For instance:
@(1 ,(+ 1 1) 3) => (1 2 3)
(Splice expr) also unquotes the given expression, but splices it
into the surrounding structure:
@(1 ,(list 2 3) 4) => (1 (2 3) 4)
@(1 ,@(list 2 3) 4) => (1 2 3 4)
Generally, the following equations hold:
@x == 'x
@,x == x
@(x) == (cons 'x nil)
@(,x) == (cons x nil)
@(,@x) == (conc x nil) ; Note: CONC instead of CONS
The following combinations of QQUOTE and SPLICE are undefined:
(qquote ((splice atom))) ; splicing a non-list into a list
(qquote (splice expr)) ; splicing something into a non-list
When a <template> is (or contains) a vector rather than a list,
the vector will be built in the same way as a list and only
subsequently concerted to a vector:
@#(1 ,(+ 1 1)) == (listvec (cons 1 (cons (+ 1 1) nil)))
QQUOTE is often used to create LISP forms inside of macros.
Examples:
@(5 * 7 = ,(* 5 7)) => (5 * 7 = 35)
@#(a ,@(list 'b 'c) d) => #(a b c d)
(let ((p '(= 1 1))
(x '((prog
(princ "true")
(terpri)))))
@(if ,p ,@x)) => (if (= 1 1)
(prog (princ "true")
(terpri)))
** LIST FUNCTIONS **********************************************
-- (ASSOC EXPR ALIST) => PAIR ----------------------------------
-- (ASSQ EXPR ALIST) => PAIR ----------------------------------
-- (ASSV EXPR ALIST) => PAIR ----------------------------------
Search the given ALIST sequentially, from left to right, for a
member with EXPR in its car field. When such a member exists,
return it, otherwise return NIL.
ASSOC uses EQUAL to identify members, ASSV uses EQV, and ASSQ
uses EQ.
Examples:
(assoc '(3 4) '(((1 2)) ((3 4)) ((5 6)))) => ((3 4))
(assv 2 '((1 foo) (2 bar) (3 baz))) => (2 bar)
(assq 'b '((a 1) (b 2) (c 3))) => (b 2)
(assq 'x '((a 1) (b 2) (c 3))) => nil
-- (ATOM EXPR) => T/NIL ----------------------------------------
Return T, ifthe given EXPR is an atom (i.e.: not a list).
Examples:
(atom nil) => t
(atom 123) => t
(atom #(1 2 3)) => t
(atom '(1)) => nil
-- (CAAR PAIR) => OBJ ----------------------------------------
-- (CDDDDR PAIR) => OBJ ----------------------------------------
Return a member of a nested list (pair, in fact) by repeatedly
applying CAR and CDR to the list. The letters between the 'C'
and the 'R' of the function names indicate the operations CAR
and CDR, respectively. For instance,
(caddr x) equals (car (cdr (cdr x)))
The functions CADR, CADDR, and CADDDR are used pretty frequently.
They extract the first, second, and third member of a list.
Analogously, CDDR, CDDDR, and CDDDDR return the corresponding
tails of a list.
Examples:
(caar '((a b) (c d))) => a
(cadr '((a b) (c d))) => (c d)
(cdar '((a b) (c d))) => (b)
(cddr '((a b) (c d))) => nil
(cadar '((a b) (c d))) => b
-- (CAR PAIR) => OBJ -------------------------------------------
-- (CDR PAIR) => OBJ -------------------------------------------
CAR extracts the car part and CDR extracts the CDR part of a
pair. The application of CAR or CDR to NIL is an error.
Examples:
(car '(a . b)) => a
(cdr '(a . b)) => b
(car '(a b c)) => a
(cdr '(a b c)) => (b c)
-- (CONC LIST ... EXPR) => DLIST ------------------------------
-- (NCONC LIST ... EXPR) => DLIST ------------------------------
Concatenate lists: return a list that contains the elements of
the first LIST argument followed by the elements of the second
argument, etc. The last list to be appended may be a dotted
list.
CONC returns a fresh list while NCONC may modify its arguments
in situ. Hence CONC can work on constant (quoted) lists, which
NCONC cannot (the OBJ argument may in fact be immutable).
When no arguments are passed to these functions, both of them
return NIL.
Examples:
(conc '(1 2 3) '(4 5 6)) => (1 2 3 4 5 6)
(conc '(1 2 3) 4) => (1 2 3 . 4)
(conc nil '(a b) nil) => (a b)
(conc '(a) '(b c) '(d)) => (a b c d)
(nconc (list 1 2 3) '(4 5 6)) => (1 2 3 4 5 6)
(nconc) => nil
-- (CONS EXPR1 EXPR2) => PAIR ----------------------------------
Create a fresh pair with EXPR1 in its car and EXPR2 in its cdr
part. The pair is guaranteed to be different from all pairs
created before or after it, so EQ can be used to identify it.
I.e.:
(eq (cons 'a 'b) (cons 'a 'b)) => nil
Examples:
(cons 'a 'b) => (a . b)
(cons 'a '(b c)) => (a b c)
(cons "foo" "bar") => ("foo" . "bar")
-- (FILTER FUN^1 LIST) => LIST ---------------------------------
Return a fresh list containing those elements X of LIST that
satisfy the predicate P, i.e. for which (P X) => T.
Examples:
(filter (lambda (x) t) '(a b c)) => (a b c)
(filter oddp '(1 2 3 4 5)) => (1 3 5)
-- (FOLD FUN^2 EXPR LIST) => OBJ ------------------------------
-- (FOLDR FUN^2 EXPR LIST) => OBJ ------------------------------
Fold function FUN^2 over the given list and return the result.
EXPR is the neutral element or base element of FUN. "Folding"
a function FUN over a list means to combine two elements of the
list by applying FUN to them and then combine the (intermediate)
result with the next element, etc. FOLD folds elements
left-associatively and FOLDR combines them right-associatively.
Formally,
(fold f 0 '(a1 ... aN)) == (f ... (f (f 0 a1) a2) ... aN)
(foldr f 0 '(a1 ... aN)) == (f a1 (f a2 ... (f aN 0) ...))
Examples:
(fold cons 0 '(a b c)) => (((0 . a) . b) . c)
(foldr cons 0 '(a b c)) => (a b c . 0)
(fold * 1 '(1 2 3 4)) => 24 ; (((1 * 2) * 3) * 4)
(foldr - 0 '(1 2 3 4)) => -2 ; (1 - (2 - (3 - 4)))
-- (MAPCAR FUN LIST1 LIST2 ...) => LIST -----------------------
-- (FOREACH FUN LIST1 LIST2 ...) => UNSPECIFIC -----------------
Map fun over the given lists, resulting in a fresh list which
contains the results of applying FUN to the corresponding
elements of the argument lists LIST1, LIST2, etc. Formally,
(mapcar f (a1 ... aN)) == (list (f a1) (f a2) ... (f aN))
and
(mapcar f (a1 ... aN) (b1 ... bN)) == (list (f a1 b1) ...
(f a2 b2)
(f aN bN))
So FUN has to be unary when one list is given, binary, when two
lists are given, etc. Any number of lists may be specified. When
the lengths of the lists differ, MAPCAR will stop mapping as
soon as the shortest list runs out of members.
FOREACH is like MAPCAR, but applies FUN for effect and returns
an unspecific value. Also FOREACH is guaranteed to traverse
its list arguments from the left to the right, which MAPCAR
is not.
Examples:
(mapcar list '(a b c) '(1 2 3)) => ((a 1) (b 2) (c 3))
(mapcar + '(1 2 3) '(4 5 6)) => (5 7 9)
(mapcar list '(a b) '(1 2) '(x y)) => ((a 1 x) (b 2 y))
-- (LENGTH LIST) => FIXNUM -------------------------------------
Return the length of the given list.
Examples:
(length nil) => 0
(length '(a b c)) => 3
-- (LIST EXPR ...) => LIST -------------------------------------
Create a fresh list from the given arguments. The list is
guaranteed to be unique. See CONS.
Examples:
(list) => nil
(list 'a (+ 1 2) "foo") => (a 3 "foo")
-- (LISTP EXPR) => T/NIL ---------------------------------------
Return T, if the given argument is a (non-dotted) list. When
EXPR is a dotted list, a graph (a cyclic list) or not a list
at all, return NIL.
LISTP need O(n) time to check its argument. In order to find
out whether a given EXPR is any list type at all, use
(or (pair EXPR) (null EXPR))
Examples:
(listp nil) => t
(listp '(1 2 3)) => t
(listp '(1 2 . 3)) => nil
(let ((x (list 1)))
(setcdr x x)
(listp x)) => nil
-- (MEMBER EXPR LIST) => LIST ----------------------------------
-- (MEMQ EXPR LIST) => LIST ----------------------------------
-- (MEMV EXPR LIST) => LIST ----------------------------------
Search the given LIST sequentially, from left to right, for a
member that is equal to EXPR. When such a member exists, return
the tail of LIST that starts with that member. Return NIL if
no such member exists.
MEMBER uses EQUAL to identify members, MEMV uses EQV, and MEMQ
uses EQ.
Examples:
(member '(3 4) '((1 2) (3 4) (5 6))) => ((3 4) (5 6))
(memv 3 '(1 2 3 4 5)) => (3 4 5)
(memq 'b '(a b c d e f)) => (b c d e f)
(memq 'x '(a b c d e f)) => nil
-- (NTH FIXNUM LIST) => OBJ ------------------------------
-- (NTH-TAIL FIXNUM DLIST) => OBJ ------------------------------
NTH returns the N'th member of the given list, and NTH-TAIL
returns the tail of LIST that begins after the N-1'st member.
The first element is at position 0. Hence FIXNUM must be less
than the length of the list in NTH and not greater than the
length of the list in NTH-TAIL.
Examples:
(nth 0 '(a b c)) => a
(nth 2 '(a b c)) => c
(nth-tail 1 '(a b c)) => (b c)
(nth-tail 2 '(a b c)) => (c)
(nth-tail 3 '(a b c)) => nil
-- (NULL EXPR) => T/NIL ----------------------------------------
Return T, if the given EXPR is NIL. Although this function is
extensionally equal to NOT, its application is different: it
is used to test whether EXPR denotes the end of a LIST.
Examples:
(null 'foo) => nil
(null '(foo)) => nil
(null (cdr '(foo))) => t
-- (RECONC LIST EXPR) => DLIST --------------------------------
-- (NRECONC LIST EXPR) => DLIST --------------------------------
Reverse LIST and concatenate it to EXPR. Formally,
(reconc a b) == (nconc (reverse a) b)
RECONC creates a fresh list while NRECONC may modify the given
list in situ. Hence RECONC can operate on immutable lists, which
NRECONC cannot do. NRECONC does not allocate any cons cells.
Examples:
(reconc '(c b a) '(d e f)) => (a b c d e f)
(reconc '(c b a) 'd) => (a b c . d)
(nreconc (list 3 2 1) '(4 5 6)) => (1 2 3 4 5 6)
-- (REVER LIST) => LIST ---------------------------------------
-- (NREVER LIST) => LIST ---------------------------------------
Return LIST with its elements in reverse order. REVER creates a
fresh list while NREVER modifies the given list in situ. Hence
REVER can reverse immutable lists, which NREVER cannot do.
Note that the effect of NREVER on a list bound to a variable may
be unexpected:
(let ((a (list 'a 'b 'c)))
(nrever a)
a) => (a)
Hence the variable should always be updated with the value
returned by NREVER:
(let ((a (list 'a 'b 'c)))
(setq a (nrever a))
a) => (c b a)
REVER is called REVER, because "rever" is the REVER of "rever".
Examples:
(rever nil) => nil
(rever '(1 2 3)) => (3 2 1)
(nrever (list 1 2 3)) => (3 2 1)
** MUTATION ****************************************************
-- (SETQ <VAR> EXPR) => OBJ ------------------------------------
Set the variable <VAR> to the value of EXPR. The variable must
have been defined before, either be DEF or LAMBDA or one of
their derived forms.
Examples:
(prog (def foo 'zzz)
(setq foo 'bar)
foo) => bar
-- (SETCAR PAIR EXPR) => PAIR ----------------------------------
-- (SETCDR PAIR EXPR) => PAIR ----------------------------------
Replace the car/cdr part of the given pair by EXPR. No new pair
will be allocated, the existing one will be modified in situ. The
pair must be mutable. SETCAR replaces the car part and SETCDR
replaces the cdr part of a pair. Both functions return the new
pair.
Note that SETCAR and SETCDR can be used to create cyclic
structures.
Examples:
(setcar (list 'f 'o 'o) 'g) => (g o o)
(setcdr (cons 1 nil) '(2 3 4 5)) => (1 2 3 4 5)
(let ((x (list 1)))
(setcdr x x)) => (1 1 1 ...) ; will print forever
** EQUIVALENCE *************************************************
-- (EQ EXPR1 EXPR2) => T/NIL -----------------------------------
Return T, if EXPR1 and EXPR2 are the same object. This is the
case, if
- EXPR1 and EXPR2 are both T
- EXPR1 and EXPR2 are both NIL
- EXPR1 and EXPR2 are the same symbol
- EXPR1 and EXPR2 are the same function
- EXPR1 and EXPR2 have been returned by the same function
application
EQ evaluates to NIL, if its arguments have different types.
EQ is guaranteed to evaluate to NIL when applied to the values
of two different applications of CONS, even when applied to the
same arguments. See CONS.
An applications of EQ to pairs (and hence lists), chars, strings,
and vectors is undefined. The case
(eq (lambda (x) x) (lambda (x) x))
is undefined.
Examples:
(eq nil nil) => t
(eq 'foo 'foo) => t
(eq 'foo 'bar) => nil
(eq 'foo 17) => nil
(eq car car) => t
(let ((x (cons 'x nil)))
(eq x x)) => t
(eq (cons 'x nil)
(cons 'x nil)) => nil
-- (EQV EXPR1 EXPR2) => T/NIL ----------------------------------
Return T, if EXPR1 and EXPR2 have the same value. This is the
case, if
- EXPR1 and EXPR2 are both fixnums and have the same value
- EXPR1 and EXPR2 are both chars and denote the same character
- EXPR1 and EXPR2 are the same object in the sense of EQ
EQV evaluates to NIL, if its arguments have different types.
An application of EQV to pairs (and hence lists) and vectors is
undefined.
Examples:
(eqv 1 1) => t
(eqv 1 2) => nil
(eqv #\a #\a) => t
(eqv #\a #\b) => nil
(eqv 27 "test") => nil
(eqv eqv eqv) => t
-- (EQUAL EXPR1 EXPR2) => T/NIL --------------------------------
Return T, if EXPR1 and EXPR2 are structurally equal. This is the
case, if
- Both EXPR1 and EXPR2 are pairs and their car and cdr
parts are equal in the sense of EQUAL
- Both EXPR1 and EXPR2 are vectors of equal length and
their elements are pairwise equal in the sense of EQUAL
- Both EXPR1 and EXPR2 are strings that are equal in the
sense of S=
- EXPR1 and EXPR2 are equivalent in the sense of EQV
Informally, EQUAL returns T for two objects, if those objects
look the same when printed by PRIN.
Examples:
(equal '(1 (2) 3) '(1 (2) 3)) => t
(equal '(1 (2) 3) '(1 (X) 3)) => nil
(equal "foo" "foo") => t
(equal #(a (b) c) #(a (b) c)) => t
(equal (a #(b) c) (a #(b) c)) => t
** TYPE PREDICATES *********************************************
-- (CHARP EXPR) => T/NIL -------------------------------------
-- (CTAGP EXPR) => T/NIL -------------------------------------
-- (INPORTP X) => T/NIL -------------------------------------
-- (FIXP X) => T/NIL -------------------------------------
-- (FUNP EXPR) => T/NIL -------------------------------------
-- (OUTPORTP X) => T/NIL -------------------------------------
-- (PAIR EXPR) => T/NIL -------------------------------------
-- (STRINGP EXPR) => T/NIL -------------------------------------
-- (SYMBOLP EXPR) => T/NIL -------------------------------------
-- (VECTORP EXPR) => T/NIL -------------------------------------
The type predicates return T, if the argument passed to them
has the corresponding type. For instance, FIXP returns T, if
its argument is a fixnum and SYMBOLP returns T, if its argument
is a symbol.
Note that LIST is not a primitive type, but a concatenation of
pairs, hence LISTP is not a type predicate. Nor is NULL a type
predicate, because NIL is a unique object with no type.
Examples:
(charp #\x) => t
(ctagp (catch (lambda (x) x))) => t
(inportp (inport)) => t
(fixp 123) => t
(funp (lambda (x) x)) => t
(outportp (errport)) => t
(pair '(1 2 3)) => t
(stringp "hello!") => t
(symbolp 'foo) => t
(vectorp #(a b c d e f)) => t
** TYPE CONVERSION *********************************************
-- (CHAR FIXNUM) => CHAR --------------------------------------
-- (CHARVAL CHAR) => FIXNUM ------------------------------------
CHAR return a character with the given code point. The code
point must be given as a fixnum between 0 and 255. CHARVAL
returns the code point of a given character as a fixnum.
Examples:
(char 65) => #\A
(charval #\A) => 65
-- (LISTSTR LIST) => STRING ----------------------------------
-- (STRLIST STRING) => LIST ------------------------------------
LISTSTR returns a fresh string containing the same characters as
the given list, in the same order. STRLIST returns a fresh list
containing the same characters as the given string, in the same
order.
Examples:
(liststr nil) => ""
(liststr '(#\f #\o #\b)) => "fob
(strlist "") => nil
(strlist "fob") => (#\f #\o #\b)
-- (LISTVEC LIST) => VECTOR ----------------------------------
-- (VECLIST VECTOR) => LIST ------------------------------------
LISTVEC returns a fresh vector containing the same objects as
the given list, in the same order. VECLIST returns a fresh list
containing the same objects as the given vector, in the same
order.
(listvec nil) => #()
(listvec '(a b c)) => #(a b c)
(veclist #()) => nil
(veclist #(a b c)) => (a b c)
-- (SYMBOL STRING) => SYMBOL-----------------------------------
-- (SYMNAME SYMBOL) => STRING ----------------------------------
SYMBOL creates a new symbol whose name consists of the
characters given in STRING. Note that SYMBOL can create symbols
that will result in invalid forms when printed and/or cannot be
read by the reader. E.g.:
(symbol ")") ; will create an extra right paren when printed
(symbol "Foo") ; the reader will fold letters to lower case
(symbol "a b") ; the reader will read two symbols
(symbol "@") ; @ is a reserved symbol
(symbol "t") ; T is a special object
SYMNAME returns a string containing the name of the given symbol.
Examples:
(symbol "foo") => foo
(symbol "(don't do this!)") => (don't do this!)
(symname 'FOO) => foo
(symname (symbol "Foo")) => Foo
** ARITHMETIC FUNCTIONS ****************************************
-- (* N1 ...) => FIXNUM ----------------------------------------
Return the product of the given fixnums. When no arguments are
given, return the neutral element of the multiply operation.
(* x) => x for any X.
When the result of the operation does not fit in a fixnum, an
error will be signalled.
Examples:
(*) => 1
(* 5) => 5
(* 2 3 4) => 24
-- (+ N1 ...) => FIXNUM ----------------------------------------
Return the sum of the given fixnums. When no arguments are
given, return the neutral element of the plus operation.
(+ x) => x for any X.
When the result of the operation does not fit in a fixnum, an
error will be signalled.
Examples:
(+) => 0
(+ 5) => 5
(+ 2 3 4) => 9
-- (- N1 N2 ...) => FIXNUM -------------------------------------
Return the different between the given fixnums. When only one
argument is specified, returns its negative value. Note that
on two's complement machines, there may be values that do not
have any negative counterpart. When applying - to such a value,
an error will be signalled.
The - function associates to the left, i.e.
(- a b c) == (- (- a b) c)
When the result of the operation does not fit in a fixnum, an
error will be signalled.
Examples:
(- 5) => -5
(- 3 2) => 1
(- 1 2 3) => -4
-- (= N1 N2 ...) => T/NIL -------------------------------------
-- (< N1 N2 ...) => T/NIL -------------------------------------
-- (> N1 N2 ...) => T/NIL -------------------------------------
-- (<= N1 N2 ...) => T/NIL -------------------------------------
-- (>= N1 N2 ...) => T/NIL -------------------------------------
These predicates return T, if their fixnum arguments are
- equal (=)
- in strictly increasing order (<)
- in strictly decreasing order (>)
- in monotonically increasing order (<=)
- in monotonically decreasing order (>=)
They are trivially true when applied to a single argument.
Examples:
(= 1 1 1) => t
(< 1 2 3) => t
(> 3 2 1) => t
(<= 1 2 2) => t
(>= 3 3 2) => t
(= 0) => t
(< 5) => t
-- (ABS FIXNUM) => FIXNUM --------------------------------------
Return the magnitude of the given fixnum. Note that on two's
complement machines there may exist negative values with a
negative magnitude. When applying ABS to such a value, an error
will be signalled.
Examples:
(abs 5) => 5
(abs -5) => 5
-- (ASRB N1 N2 N3 ...) => FIXNUM -------------------------
-- (BITOP <OP> N1 N2 N3 ...) => FIXNUM -------------------------
-- (ANDB N1 N2 N3 ...) => FIXNUM -------------------------
-- (EQVB N1 N2 N3 ...) => FIXNUM -------------------------
-- (NANDB N1 N2 N3 ...) => FIXNUM -------------------------
-- (NORB N1 N2 N3 ...) => FIXNUM -------------------------
-- (NOTB FIXNUM) => FIXNUM -------------------------
-- (ORB N1 N2 N3 ...) => FIXNUM -------------------------
-- (SHLB N1 N2 N3 ...) => FIXNUM -------------------------
-- (SHRB N1 N2 N3 ...) => FIXNUM -------------------------
-- (XORB N1 N2 N3 ...) => FIXNUM -------------------------
BITOP implements the bitwise operators summarized in the below
table. The operation itself is passed to BITOP in the <OP>
argument, which must also be a fixnum. The remaining fixnums
are combined using the corresponding operator. All operations
associate to the left, e.g.
(bitop 16 1 2 3 4) => 512 ; ((1 shl 2) shl 3) shl 4
The values for <OP> are derived from the following table:
| AB AB AB AB |
Operation | 00 01 10 11 | Op | Notes
-------------------------------------------------------------
0 | 0 0 0 0 | 0 | Aways 0 (Clear)
(ANDB A B) | 0 0 0 1 | 1 | ANDB
(ANDB A (NOTB B)) | 0 0 1 0 | 2 |
A | 0 0 1 1 | 3 |
(ANDB (NOTB A) B) | 0 1 0 0 | 4 |
B | 0 1 0 1 | 5 |
(XORB A B) | 0 1 1 0 | 6 | XORB
(ORB A B) | 0 1 1 1 | 7 | ORB (Inclusive)
(NOTB (ORB A B)) | 1 0 0 0 | 8 | NORB
(NOTB (XORB A B)) | 1 0 0 1 | 9 | EQVB
(NOTB B) | 1 0 1 0 | 10 | NOTB B, A is ignored
(ORB A (NOTB B)) | 1 0 1 1 | 11 |
(NOTB A) | 1 1 0 0 | 12 | NOTB A, B is ignored
(ORB (NOTB A) B)) | 1 1 0 1 | 13 |
(NOTB (ANDB A B)) | 1 1 1 0 | 14 | NANDB
1 | 1 1 1 1 | 15 | Aways 1 (Set)
(SHLB A B) | | 16 | Shift left
(SHRB A B) | | 17 | Shift right
(ASRB A B) | | 18 | Arithmetic shift right
The names in the "Notes" column are macros defining the
corresponding operations. E.g. (bitop 1 a b) == (andb a b).
Examples:
(bitop 0 123 456) => 0 ; clear
(bitop 1 7 14) => 6 ; and
(bitop 7 7 8) => 15 ; or
(bitop 16 1 4) => 16 ; shift left
-- (DIV N1 N2) => FIXNUM ---------------------------------------
-- (MOD N1 N2) => FIXNUM ---------------------------------------
-- (REM N1 N2) => FIXNUM ---------------------------------------
DIV returns the truncated quotient of its fixnum arguments N1
and N2, i.e. the quotient N1/N2 with all fractional digits cut
off.
REM returns the remainder of the truncated fixnum division. I.e.:
(rem a b) == (- a (* b (div a b)))
MOD returns the remainder of the floored fixnum division. The
floored division is represented by FLOORDIV in the following
formula; note that this is *not* a LISP9 function! Formally,
(mod a b) == (- a (* b (floordiv a b)))
Examples:
(mod 13 4) => 1
(rem 13 4) => 1
(mod -13 4) => 3
(rem -13 4) => -1
(mod 13 -4) => -3
(rem 13 -4) => 1
(mod -13 -4) => -1
(rem -13 -4) => -1
-- (EVENP FIXNUM) => T/NIL -------------------------------------
-- (ODDP FIXNUM) => T/NIL -------------------------------------
EVENP returns T, if the given fixnum is divisible by two with
a remainder of zero [i.e. (= 0 (N REM 2))]. ODDP returns T, if
the remainder would be non-zero.
Examples:
(evenp 2) => t
(evenp 3) => nil
(oddp 2) => nil
(oddp 3) => t
-- (EXPT N1 N2) => FIXNUM --------------------------------------
Return N1 raised to the power of N2. Both arguments must be
fixnums. When the result does not fit in a fixnum, an error
will be signalled. Any value to the 0'th power is 1.
Examples:
(expt 2 0) => 1
(expt 2 2) => 4
(expt -3 3) => -27
-- (GCD N1 N2) => FIXNUM ---------------------------------------
-- (LCM N1 N2) => FIXNUM ---------------------------------------
GCD returns the greatest common divisor of the fixnums N1 and N2.
LCM returns their least common multiple. When the result if LCM
does not fit in a fixnum, an error will be signalled.
Examples:
(gcd 12 -18) => 6
(lcm 9 6) => 18
-- (MAX N1 N2 ...) => FIXNUM -----------------------------------
-- (MIN N1 N2 ...) => FIXNUM -----------------------------------
Return the largest or smallest of the given fixnum arguments,
respectively.
Examples:
(min 1) => 1
(max 1 2) => 2
(min 3 -14 15) => -14
-- (NOT EXPR) => T/NIL -----------------------------------------
Return T, if the given EXPR is NIL. Although this function is
extensionally equal to NULL, its application is different: it
is used to express the logical complement.
Examples:
(not t) => nil
(not (= 1 2)) => t
** CHARACTER FUNCTIONS *****************************************
-- (ALPHAC CHAR) => T/NIL -------------------------------------
-- (LOWERC CHAR) => CHAR --------------------------------------
-- (NUMERIC CHAR) => T/NIL -------------------------------------
-- (UPPERC CHAR) => T/NIL -------------------------------------
-- (WHITEC CHAR) => T/NIL -------------------------------------
Return T, if the character CHAR has the corresponding property:
ALPHAC the character is alphabetic (A-Z or a-z)
LOWERC the character is a lower-case letter (a-z)
NUMERIC the character is a decimal digit (0-9)
UPPERC the character is an upper-case letter (A-Z)
WHITEC the character is a space character:
blank (\40), HT (\10), LF (\12), CR (\15), FF (\14)
Examples:
(alphac #\A) => t
(lowerc #\a) => t
(numeric #\9) => t
(upperc #\A) => t
(whitec #\sp) => t
-- (C= C1 C2 ...) => T/NIL ------------------------------------
-- (C< C1 C2 ...) => T/NIL ------------------------------------
-- (C> C1 C2 ...) => T/NIL ------------------------------------
-- (C<= C1 C2 ...) => T/NIL ------------------------------------
-- (C>= C1 C2 ...) => T/NIL ------------------------------------
These predicates return T, if their character arguments are
- equal (C=)
- in strictly increasing lexicographic order (C<)
- in strictly decreasing lexicographic order (C>)
- in monotonically increasing lexicographic order (C<=)
- in monotonically decreasing lexicographic order (C>=)
They are trivially true when applied to a single argument.
The order of two characters of different case is undefined, i.e.
(c< #\a #\B) may be T or NIL.
Examples:
(c= #\a #\a) => t
(c< #\a #\b #\c) => t
(c> #\z) => t
(c<= #\a #\a #\b) => t
(c>= #\b #\b) => t
-- (DOWNCASE CHAR) => CHAR -------------------------------------
-- (UPCASE CHAR) => CHAR -------------------------------------
Convert character CHAT to lower or upper case, respectively. If
the given character cannot be converted (because it is not a
letter or already has the desired case), return the character
unchanged.
Examples:
(downcase #\U) => #\u
(downcase #\d) => #\d
(upcase #\f) => #\F
(upcase #\*) => #\*
** STRING FUNCTIONS ********************************************
-- (MKSTR FIXNUM CHAR) => STRING -------------------------------
-- (MKSTR FIXNUM) => STRING -------------------------------
Create a fresh string of the given length (FIXNUM). If a second
argument of the type char is specified, fill the string with
that character. When no second argument is given, the string is
filled with blanks.
Examples:
(mkstr 0) => ""
(mkstr 5) => " "
(mkstr 5 #\_) => "_____"
-- (NUMSTR FIXNUM) => STRING -----------------------------------
-- (NUMSTR N1 N2) => STRING -----------------------------------
Return a string containing the external representation of the
given fixnum. When a second fixnum argument N2 is given, return
the external representation in base N2. The base must be between
2 and 36. The default base is decimal. Digits with values above
9 will be represented by lower-case letters.
Examples:
(numstr 123) => "123"
(numstr 51996 16) => "cafe"
(numstr -27 8) => "-33"
-- (S= S1 S2) => T/NIL ----------------------------------------
-- (S< S1 S2) => T/NIL ----------------------------------------
-- (S> S1 S2) => T/NIL ----------------------------------------
-- (S<= S1 S2) => T/NIL ----------------------------------------
-- (S>= S1 S2) => T/NIL ----------------------------------------
These predicates return T, if their string arguments are
- equal (S=)
- in strictly increasing lexicographic order (S<)
- in strictly decreasing lexicographic order (S>)
- in monotonically increasing lexicographic order (S<=)
- in monotonically decreasing lexicographic order (S>=)
The individual characters of two strings are compared using the
char comparison predicates C=, C<, etc. If S1 is a proper prefix
of S2, then (s< S1 S2) => T, and if S2 is a proper prefix of
S1, then (s> S1 S2) => T.
Examples:
(s= "foo" "foo") => t
(s< "foo" "zork") => t
(s> "foo" "bar") => t
(s<= "fob" "foo") => t
(s>= "fob" "fob") => t
-- (SCONC STRING ...) => STRING --------------------------------
Concatenate strings: return a fresh string that contains the
characters of the first STRING argument followed by the
characters of the second argument, etc. When no arguments are
given, return the empty string "".
Examples:
(sconc) => ""
(sconc "foo") => "foo"
(sconc "foo" "bar") => "foobar"
-- (SCOPY STRING) => STRING ------------------------------------
Return a fresh (and mutable) copy of the given string.
Examples:
(scopy "foo") => "foo"
(sset (scopy "foo") 2 #\b) => "fob"
-- (SFILL STRING CHAR) => STRING -------------------------------
Store the given char in every position of the given string. The
string will be modified in situ, hence it must be mutable.
Example:
(sfill (mkstr 5) #\x) => "xxxxx"
-- (SI< S1 S2) => T/NIL ---------------------------------------
-- (SI<= S1 S2) => T/NIL ---------------------------------------
-- (SI= S1 S2) => T/NIL ---------------------------------------
-- (SI> S1 S2) => T/NIL ---------------------------------------
-- (SI>= S1 S2) => T/NIL ---------------------------------------
These predicates return T, if their string arguments are
- equal (SI=)
- in strictly increasing lexicographic order (SI<)
- in strictly decreasing lexicographic order (SI>)
- in monotonically increasing lexicographic order (SI<=)
- in monotonically decreasing lexicographic order (SI>=)
The individual characters of two strings are compared using
(lambda (c1 c2) (PRED (downcase c1) (downcase c2)))
where PRED is the corresponding char comparison predicate (C=,
C<, etc). The 'I' in SI=, etc, means "case-Insensitive".
If S1 is a proper prefix of S2, then (si< S1 S2) => T, and if S2
is a proper prefix of S1, then (si> S1 S2) => T.
Examples:
(si= "foo" "FOO") => t
(si< "Foo" "zork") => t
(si> "foo" "BAR") => t
(si<= "fob" "Foo") => t
(si>= "FOB" "fob") => t
-- (SREF STRING FIXNUM) => CHAR --------------------------------
Extract a character from a string. FIXNUM specifies the position
of the character to extract. Positions start at 0. The FIXNUM
argument must be positive and less than (ssize STRING).
Examples:
(sref "fob" 0) => #\f
(sref "fob" 2) => #\b
-- (SSET STRING FIXNUM CHAR) => STRING -------------------------
Store the character CHAR in position FIXNUM of the given string.
The string will be modified in situ, hence it must be mutable.
Positions start at 0, so FIXNUM must be positive and less than
(ssize STRING).
Examples:
(sset (mkstr 5 #\_) 2 #\x) => "__x__"
(sset (string #\f #\o #\o) 2 #\b) => "fob"
-- (SSIZE STRING) => FIXNUM ------------------------------------
Return the number of characters in the given string.
Examples:
(ssize "") => 0
(ssize "hello, world!") => 13
(ssize "\0\1\2\3") => 4
-- (STRING CHAR ...) => STRING ---------------------------------
Create a fresh string from the given arguments. The arguments
must be of the type char.
Examples:
(string) => ""
(string #\f #\o #\b) => "fob"
-- (STRNUM STRING) => FIXNUM/NIL ------------------------
-- (STRNUM STRING FIXNUM) => FIXNUM/NIL ------------------------
Return the number whose external representation is stored in the
given string. When no second argument is specified, the number
will be assumed in base 10 (decimal). When the FIXNUM argument
is given it indicates the base of the representation in the
string. The base must be between 2 and 36.
The number represented by STRING may have an optional plus (+) or
minus (-) sign. It may *not* contain any non-numeric leading or
trailing characters.
When STRING does not contain a valid external representation
of a number, STRNUM returns NIL. This includes numeric strings
that cannot be converted to fixnum without overflow.
Examples:
(strnum "123") => 123
(strnum "+123" 8) => 83
(strnum "-fff 16) => -4095
(strnum "foo") => nil
(strnum " -1") => nil
(strnum "123 ") => nil
-- (SUBSTR STRING N1 N2) => STRING -----------------------------
Return a fresh string that contains a substring extracted from
the given string. The substring starts at position N1 and
extends to (but does not include) position N2. N1 and N2 must be
positive fixnums, N2 must not be larger than the size of STRING,
and N1 must not be larger than N2, i.e.
(<= 0 N1 N2 (ssize STRING)) => T
must hold.
Examples:
(substring "abc" 0 0) => ""
(substring "abc" 0 1) => "a"
(substring "abc" 0 2) => "ab"
(substring "abc" 0 3) => "abc"
(substring "abc" 1 3) => "bc"
(substring "abc" 2 3) => "c"
(substring "abc" 3 3) => ""
** VECTOR FUNCTIONS ********************************************
-- (MKVEC FIXNUM) => VECTOR -------------------------------
-- (MKVEC FIXNUM EXPR) => VECTOR -------------------------------
Create a fresh vector of the given length (FIXNUM). If a second
argument is specified, fill the string with that argument. When
no second argument is given, the vector is filled with NIL.
Examples:
(mkvec 0) => #()
(mkvec 5) => #(nil nil nil nil nil)
(mkvec 5 'xyz) => #(xyz xyz xyz xyz xyz)
-- (SUBVEC VECTOR N1 N2) => VECTOR -----------------------------
Return a fresh vector that contains elements extracted from the
given vector. The extracted elements start at position N1 and
extends to (but does not include) position N2. N1 and N2 must be
positive fixnums, N2 must not be larger than the size of VECTOR,
and N1 must not be larger than N2, i.e.
(<= 0 N1 N2 (vsize VECTOR)) => T
must hold.
Examples:
(subvec #(a b c) 0 0) => #()
(subvec #(a b c) 0 1) => #(a)
(subvec #(a b c) 0 2) => #(a b)
(subvec #(a b c) 0 3) => #(a b c)
(subvec #(a b c) 1 3) => #(b c)
(subvec #(a b c) 2 3) => #(c)
(subvec #(a b c) 3 3) => #()
-- (VCONC VECTOR ...) => VECTOR --------------------------------
Concatenate vectors: return a fresh vector that contains the
elements of the first VECTOR argument followed by the elements
of the second argument, etc. When no arguments are given, return
the empty vector #().
Examples:
(vconc) => #()
(vconc #(f o o)) => #(f o o)
(vconc #(f o o) #(b a r)) => #(f o o b a r)
-- (VECTOR EXPR ...) => VECTOR ---------------------------------
Create a fresh vector from the given arguments.
Examples:
(vector) => #()
(vector 'foo (* 6 7)) => #(foo 42)
-- (VFILL VECTOR EXPR) => VECTOR -------------------------------
Store the given EXPR in every position of the given vector. The
vector will be modified in situ, hence it must be mutable.
Example:
(vfill (mkvec 5) 'x) => #(x x x x x)
-- (VREF VECTOR FIXNUM) => OBJ ---------------------------------
Extract an element from a vector. FIXNUM specifies the position
of the element to extract. Positions start at 0. The FIXNUM
argument must be positive and less than (vsize VECTOR).
Examples:
(vref '(foo bar baz) 0) => 'foo
(vref '(foo bar baz) 2) => 'baz
-- (VSET VECTOR FIXNUM EXPR) => VECTOR -------------------------
Store the given EXPR in position FIXNUM of the given vector.
The vector will be modified in situ, hence it must be mutable.
Positions start at 0, so FIXNUM must be positive and less than
(vsize VECTOR).
Examples:
(vset (mkvec 5 'x) foo) => #(x x foo x x)
(vset (vector 'f 'o 'o) 2 'b) => #(f o b)
-- (VSIZE VECTOR) => FIXNUM ------------------------------------
Return the number of elements in the given vector.
Examples:
(vsize #()) => 0
(vsize #(a b c d e)) => 5
** MACROS ******************************************************
-- (MACRO <KEYWORD> FUN) => UNSPECIFIC -------------------------
Bind the symbol <KEYWORD> to the given function in the syntactic
environment, thereby creating a macro. The syntactic environment
is distinct from all lexical environments of LISP9, so
definitions via DEF and local variables via LAMBDA do not
interfere with it. There is only one syntactic environment in
which all macros are bound. Hence the MACRO form must appear at
the top level (or inside of a PROG form at the top level).
Macros are used to define derived special forms, like COND, LET,
and DO. See the section on DERIVED SYNTAX for details.
Examples:
(macro kwote
(lambda (x)
@(quote ,x)))
(macro when
(lambda (p . xs)
@(if ,p (prog . ,xs))))
-- (DEFMAC (<KW> . <FORMALS>) EXPR1 EXPR2 ...) => UNSPECIFIC ---
The DEFMAC form is an abbreviation for
(macro <kw> (lambda <formals> expr1 expr2 ...))
where <formals> is a formal argument list as specified in the
FORMAL SYNTAX section. Note that the dot in the above form only
serves to formalize the equivalence between MACRO and DEFMAC.
You would normally write
(defmac (foo . (x y)) @(bar ,x ,y))
as
(defmac (foo x y) @(bar ,x ,y))
although the former would also work.
Examples:
(defmac (kwote x)
@(quote ,x))
(defmac (when p . xs)
@(if ,p (prog . ,xs)))
-- (GENSYM) => SYMBOL ------------------------------------------
Generate a unique local symbol. Generated symbols (gensyms) are
typically used in macros to avoid name capturing. Imagine the
SWAP example below with the name FOO instead of a gensym and
then applying (swap foo bar) to illustrate the problem that
GENSYM solves.
The LISP9 implementation of GENSYM will not intern gensym names
and start to recycle them each time the system is started.
Therefore, gensyms should never be used to name global variables.
Their names *will* be reused. This is not a problem in local
definitions, because variable names are no longer used after
compiling the expressions in which they are contained.
Examples:
(gensym) => G1
(eq (gensym) (gensym)) => nil
(defmac (swap a b)
(let ((x (gensym)))
@(prog (setq ,x ,a)
(setq ,a ,b)
(setq ,b ,x))))
-- (MX EXPR) => OBJ -------------------------------------------
-- (MX1 EXPR) => OBJ -------------------------------------------
Macro-expand the given EXPR and returns its expanded form. When
EXPR does not contain any macro applications, return it in its
original form.
MX expands all macro applications in EXPR recursively, so the
result of MX will be free of derived special syntax.
MX1 expands the first (leftmost) macro application in EXPR and
return the resulting form immediately. If the macro should be
recursive, it will only be expanded once.
Note that EXPR must be quoted, or it will be macro-expanded
before passing it to MX or MX1.
Examples:
(mx1 '(let* ((a 1) (b a)) b))
=> (let ((a 1)) (let* ((b a)) b))
; iterative application of MX1 will expand EXPR completely:
(mx1 **) => ((lambda (a) (let* ((b a)) b)) 1)
(mx1 **) => ((lambda (a) (let ((b a)) (let* () b))) 1)
(mx1 **) => ((lambda (a) ((lambda (b) (let* () b)) a)) 1)
(mx1 **) => ((lambda (a) ((lambda (b) (prog b)) a)) 1)
; MX performs all of the above expansions at once:
(mx '(let* ((a 1) (b a)) b))
=> ((lambda (a) ((lambda (b) (prog b)) a)) 1)
** NON-LOCAL EXITS *********************************************
-- (CATCH FUN^1) => OBJ -----------------------------------
-- (THROW CTAG EXPR) => N/A -----------------------------------
-- (CATCH* FUN^1) => OBJ -----------------------------------
-- (THROW* CTAG EXPR) => N/A -----------------------------------
CATCH packages the current escape continuation into a "catch tag"
and passes it to the given function, which must be a function of
one argument. The function will then evaluate and return a
result, which will in turn be returned by CATCH -- unless the
function applies THROW to the catch tag passed to it.
When FUN^1 applies THROW to the catch tag generated by CATCH,
then evaluation of the function will be aborted immediately and
control will be passed back to CATCH. The result of CATCH will
in this case be the second argument (EXPR) of the corresponding
THROW.
A catch tag that escapes the dynamic extent of CATCH is no longer
valid and throwing it will cause an undefined result. That is,
CATCH only captures its escape continuation, so catch tags can
only be used to escape the dynamic extent of CATCH, but not to
reenter it.
The difference between CATCH/THROW and CATCH*/THROW* is that
CATCH and THROW unwinds UNWIND functions, which CATCH* and
THROW* do not do. See UNWIND for details. The effects of
combining CATCH* with THROW or CATCH with THROW* are undefined.
For examples of the interaction between CATCH, THROW, and UNWIND,
see UNWIND. Other than that, CATCH*/THROW* can be considered to
be a more efficient version of CATCH and THROW.
Examples:
(cons 'foo (catch* (lambda (ct) (cons 'baz (throw* ct 'bar)))))
=> (foo . bar)
(define (list-length a)
(catch*
(lambda (improper)
(let loop ((a a))
(cond ((null? a) 0)
((pair? a) (+ 1 (loop (cdr a))))
(else (throw* improper nil)))))))
(list-length '(1 2 3)) => 3
(list-length '(1 2 3 . 4 )) => nil
-- (UNWIND FUN1^0 FUN2^0) => OBJ -------------------------------
Evaluate the body of FUN2^0 (the "body") and then the body of
FUN1^0 (the "unwind function"), returning the value delivered
by FUN2^0.
If UNWIND appears inside of the dynamic extent of an application
of CATCH and a THROW inside of FUN2^0 transfers control to that
CATCH, then the body of FUN1^0 will still evaluate. E.g.
(let ((foo 'initial))
(catch
(lambda (c)
(unwind
(lambda ()
(setq foo 'unwound))
(lambda ()
(setq foo 'modified)
(throw c 'ignored)
(setq foo 'unreached)))))
foo) => unwound
When there are multiple UNWIND expressions in the dynamic extent
of a CATCH expression, then all of them will evaluate, and the
most recently registered unwind function will evaluate first.
When there are multiple nested CATCH expressions, each with its
own UNWIND expressions, then THROWing a catch tag will trigger
evaluation of all unwind functions that were registered after
evaluating the receiving CATCH and before evaluating the THROW.
Rationale: transferring control non-locally can leave the state
of a program altered in an undesired way. For example, given a
native implementation of WITH,
(catch-errors (nil)
(with ((*parameter* value))
(do-something)))
will fail to reset *PARAMETER* to its original value when an
error occurs in DO-SOMETHING. UNWIND can be used to reset the
value of the parameter when control is passed "across" an
unwind function:
(let ((outer-parameter *parameter*))
(catch-errors (nil)
(unwind (lambda ()
(setq *parameter* outer-parameter))
(lambda ()
(with ((*parameter* value))
(do-something))))))
The implementation of WITH that is part of LISP9 will do this
internally, though.
Other uses of UNWIND would be closing files, changing input or
output ports, and any other operations that are required to
leave the state of a program in a consistent way after catching
a non-local exit.
Examples:
; see above
(unwind (lambda () 'foo)
(lambda () 'bar)) => foo
-- (ERROR STRING EXPR) => UNDEFINED ----------------------------
-- (ERROR STRING) => UNDEFINED ----------------------------
Signal an error and abort the computation in progress. STRING
will be printed as an error message. When an EXPR argument is
also specified, print that argument (using PRIN) after the
message.
ERROR does not return any value. It returns control to the
REPL or, in case the interpreter runs in batch mode, terminates
program execution.
Examples:
(error "good bye!")
(if (< x 1)
(error "expected positive X, but got" x))
-- (CATCH-ERRORS (<ERRVAL>) EXPR1 EXPR2 ...) => OBJ ------------
First evaluate <ERRVAL>, which can be any expression. Then set
up a special catch tag (see CATCH) that will be thrown when the
LISP9 system would signal an error. Within the dynamic extent of
CATCH-ERRORS (the "error context") evaluate the given EXPRs.
When none of the expressions signals an error, return the value
of the last expression.
When an expression in the body of CATCH-ERRORS signals an error,
return <ERRVAL> immediately (via THROW), thereby aborting
evaluation of the given expressions.
Note that CATCH-ERRORS will *not* unwind the unwind stack when
an error is being caught, becasue it uses CATCH* and THROW*
internally! Unwinding must be done explicitly in code that uses
CATCH-ERRORS.
When no <ERRVAL> is specified (i.e. the first argument of
CATCH-ERRORS is NIL), the error message passed to ERROR will be
returned in case of an error. Note that ERROR is also used by
built-in functions of LISP9 to signal errors.
Multiple error contexts may exist. In this case, <ERRVAL> is
evaluated in the outer ("surrounding") error context and the
body of CATCH-ERRORS is evaluated in the inner context. When
CATCH-ERRORS returns (in whatever way), the outer context will
be re-established.
Examples:
(catch-errors ('foo) (+ 1 2)) => 3
(catch-errors ('foo) (car nil)) => foo
(catch-errors (0) (div 1 0)) => 0
(catch-errors () (cdr nil)) => "cdr: expected pair"
(catch-errors ((div 1 0)) 'bar) => error
(catch-errors ('foo)
(catch-errors ((div 1 0)) 'bar)) => foo
** INPUT/OUTPUT FUNCTIONS **************************************
-- (CLOSE-PORT PORT) => UNSPECIFIC -----------------------------
Close an input or output port. The port becomes inaccessible
immediately and will not accept or deliver any further input
or output.
Note that LISP9 closes ports automatically when they can no
longer be referenced by the system. CLOSE-PORT is mostly used
to make sure that all output sent to a port has been written
to the associated file or device.
The standard ports -- (inport), (outport), and (errport) --
should not be closed.
Example:
(close-port (open-outfile "file.tmp"))
-- (DELETE STRING) => UNSPECIFIC -------------------------------
Delete the file specified in STRING. When the file does not
exist or cannot be deleted, an error will be signalled.
Example:
(delete "file.tmp")
(catch-errors (t) (delete "file.tmp")) => t
-- (ERRPORT) => OUTPORT ----------------------------------------
-- (INPORT) => INPORT -----------------------------------------
-- (OUTPORT) => OUTPORT ----------------------------------------
Return the current error port, input port, or output port,
respectively. The current input port -- (INPORT) -- is the port
from which all input function will read their input unless an
explicit port is passed to them. Similarly, the current output
port -- (OUTPORT) -- is the port where all output will go unless
an explicit port is given.
(ERRPORT) is a port that is useful for reporting errors in case
the (OUTPORT) has been redirected.
Examples:
(let ((old (inport))
(new (open-infile "some-file"))
(ln nil))
(set-inport new)
(setq ln (readln)) ; (readln) will read from NEW
(set-inport old)
ln)
(prog
(princ "Something unusual has happened!" (errport))
(terpri (errport)))
-- (EXISTSP STRING) => T/NIL -----------------------------------
Return T, if the file specified in STRING exists and is readable
by the LISP9 process.
Examples:
(if (not (existsp some-file))
(error "file not found" some-file))
(if (existsp "file.tmp")
(delete "file.tmp"))
-- (EOFP EXPR) => T/NIL ----------------------------------------
Return T, if EXPR is the EOF marker.
Example:
(prog (with-outfile "test.tmp" (lambda () nil))
(eofp (with-infile "test.tmp" read))) => t
-- (OPEN-INFILE STRING) => INPORT ---------------------------
-- (OPEN-OUTFILE STRING) => OUTPORT --------------------------
-- (OPEN-OUTFILE STRING T) => OUTPORT --------------------------
Open a file for input or output, respectively, and return a port
for accessing the file. When any of the above functions fails to
open a file, an error will be signalled.
When OPEN-OUTFILE opens an existing file, the file will be
truncated to a size of 0. When a second argument of T is passed
to OPEN-OUTFILE, the file will not be truncated and output
written to the resulting port will be appended to the existing
file.
Example:
(open-infile "some-file") => #<inport 3>
-- (FORMAT EXPR) => STRING -------------------------------------
Return a fresh string containing the external representation of
the given expression. FORMAT is like PRIN (q.v.), but directs
output to a string instead of a port.
Examples:
(format 123) => "123"
(format '(a b c d)) => "(a b c d)"
(format "\"Hi\", she said.") => "\"Hi\"", she said."
-- (PRIN EXPR) => OBJ ---------------------------------
-- (PRIN EXPR OUTPORT) => OBJ ---------------------------------
-- (PRINC EXPR) => OBJ ---------------------------------
-- (PRINC EXPR OUTPORT) => OBJ ---------------------------------
-- (PRINT EXPR ...) => UNSPECIFIC -------------------------
Write an EXPR to the given output port, or to (outport) when no
port was specified. PRIN writes the external representation of
EXPR to a port and PRINC pretty-prints the expression. The
external representation and the pretty form are the same except
for strings and characters, which will print as follows:
PRIN PRINC PRIN PRINC
"foo" foo #\x x
"\"bar\"" "bar" #\sp (blank)
"\\x" \x #\\7 (sounds a bell)
"a\nb" a
b
The output of PRINC is mostly intended to be read by human
beings while the output of PRIN is in such a format that it can
be read back in by the READ function. There are some LISP9
objects that do not have a READable external representation,
though, like functions, catch tags, and I/O ports. For those
objects, the printing functions will emit a descriptive text
that cannot be read by READ. Such text is typically prefixed by
the sequence "#<", which will cause an error when attempting to
read it.
Neither PRIN nor PRINC print a newline sequence after their
output. Use (print) or (terpri) to begin a new line.
PRINT prints all of its arguments, separated by spaces, in the
same way as PRIN would and emits a newline sequence at the end.
PRINT always prints to (outport), no other port can be specified,
but its output can be redirected using WITH-OUTFILE.
PRIN and PRINC return the object being printed.
Examples:
(prin "\"Hi\", she said.") prints "\"Hi\", she said."
(princ "\"Hi\", she said.") prints "Hi", she said.
(prin '(1 #\2 (3))) prints (1 #\2 (3))
(princ '(1 #\2 (3))) prints (1 #\2 (3))
(print 1 #\2 '(3)) prints 1 #\2 (3) and does (terpri)
(print) just emits a newline sequence
-- (READ) => OBJ/EOF ------------------------------------
-- (READ INPORT) => OBJ/EOF ------------------------------------
-- (READ STRING) => LIST/STRING --------------------------------
Read the external representation of a LISP9 object from the
given input port or, if no port is specified, from (inport).
READ skips over leading space characters (in the sense of
WHITEC) and keeps reading until all characters of the external
representation of one object have been consumed.
When the object is a compound object, like a list or a vector,
READ keeps reading until the outermost closing parenthesis has
been found.
When READ encounters the end of its input before reading the
first character of an object, it will return the EOF marker.
When encountering the end of its input inside of a compound
object, it will signal an error.
When a string is passed to READ, it will read that string
instead of an input port and return the resulting object in a
single-element list. When reading a string, no error will ever
be signalled, but another string, which describes the error,
will be returned.
When reading a string that contains the external representations
of multiple objects, only the first object will be read.
Note that comments are objects in LISP9, so READing a comment
will return immediately and yield the comment. Comments are
only ignored by the compiler, but not at the READ level.
READ returns the object whose external representation it has
read.
Examples:
(read) foo => foo
(read) 'foo => 'foo
(read) (quote foo) => 'foo
(read) (1 #\2 (3) #(4)) => (1 #\2 (3) #(4))
(read) ; comment
=> ; comment
(read) (defun (f x)
(* x x x)) => (defun (f x) (* x x x))
(read "(foo bar)") => ((foo bar))
(read "1 2 3") => 1
(read ". oops") => "unexpected '.'"
-- (READC) => CHAR/EOF ----------------------------------
-- (READC INPORT) => CHAR/EOF ----------------------------------
-- (PEEKC) => CHAR/EOF ----------------------------------
-- (PEEKC INPORT) => CHAR/EOF ----------------------------------
Read a character from the given input port or from (inport), if
no port is specified. Return the character. When no more input
is available from the given port, return the EOF marker instead.
READC advances the read pointer of the port, so that a
subsequent READC will produce the next character from the file
or device associated with the port. PEEKC does not advance the
read pointer, so a subsequent READC will deliver the same
character again.
Examples:
(readc)x => #\x
(prog (readc) (readc))xy => #\y
(prog (peekc) (readc))x => #\x
-- (READLN) => STRING/EOF -------------------------------
-- (READLN INPORT) => STRING/EOF -------------------------------
Read characters from the given input port or, if no port is
specified, from (inport). Keep reading characters until a
newline sequence is found. Return a fresh string containing
all characters consumed, but excluding the newline sequence
itself. When no characters are available on the input port,
return the EOF marker.
Examples:
(readln) foo bar baz => " foo bar baz"
(readln (inport)) => ""
-- (SET-INPORT INPORT) => UNSPECIFIC -------------------------
-- (SET-OUTPORT OUTPORT) => UNSPECIFIC -------------------------
Specify a new current input port or output port, respectively.
After applying SET-INPORT, INPORT will return the given port and
after applying SET-OUTPORT, OUTPORT will return the specified
port.
These functions are typically not used in user-defined functions.
Use WITH-INFILE or WITH-OUTFILE instead.
Examples:
(set-outport (errport)) ; output will go to the error port
; by default now
; see INPORT for another example
-- (TERPRI) => #\NL ------------------------------------
-- (TERPRI OUTPORT) => #\NL ------------------------------------
Write a newline sequence to the given output port, or, if no
port was specified, to (outport).
Examples:
(terpri)
(terpri (errport))
-- (WITH-INFILE STRING FUN^0) => OBJ --------------------------
-- (WITH-OUTFILE STRING FUN^0) => OBJ --------------------------
Open the file specified in STRING for input or output,
respectively. The resulting port will become the current input
or output port in the dynamic extent of the corresponding
function, i.e. while FUN^0 evaluates. FUN^0 must be a function
of no arguments. All applications of I/O function inside of
FUN^0 that do not specify an explicit port will read from or
write to the port created by WITH-INFILE or WITH-OUTFILE.
When FUN^0 returns, the created port will be closed and the
value delivered by FUN^0 will be returned.
Examples:
(with-infile "some-file" readln) => "first line of some-file"
(with-outfile "some-file"
(lambda ()
(princ "Hello, World!")
(terpri))) => #\nl
-- (WITH-INPORT STRING FUN^1) => OBJ --------------------------
-- (WITH-OUTPORT STRING FUN^1) => OBJ --------------------------
Open the file specified in STRING for input or output,
respectively. The resulting port will be passed to FUN^1, which
must be a function of one argument. FUN^1 can then use the port
to read or write the opened file. When FUN^1 returns, the port
will be closed and the result of FUN^1 will be returned.
Examples:
(with-inport "some-file"
(lambda (in)
(readln) ; this will read (inport)
(readln in))) ; this will read "some-file"
(with-outport "some-file"
(lambda (out)
(print "this will go to (outport)")
(princ "this will go to some-file" out)
(terpri out))) ; this will also go to the file
-- (WRITEC CHAR) => CHAR -------------------------------
-- (WRITEC CHAR OUTPORT) => CHAR -------------------------------
Write a CHAR to the given output port, or to (outport) when no
port was specified. The character is written as if printed by
PRINC. WRITEC returns the char it printed.
Examples:
(writec #\x) => #\x ; prints x
(writec #\sp) => #\sp ; prints a space character
** SYSTEM FUNCTIONS ********************************************
-- (CMDLINE) => LIST -------------------------------------------
Deliver a list of the command line arguments passed to a LISP9
program. Each element of the list will be a string containing
one argument.
Example:
(cmdline) => ("foo" "bar" "baz") ; Given that the program
; was started with
; "ls9 program foo bar baz"
-- (CONSTP EXPR) => T/NIL --------------------------------------
Return T, if EXPR is immutable. The following objects are
immutable:
- Non-empty quoted lists
- non-empty vector literals
- Non-empty string literals
CONSTP facilitates the implementation of metacircular
interpreters, because it allows to intercept immutable
arguments to procedures such as SETCAR, SSET, or VFILL.
Examples:
(constp '(1 2 3)) => t
(constp (list 1 2 3)) => nil
-- (DUMP-IMAGE STRING) => UNSPECIFIC ---------------------------
-- (SAVE) => UNSPECIFIC ---------------------------
Save the complete state of the LISP9 system to an image file.
The image will contain the complete top level environment and
the syntactic environment of the interpreter as well as all
objects referenced by them. Note, though, that I/O ports will
no longer be open when restarting the image file.
The STRING argument of DUMP-IMAGE names the image file. The SAVE
function saves the system state to the file name in the special
variable *IMAGEFILE*. This variable will be set automatically
when LISP9 restarts an image file. DUMP-IMAGE will change the
value of the variable to its argument after successfully writing
an image file. When *IMAGEFILE* is NIL, SAVE will signal an
error.
Before writing an image file, any existing image file named
"file.image" will be renamed to "file.oimage". When the file
has no ".image" suffix, ".oimage" will be appended.
Examples:
(dump-image "ls9.image")
(save)
-- (EVAL EXPR) => OBJ ------------------------------------------
Evaluate the given expression, as if entered at the REPL, and
return its value. In fact, EVAL is the "E" in read-eval-print
loop. EXPR is evaluated in the top-level environment, so if EXPR
is a definition (DEF form or derived from it) or mutation (SETQ
form), it will alter the top-level environment.
Note that EXPR must be quoted, or the *value* of EXPR will be
passed to EVAL (thereby evaluating EXPR twice).
Examples:
(eval 'foo) => foo
(eval ''foo) => 'foo
(eval '(cons (- 2 1) 2)) => (1 . 2)
(prog (def foo 'zzz)
(eval '(def foo 'bar))
foo) => bar
-- (GC) => LIST ------------------------------------------------
Perform a garbage collection and return a list containing the
amount of free nodes and free vector cells, respectively:
(free-nodes free-vcells)
Running GC will also finalize and close all I/O ports that are
still open, but can no longer be accessed by any LISP9 program.
Example:
(gc) => (245498 235877) ; actual values will probably differ
-- (LOAD STRING) => UNSPECIFIC ---------------------------------
Open the file specified in STRING and read an evaluate the LISP9
expressions contained in it. The expressions are evaluated in
the top level environment, as if typed in at the REPL. While
loading, the value of (inport) stays unaffected, i.e. applying
READ or a similar function inside of the file being loaded will
suspend loading and read input from the original (inport).
Example:
(with-outfile "test.tmp"
(lambda ()
(print '(def foo 'bar))))
(load "test.tmp")
foo => bar
-- (OBTAB) => VECTOR -------------------------------------------
Return a sparse vector containing all objects that are currently
known to the LISP9 system. Unused slots of the vector will be
set to NIL (except for the first slot, which contains the actual
object NIL).
The OBTAB (object table) is a highly dynamic structure where
elements will be added by the reader (READ) and deleted (set to
NIL) by the garbage collector. The OBTAB grows on demand.
-- (START) => UNSPECIFIC ---------------------------------------
This function is applied to zero arguments when the interpreter
starts, after loading program files, but before entering batch
execution or the REPL. By default this function is undefined and
the application will fail silently.
When a START function is defined and stored in an image file,
though, it will evaluate each time the interpreter is invoked.
Example:
(defun (start) (princ "Hello, World\n"))
(save)
-- (SYMTAB) => VECTOR ------------------------------------------
Return a vector containing all symbols known to the LISP9 system.
Unused slots in the vector will be set to NIL. The symbol table
(SYNTAB) grows on demand.
Note that symbols generated by GENSYM will not appear in the
table.
-- (SYSCMD STRING) => FIXNUM -----------------------------------
Pass the given string to the operating system for execution.
Return the exit status delivered by the operating system, where
zero usually indicates success and non-zero failure.
Example:
(system "ls") => 0 ; will list files on a Unix system
-- (UNTAG EXPR) => OBJ -----------------------------------------
Remove the tag from a tagged data object, if possible. If the
tag cannot be removed, return NIL. An untagged data object is
not a valid LISP9 object and should not passed to any function
without knowing the internal structure of the object.
USING THIS FUNCTION CARELESSLY *WILL* CRASH THE LISP9 SYSTEM!
The most common application of this function is to extract the
bytecode of a function object for examination.
Example:
(untag car) => #(10 8 19 1 5 0 30 21 16 14 2 23 5 13)
** SPECIAL VARIABLES *******************************************
-- ** ----------------------------------------------------------
The value most recently printed on the REPL. The value of
this variable will not be changed by by aborted or erroneous
computations.
Examples:
(mkvec 5 '_) => #(_ _ _ _ _)
(vset ** 2 'foo) => #(_ _ foo _ _)
(expt 2 9) => 512
(* 2 **) => 1024
-- *ERRTAG* ----------------------------------------------------
-- *ERRVAL* ----------------------------------------------------
These variables are used internally by the CATCH-ERRORS function.
*ERRTAG* holds the catch tag that will be thrown in case of an
error and *ERRVAL* holds the value to be delivered in case of an
error. These variables should not be touched by any function
other than CATCH-ERRORS.
-- *IMAGEFILE* -------------------------------------------------
The image file from which the current LISP9 session was started
or to which the most recent state was dumped. When LISP9 starts
up, it will set the value of this variable to the file name of
the image being loaded initially. When no image is being loaded,
the value will be set to NIL.
DUMP-IMAGE sets *IMAGEFILE* to its argument when an image file
could be written successfully.
-- *QUIET* -----------------------------------------------------
This variable is set to T when the interpreter was started in
quiet mode and otherwise to NIL.
-- *UNWIND* ----------------------------------------------------
This variable is bound to the unwind stack, i.e., the location
where unwind functions are registered and unregistered (see
UNWIND).
** APPENDIX ****************************************************
-- FORMAL SYNTAX -----------------------------------------------
DEFINITIONS
<symchar> = member of {abcdefghijklmnopqrstuvwxyz
0123456789!$%&*+-/:<=>?^_~}
Note: upper case letters will be folded to
lower case by the reader!
<digit> = member of {0123456789}
<char> = any ASCII character
<nl> = ASCII character 10 (linefeed)
a := b a | b = "a" can be written as "b a" or "b"
a* = zero or more "a"s
a+ = one or more "a"s
SYNTAX
program := expr*
expr := app | symbol | string | char | fixnum
| pair | list | vector | special
cexpr := expr | comment
comment := (-- expr* )
symbol := <symchar>+
string := "<char>*"
char := #\<char> | #\sp | #\nl | #\ht | #\\[0-7]+
fixnum := <digit>+ | -<digit>+
pair := (expr . expr)
list := (expr*)
vector := #(expr*)
special := t | nil
app := (QUOTE expr)
| (LAMBDA formals cexpr*)
| (expr expr*)
| (APPLY expr+ expr)
| (PROG cexpr*)
| (IF expr expr expr)
| (IF expr expr)
| (IF* expr expr)
| (SETQ symbol expr)
| (DEF symbol expr)
| (MACRO symbol expr)
formals := symbol | (symbol*) | (symbol+ . symbol)
ABBREVIATIONS
(DEFUN (symbol . formals) expr+)
= (DEF symbol (lambda formals expr+))
(DEFMAC (symbol . formals) expr+)
= (MACRO symbol (lambda formals expr+))
;<char>* = (-- "<char>*")
'expr = (QUOTE expr)
@expr = (QQUOTE expr)
`expr = (QQUOTE expr)
,expr = (UNQUOTE expr)
,@expr = (SPLICE expr)
*************************** THE END ****************************