This report describes research done at the Artificial Intelligence Laboratory of the Massachusetts Institute of Technology. Support for the laboratory’s artificial intelligence research is provided in part by the Advanced Research Projects Agency of the Department of Defense under Office of Naval Research Contract number N00014-80-C-0505.
The Lisp Machine manual describes both the language and the operating system of the Lisp Machine. The language, a dialect of Lisp called Zetalisp, is completely documented by this manual. The software environment and operating-system-like parts of the system contain many things which are still in a state of flux. This manual confines itself primarily to the stabler parts of the system. It describes how to program, but not for the most part how to operate the machine. The window system is documented separately in the Lisp Machine Window System manual.
Any comments, suggestions, or criticisms will be welcomed. Please send Arpa network mail to BUG-LMMAN@MIT-MC.
Those not on the Arpanet may send U.S. mail to
Richard M. Stallman
Artificial Intelligence Lab
545 Technology Square
Cambridge, Mass. 02139
Portions of this manual were written by Mike McMahon and Alan Bawden. The chapter on the LOOP iteration macro is mostly a reprint of Laboratory for Computer Science memo TM-169, by Glenn Burke. Sarah Smith, Meryl Cohen and Richard Ingria of LMI, and Richard Mlynarik of MIT, helped to correct the manual.
The Lisp Machine is a product of the efforts of many people too numerous to list here and of the former unique unbureaucratic, free-wheeling and cooperative environment of the M.I.T Artificial Intelligence Laboratory. I believe that the commercialization of computer software has harmed the spirit which enabled such systems to be developed. Now I am attempting to build a software-sharing movement to revive that spirit from near oblivion.
Since January 1984 I have been working primarily on the development of GNU, a complete Unix-compatible software system for standard hardware architectures, to be shared freely with everyone just like EMACS. This will enable people to use computers and be good neighbors legally (a good neighbor allows his neighbors to copy any generally useful software he has a copy of). This project has inspired a growing movement of enthusiastic supporters. Just recently the first free portable C compiler compiled itself. If you would like to contribute to GNU, write to me at the address above. Restrain social decay–help get programmers sharing again.
The Lisp Machine is a new computer system designed to provide a high-performance and economical implementation of the Lisp language. It is a personal computation system, which means that processors and main memories are not time-multiplexed: when using a Lisp Machine, you get your own processor and memory system for the duration of the session. It is designed this way to relieve the problems of running large Lisp programs on time-sharing systems. Everything on the Lisp Machine is written in Lisp, including all system programs; there is never any need to program in machine language. The system is highly interactive.
The Lisp Machine executes a new dialect of Lisp called Zetalisp, developed at the M.I.T Artificial Intelligence Laboratory for use in artificial intelligence research and related fields. It was originally based on the Maclisp dialect, and attempts to maintain a good degree of compatibility with Maclisp, while also providing many improvements and new features. Maclisp, in turn, was based on Lisp 1.5.
Common Lisp is a Lisp dialect designed to standardize all the various Lisp systems derived from Maclisp. Zetalisp today is nearly a superset of Common Lisp, but there are a few important incompatibilities between them, in places where Common Lisp involves an incompatible change which is deemed to severe to impose on traditional Zetalisp users. There is a special mode which provides strict Common Lisp compatibility. See common-lisp for more information.
This document is the reference manual for the Zetalisp language. This document is not a tutorial, and it sometimes refers to functions and concepts that are not explained until later in the manual. It is assumed that you have a basic working knowledge of some Lisp dialect; you will be able to figure out the rest of the language from this manual.
There are also facilities explained in this manual that are not really part of the Lisp language. Some of these are subroutine packages of general use, and others are tools used in writing programs. The Lisp Machine window system and the major utility programs are, or ought to be, documented in other manuals.
The manual starts out with an explanation of the language. Chapter object-chapter explains the different primitive types of Lisp object and presents some basic predicate functions for testing types. Chapter evaluator-chapter explains the process of evaluation, which is the heart of the Lisp language. Chapter flow-chapter introduces the basic Lisp control structures.
The next several chapters explain the details of the various primitive data-types of the language and the functions that deal with them. Chapter cons-chapter deals with conses and the higher-level structures that can be built out of them, such as trees, lists, association lists, and property lists. Chapter symbol-chapter deals with symbols, chapter number-chapter with the various kinds of numbers, and chapter array-chapter with arrays. Chapter string-chapter explains character strings, which are a special kind of array.
After this there are some chapters that explain more about functions, function-calling, and related matters. Chapter function-chapter presents all the kinds of functions in the language, explains function-specs, and tells how to manipulate definitions of functions. Chapters closure-chapter and stack-group-chapter discuss closures and stack-groups, two facilities useful for creating coroutines and other advanced control and access structures.
Next, a few lower-level issues are dealt with. Chapter locative-chapter explains locatives, which are a kind of pointer to memory cells. Chapter subprimitive-chapter explains the “subprimitive” functions, which are primarily useful for implementation of the Lisp language itself and the Lisp Machine’s operating system. Chapter area-chapter discusses areas, which give you control over storage allocation and locality of reference.
Chapter compiler-chapter discusses the Lisp compiler, which converts Lisp programs into “machine language” or “macrocode”. Chapter macros-chapter explains the Lisp macro facility, which allows users to write their own extensions to Lisp, extending both the interpreter and the compiler. The next two chapters go into detail about two such extensions, one that provides a powerful iteration control structure (chapter loop-chapter), and one that provides a powerful data structure facility (chapter defstruct-chapter).
Chapter flavor-chapter documents flavors, a language facility to provide generic functions using the paradigm used in Smalltalk and related languages, called “object-oriented programming” or “message passing”. Flavors are widely used by the system programs of the Lisp Machine, as well as being available to the user as a language feature.
The next few chapters discuss I/O: chapter io-chapter explains I/O streams and character and line level operations; chapter expression-io-chapter explains reading and printing symbolic expressions; chapter pathname-chapter explains naming of files; chapter file-io-chapter explains input and output to files. Chapter chaos-chapter describes the use of the Chaosnet.
Chapter package-chapter describes the package system, which allows many name spaces within a single Lisp environment. Chapter system-chapter documents the “system” facility that helps you create and maintain systems, which are programs that reside in many files.
Chapter process-chapter discusses the facilities for multiple processes and how to write programs that use concurrent computation. Chapter error-chapter explains how exceptional conditions (errors) can be handled by programs, handled by users, and debugged. Chapter code-chapter explains the instruction set of the Lisp Machine and tells you how to examine the output of the compiler. Chapter query-chapter documents some functions for querying the user, chapter time-chapter explains some functions for manipulating dates and times, and chapter misc-chapter contains other miscellaneous functions and facilities.
There are several conventions of notation and various points that should be understood before reading the manual. This section explains those conventions.
The symbol ‘=>’ is used to indicate evaluation in
examples. Thus, when you see ‘foo
=> nil
’, this means that
“the result of evaluating foo
is (or would have
been) nil
”.
The symbol ‘==>’ is used to indicate macro expansion
in examples. This, when you see ‘(foo bar)
==> (aref bar 0)
’,
this means that “the result of macro-expanding (foo bar)
is (or would have been) (aref bar 0)
”.
A typical description of a Lisp function looks like this:
The function-name
function adds together arg1 and arg2,
and then multiplies the result by arg3. If arg3 is not provided,
the multiplication isn’t done. function-name
then returns a list
whose first element is this result and whose second element is arg4.
Examples:
(function-name 3 4) => (7 4) (function-name 1 2 2 'bar) => (6 bar)
Note the use of fonts (typefaces). The name of the function is
in bold-face in the first line of the description, and the arguments are
in italics. Within the text, printed representations of Lisp objects
are in a different bold-face font, as in (+ foo 56)
, and argument
references are italicized, as in arg1 and arg2. A different,
fixed-width font, as in function-name
, is used for Lisp examples
that are set off from the text. Other font conventions are that
filenames are in bold-face, all upper case (as in SYS: SYS; SYSDCL
LISP
) while keys on the keyboard are in bold-face and capitalized
(as in Help
, Return
and Meta
).
‘Car’, ‘cdr’ and ‘cons’ are in bold-face when the actual Lisp objects are being mentioned, but in the normal text font when used as words.
The word ‘&optional’ in the list of arguments tells you that all
of the arguments past this point are optional. The default value can be
specified explicitly, as with arg4 whose default value is the result
of evaluating the form (foo 3)
. If no default value is specified,
it is the symbol nil
. This syntax is used in lambda-lists in the
language, which are explained in lambda-list. Argument lists may
also contain ‘&rest’ and ‘&key’ to indicate rest and keyword arguments.
The descriptions of special forms and macros look like this:
This evaluates form three times and returns the result of the third evaluation.
This evaluates the forms with the symbol foo
bound to nil
.
It expands as follows:
(with-foo-bound-to-nil form1 form2 ...) ==> (let ((foo nil)) form1 form2 ...)
Since special forms and macros are the mechanism by which the syntax of Lisp
is extended, their descriptions must describe both their syntax and their
semantics; functions follow a simple consistent set of rules, but each
special form is idiosyncratic. The syntax is displayed on the first line
of the description using the following conventions. Italicized words are
names of parts of the form which are referred to in the descriptive text.
They are not arguments, even though they resemble the italicized words in
the first line of a function description. Parentheses (‘(
’ and ‘)
’) stand for themselves.
Square brackets (‘[
’ and `]
’) indicate that what they enclose is optional.
Ellipses (‘...
’) indicate that the subform (italicized word or parenthesized
list) that precedes them may be repeated any number of times (possibly no times at all).
Curly brackets followed by ellipses (‘{
’ and ‘}...
’) indicate that what they
enclose may be repeated any number of times. Thus the first line of the
description of a special form is a “template” for what an instance of that
special form would look like, with the surrounding parentheses removed.
The syntax of some special forms is sufficiently complicated
that it does not fit comfortably into this style; the first line of the
description of such a special form contains only the name, and the syntax is
given by example in the body of the description.
The semantics of a special form includes not only what it “does for a living”, but also which subforms are evaluated and what the returned value is. Usually this will be clarified with one or more examples.
A convention used by many special forms is that all of their subforms after
the first few are described as ‘body...
’. This means that the remaining
subforms constitute the “body” of this special form; they are Lisp forms that
are evaluated one after another in some environment established by the special
form.
This ridiculous special form exhibits all of the syntactic features:
This twiddles the parameters of frob, which defaults to default-frob
if not specified. Each parameter is the name of one of the adjustable parameters of
a frob; each value is what value to set that parameter to. Any number
of parameter/value pairs may be specified. If any options are specified,
they are keywords that select which safety checks to override while twiddling
the parameters. If neither frob nor any options are specified, the
list of them may be omitted and the form may begin directly with the first
parameter name.
frob and the values are evaluated; the parameters and options are syntactic keywords and not evaluated. The returned value is the frob whose parameters were adjusted. An error is signaled if any safety checks are violated.
Operations, the message-passing equivalent of ordinary Lisp’s functions, are described in this style:
flavor-name
: :operation-name arg1 arg2 &optional arg3 ¶This is the documentation of the effect of performing operation
:operation-name
(or, sending a message named :operation-name
),
with arguments arg1, arg2, and arg3, on an instance of
flavor flavor-name
.
Descriptions of variables (“globally special” variables) look like this:
The variable typical-variable
has a typical value....
If the description says ‘Constant’ rather than ‘Variable’, it means that the value is never set by the system and should not be set by you. In some cases the value is an array or other structure whose contents may be changed by the system or by you.
Most numbers in this manual are decimal; octal numbers are
labelled as such, using #o
if they appear in examples. Currently
the default radix for the Lisp Machine system is eight, but this will be
changed in the near future. If you wish to change to base ten now, see
the documentation on the variables *read-base*
and *print-base*
(*read-base*-var).
All uses of the phrase ‘Lisp reader’, unless further qualified,
refer to the part of Lisp that reads characters from I/O streams
(the read
function), and not the person reading this manual.
There are several terms that are used widely in other references on Lisp, but are not used much in this document since they have become largely obsolete and misleading. For the benefit of those who may have seen them before, they are: ‘s-expression’, which means a Lisp object; ‘dotted pair’, which means a cons; and ‘atom’, which means, roughly, symbols and numbers and sometimes other things, but not conses. The terms ‘list’ and ‘tree’ are defined in list-and-tree.
The characters acute accent ('
) (also called "single quote") and
semicolon (‘;
’) have special meanings when typed to Lisp; they are
examples of what are called macro characters. Though the
mechanism of macro characters is not of immediate interest to the new
user, it is important to understand the effect of these two, which are
used in the examples.
When the Lisp reader encounters a "'
", it reads in the next
Lisp object and encloses it in a quote
special form. That
is, 'foo-symbol
turns into (quote foo-symbol)
, and '(cons 'a 'b)
turns into (quote (cons (quote a) (quote b)))
. The reason
for this is that quote
would otherwise have to be typed in very
frequently, and would look ugly.
The semicolon is used as a commenting character. When the
Lisp reader sees one, the remainder of the line is
discarded.
The character ‘/
’ is used for quoting strange characters so
that they are not interpreted in their usual way by the Lisp reader,
but rather are treated the way normal alphabetic characters are treated.
So, for example, in order to give a ‘/
’ to the reader, you must type ‘//
’,
the first ‘/
’ quoting the second one. When a character
is preceded by a ‘/
’ it is said to be escaped. Escaping
also turns off the effects of macro characters such as "'
" and ‘;
’.
If you select Common Lisp syntax, escaping is done with ‘\
’ instead,
and ‘/
’ has no special syntactic significance.
The manual uses traditional syntax throughout, however.
The following characters also have special meanings
and may not be used in symbols without escaping. These characters
are explained in detail in the section on printed representation
(reader).
"
Double-quote delimits character strings.
#
Sharp-sign introduces miscellaneous reader macros.
`
Backquote is used to construct list structure.
,
Comma is used in conjunction with backquote.
:
Colon is the package prefix.
|
Characters between pairs of vertical-bars are escaped.
circleX
Circle-cross lets you type in characters using their octal codes.
All Lisp code in this manual is written in lower case. In fact, the reader turns all symbols into upper case, and consequently everything prints out in upper case. You may write programs in whichever case you prefer.
You will see various symbols that have the colon (:
)
character in their names. The colon and the characters preceding it
are not actually part of the symbol name, but in early stages of
learning the system you can pretend that they are. Actually they
are a package prefix. See chapter package-chapter for an explanation
of packages and what package prefixes really do.
Symbols whose names start with si:
are internal to the
system. These functions and variables are documented here because they
are things you sometimes need to know about. However, they are subject
to change with little concern for compatibility for users.
Zetalisp is descended from Maclisp, and a good deal of effort was expended to try to allow Maclisp programs to run in Zetalisp. Throughout the manual, there are notes about differences between the dialects. For the new user, it is important to note that many functions herein exist solely for Maclisp compatibility; they should not be used in new programs. Such functions are clearly marked in the text.
The Lisp Machine character set is not quite the same as that
used on I.T.S nor on Multics; it is described in full detail in
character-set. The important thing to note for now is that the
character “newline” is the same as Return
, and is represented by the
number 215 octal. (This number should not be built into any
programs.)
When the text speaks of “typing Control-Q
” (for example),
this means to hold down the Control
key on the keyboard (either of
the two keys labeled ‘CTRL’), and, while holding it down, to strike the
Q
key. Similarly, to type Meta-P
, hold down either of the
Meta
keys and strike P
. To type Control-Meta-T
hold down
both Control
and Meta
. Unlike ASCII, the Lisp machine character
set does not simply label a few of the characters as “control
characters”; Control
and Meta
(and Super
and Hyper
) are
modifiers that can be attached to any character and are represented as
separate bits. These
modifier bits are not present in characters in strings or files.
Many of the functions refer to “areas”. The area feature is of interest only to writers of large systems and can be safely disregarded by the casual user. It is described in chapter area-chapter.
Common Lisp is the name of a standardization project whose goal was to establish a compatible subset for Lisp systems descended from Maclisp.
Originally it was hoped that Zetalisp and the Lisp Machine system could be changed to become a superset of Common Lisp; but this proved impossible because the final Common Lisp design includes several incompatible changes to widely used functions, which, while of no fundamental importance, would make most user programs fail to work. Therefore it was necessary to make Common Lisp a separate mode of operation. The incompatibilities fall into two classes:
*
Read syntax: Common Lisp specifies ‘\
’ as the single-character escape
character rather than the traditional ‘/
’. A few other constructs,
such as character objects and complex numbers, are also written incompatibly.
*
Specific functions: many Lisp functions of ancient pedigree, including
member
, assoc
, subst
, union
, terpri
, close
and //
are specified to be incompatible with their traditional behavior.
The read syntax incompatibilities have been dealt with by having separate
readtables for traditional and Common Lisp syntax. The
incompatibilities in functions have been dealt with by means of reader
symbol substitutions. For each function changed incompatibly, such as
member
, a new, distinct symbol exists in a package called cli
(“Common Lisp Incompatible”); for example, cli:member
. The function
definition of the symbol member
is the traditional definition, while
that of cli:member
is the Common Lisp definition. In Common Lisp
programs, the reader is directed to replace member
with
cli:member
wherever it is seen. So traditional and Common Lisp
programs both get the member
functions they expect. Programs
written in traditional syntax can refer to the new cli
functions
with explicit cli:
package prefixes. Programs written in Common Lisp
syntax can refer to the traditional symbols with explicit global:
package prefixes, but this is not expected to be necessary in code.
The symbol replacements are under control of the current readtable,
so that the Common Lisp readtable is responsible for causing
cli:close
to replace close
and so on.
In this manual, the incompatible Common Lisp functions are documented
under names starting with cli:
, the names by which a traditional
program could refer to them. Keep in mind that, in Common Lisp programs,
the cli:
would be omitted. A list of symbols which
have incompatible Common Lisp substitutes can be found by looking up
cli:
in the function and variable indices.
Traditional read syntax is used nearly everywhere in the manual.
This includes the use of ‘/
’ as an escape character, the escaping of
‘/
’ itself, and not escaping the character ‘\
’, which in traditional
syntax is not special. It is up to the user to make appropriate
modifications to express the same Lisp object in Common Lisp syntax when
necessary.
The majority of Common Lisp changes, those that are upward compatible, have been incorporated directly into Zetalisp and are documented in this manual with no special notice.
Common Lisp read syntax and function definitions may be used either in files or interactively.
For listen loops, including Lisp Listener windows, break loops and the
debugger, the choice of syntax and function semantics is made by setting the
variable readtable
to the appropriate readtable (see si:common-lisp-readtable-var)
or most simply by calling the function common-lisp
.
If flag is t
, selects Common Lisp syntax and function definitions.
If flag is nil
, selects traditional syntax and function definitions.
In either case, this controls the reading of the following expressions that
you type in the same process. It works by setting readtable
.
In a file, Common Lisp is requested by writing the attribute
Readtable: Common-Lisp;
in the -*-
file’s line. This controls
both loading or compiling the file and evaluation or compilation in the
editor while visiting the file. Readtable: Traditional;
specifies
the use of traditional syntax and function definitions. If neither
attribute is present, the file is processed using whatever syntax is
selected in the process that loads it. See file-attribute-list.
Reading and printing done by programs are controlled by the same things
that control reading of programs. They can also be controlled explicitly
by binding the variable readtable
.
This section enumerates some of the various different primitive types of objects in Zetalisp. The types explained below include symbols, conses, various types of numbers, two kinds of compiled code objects, locatives, arrays, stack groups, and closures.
A symbol (these are sometimes called “atoms” or “atomic symbols” by other texts) has a print name, a value, a definition, a property list, and a package.
The print name is a string, which may be obtained by the
function symbol-name
(symbol-name-fun). This string serves as the
printed representation (see printer) of the symbol.
Each symbol
has a value, which may be any
Lisp object. This is the value of the symbol when regarded as a dynamic variable.
It is also referred to sometimes as the “contents of the
value cell”, since internally every symbol has a cell called the value
cell, which holds the value. It is accessed by the symeval
function (symeval-fun), and updated by the set
function
(set-fun). (That is, given a symbol, you use symeval
to find out
what its value is, and use set
to change its value.)
Each
symbol has a definition, which may also be any Lisp object. It is
also referred to as the “contents of the function cell”, since
internally every symbol has a cell called the function cell, which
holds the definition. The definition can be accessed by the
fsymeval
function (fsymeval-fun), and updated with fset
(fset-fun), although usually the functions fdefinition
and
fdefine
are employed (fdefine-fun).
The property list is a list of an even number of
elements; it can be accessed directly by plist
(plist-fun), and
updated directly by setplist
(setplist-fun), although usually the
functions get
, putprop
, and remprop
(get-fun) are used.
The property list is used to associate any number of additional
attributes with a symbol–attributes not used frequently enough to
deserve their own cells as the value and definition do.
Symbols also have a package cell, which indicates which package of names the symbol belongs to. This is explained further in the section on packages (chapter package-chapter) and can be disregarded by the casual user.
The primitive function for creating symbols is
make-symbol
(make-symbol-fun), although most symbols
are created by read
, intern
, or
fasload
(which call make-symbol
themselves.)
A cons is an object that cares about two
other objects, arbitrarily named the car and the cdr.
These objects can be accessed with car
and cdr
(car-fun), and updated
with rplaca
and rplacd
(rplaca-fun). The primitive function for creating
conses is cons
(cons-fun).
There are several kinds of numbers in Zetalisp. Fixnums represent integers in the range of -2^24 to 2^24-1. Bignums represent integers of arbitrary size, but they are more expensive to use than fixnums because they occupy storage and are slower. The system automatically converts between fixnums and bignums as required. Floats are floating-point numbers. Short floats are another kind of floating-point numbers, with less range and precision, but less computational overhead. Ratios are exact rational numbers that are represented with a numerator and a denominator, which are integers. Complexnums are numbers that have explicitly represented real and imaginary parts, which can be any real numbers of the same type. See number for full details of these types and the conversions between them.
A character object is much like a fixnum except that its type is distinguishable. Common Lisp programs use character objects to represent characters. Traditional programs usually use fixnums to represent characters, although they can create an manipulate character objects when they desire. Character objects behave like fixnums when used in arithmetic; only a few operations make any distinction. They do, however, print distinctively. See characters for more information.
The usual form of compiled, executable code is a Lisp object, called a “Function Entry Frame” or “FEF” for historical reasons. A FEF contains the code for one function. This is analogous to what Maclisp calls a “subr pointer”. FEFs are produced by the Lisp Compiler (compiler), and are usually found as the definitions of symbols. The printed representation of a FEF includes its name so that it can be identified. Another kind of Lisp object that represents executable code is a “microcode entry”. These are the microcoded primitive functions of the Lisp system, and any user functions compiled into microcode.
About the only useful thing to do with any of these compiled code objects
is to apply it to arguments. However, some functions are
provided for examining such objects, for user convenience. See
arglist
(arglist-fun),
args-info
(args-info-fun),
describe
(describe-fun),
and disassemble
(disassemble-fun).
A locative (see locative) is a kind of a pointer to a single memory cell
anywhere in the system. The contents of this cell can be accessed by cdr
(see cdr-fun) and updated by rplacd
(see rplacd-fun).
An array (see array) is a set of cells indexed by a tuple of integer subscripts. The contents of the cells may be accessed and changed individually. There are several types of arrays. Some have cells that may contain any object, while others (numeric arrays) may only contain small positive numbers. Strings are a type of array; the elements are character objects.
A list is not a primitive data type, but rather a data structure
made up out of conses and the symbol nil
. See list-and-tree.
A predicate is a function that tests for some condition involving
its arguments and returns the symbol t
if the condition is true, or
the symbol nil
if it is not true. The following predicates are for
testing what data type an object has.
By convention, the names of predicates usually end in the letter ‘p’ (which stands for ‘predicate’).
The following predicates are for testing data types. These predicates
return t
if the argument is of the type indicated by the name of the function,
nil
if it is of some other type.
t
if object is a symbol, otherwise nil
.
nil
if object is a symbol, otherwise t
.
t
if object is a cons, otherwise nil
.
Note that this means (listp nil)
is nil
even though nil
is the empty list.
[This may be changed in the future to work like cli:listp
.
Since the current definition of listp
is identical to that of consp
,
all uses of listp
should be changed to consp
unless the
treatment of nil
is not of concern.]
The Common Lisp version of listp
returns t
if object
is nil
or a cons.
t
if object is anything besides a cons,
otherwise nil
. (nlistp nil)
returns t
.
[This may be changed in the future, if and when listp
is changed.
Since the current definition of nlistp
is identical to that of atom
,
all uses of nlistp
should be changed to atom
unless the
treatment of nil
is not of concern.]
t
if object is not a cons,
otherwise nil
. This is the same as (not (consp object))
.
t
if object is a cons, otherwise nil
. At the
moment, this is the same as listp
; but while listp
may be
changed, consp
will never be true of nil
.
t
if object is any kind of number,
otherwise nil
.
Return t
if object is a representation of an integer, i.e a
fixnum or a bignum, otherwise nil
.
t
if object is a floating-point number,
i.e a full-size or short float, otherwise nil
.
t
if object is a fixnum, otherwise nil
.
t
if object is a bignum, otherwise nil
.
t
if object is a full-size float, otherwise nil
.
t
if object is a short float, otherwise nil
.
t
if object is an exact representation of a rational number;
that is, if it is a fixnum, a bignum or a ratio. Otherwise nil
.
t
if object is a complexnum, a number explicitly
represented as complex. Otherwise nil
.
t
if object is a number whose value is real,
otherwise nil
. Any fixnum, bignum, float (of either format) or
ratio satisfies this predicate. So does a complexnum whose imaginary
part is zero.
t
if object is a character object, otherwise nil
.
t
if object is a string, otherwise nil
.
t
if object is an array, otherwise nil
.
Note that strings are arrays.
t
if object is an array of rank 1.
t
if object is an array of rank 1 that allows only 0 and 1 as elements.
t
if object is an array of rank 1, with no fill pointer and not displaced,
that can have any Lisp object as an element.
t
if object is an array of rank 1, with no fill pointer and not displaced,
that allows only 0 and 1 as elements.
t
if object is a string with no fill pointer and not displaced.
t
if object is a function (essentially, something
that is acceptable as the first argument to apply
), otherwise nil
.
In addition to interpreted, compiled, and microcoded functions, functionp
is true of closures, select-methods (see select-method), and symbols whose function
definition is functionp
.
functionp
is not true of objects that can be called as functions but
are not normally thought of as functions: arrays, stack groups,
entities, and instances. As a special case, functionp
of a symbol
whose function definition is an array returns t
, because in this
case the array is being used as a function rather than as an object.
If allow-special-forms is specified and non-nil
, then
functionp
will be true of macros and special-form functions (those
with quoted arguments). Normally functionp
returns nil
for
these since they do not behave like functions.
t
if object is any compiled code object, otherwise nil
.
The name subrp
is for Maclisp compatibility.
t
if symbol is defined as a function that takes some
unevaluated args. Macros do not count as special forms.
macro-function
can be used to test whether a symbol is defined as a
macro, but you must be careful because it also returns a non-nil
value
for certain special forms. See the definition macro-function
(macro-function-fun) to find out how to do this properly.
t
if object is a closure, otherwise nil
.
t
if object is an entity, otherwise nil
.
See entity for information about entities.
t
if object is a locative, otherwise nil
.
t
if object is of a type that Common Lisp defines operations on.
See the type specifier common
(common-type-spec).
Other standard type predicates include packagep
(see packagep-fun),
random-state-p
(see random-state-p-fun), hash-table-p
(hash-table-p-fun), pathnamep
(pathnamep-fun),
streamp
(streamp-fun) and readtablep
(readtablep-fun).
defstruct
can define additional type predicates automatically
(defstruct-predicates).
Data types can be represented symbolically by Lisp objects called type
specifiers. A type specifier describes a class of possible Lisp
objects; the function typep
tells whether a given object matches a
given type specifier.
Built-in type specifiers exist for the actual Lisp Machine data types. The user can define additional type specifiers to represent arbitrary classifications of data. Type specifiers can also be combined into specifiers for more complex types.
Some type specifiers are symbols: for example, number
, cons
,
symbol
, integer
, character
, compiled-function
,
array
, vector
. Their meanings are mostly obvious, but a table
follows below. Type specifiers that are symbols are called simple
type specifiers.
Lists can also be type specifiers. They are usually combinations or
restrictions of other type specifiers. The car of the list is the key
to understanding what it means. An example of a combination is (or
array symbol)
, which matches any array or any symbol. An example of a
restriction type is (integer 0 6)
, which matches only integers
between 0 and 6 (inclusive).
Basic Data Types
cons
non-nil
lists.
symbol
symbols.
array
all arrays, including strings.
number
numbers of all kinds.
instance
all instances of any flavor.
structure
named structures of any structure type.
locative
locatives.
closure
closures.
entity
entities.
stack-group
stack groups.
compiled-function
macrocode functions such as the compiler makes.
microcode-function
built-in functions implemented by the microcode.
select
select-method functions (defined by defselect
or defselect-incremental
).
character
character objects.
Other Useful Simple Types
t
all Lisp objects belongs to this type.
nil
nothing belongs to this type.
string-char
characters that can go in strings.
standard-char
characters defined by Common Lisp.
These are the 95 ASCII printing characters (including Space
),
together with Return
.
null
nil
is
the only object that belongs to type null
.
list
lists, including nil
. This type is the union of the types null
and cons
.
sequence
lists and vectors. Many Common Lisp functions accept either a list or a vector as a way of describing a sequence of elements.
keyword
keywords (symbols belonging to package keyword
).
atom
anything but conses.
Simple Number Types
integer
fixnums and bignums.
ratio
explicit rational numbers, such as 1\2
(1/2
in Common Lisp syntax).
rational
integers and ratios.
fixnum
small integers, whose %data-type
is dtp-fix
and which occupy no storage.
bignum
larger integers, which occupy storage.
bit
very small integers–only 0
and 1
belong to this type.
float
any floating point number regardless of format.
short-float
short floats
single-float
full-size floats
double-float
long-float
defined by Common Lisp, but on the Lisp Machine synonymous with single-float
.
real
any number whose value is real.
complex
a number explicitly stored as complex. It is possible for such a number to have zero as an imaginary part but only if it is a floating point zero.
noncomplex
a number which is not explicitly stored as complex.
This is a subtype of real
.
Restriction Types for Numbers
(complex type-spec)
complex numbers whose components match type-spec.
Thus, (complex rational)
is the type of complex numbers with
rational components. (complex t)
is equivalent to complex
.
(integer low high)
integers between low and high. low can be:
integer
integer is an inclusive lower limit
(integer)
integer is an exclusive lower limit.
*
There is no lower limit.
high has the same sorts of possibilities.
If high is omitted, it defaults to *
. If both low and high are omitted,
you have (integer)
, which is equivalent to plain integer
. Examples:
(integer 0 *) matches any nonnegative integer. (integer 0) matches any nonnegative integer. (integer -4 3) matches any integer between -4 and 3, inclusive. (integer -4 (4)) matches any integer between -4 and 3, inclusive.
bit
is equivalent to (integer 0 1)
.
(rational low high)
(float low high)
(short-float low high)
(single-float low high)
(double-float low high)
(long-float low high)
(noncomplex low high)
These specify restrictive bounds for the types rational
, float
and so on.
The bounds work on these types just the way they do on integer
.
Exclusive and inclusive bounds make a useful difference here:
(float (-4) (3)) matches any float between -4 and 3, exclusive.
No possible inclusive bounds could provide the same effect.
(mod high)
nonnegative integers less than high. high should be an integer.
(mod)
, (mod *)
and plain mod
are allowed, but are equivalent
to (integer 0)
.
(signed-byte size)
integers that fit into a byte of size bits, of which one bit is the sign bit.
(signed-byte 4)
is equivalent to (integer -8 7)
.
(signed-byte *)
and plain signed-byte
are equivalent to integer
.
(unsigned-byte size)
nonnegative integers that fit into a byte of size bits, with no sign bit.
(unsigned-byte 3)
is equivalent to (integer 0 7)
.
(unsigned-byte *)
and plain unsigned-byte
are equivalent to (integer 0)
.
Simple Types for Arrays
array
all arrays.
simple-array
arrays that are not displaced and have no fill pointers. (Displaced arrays are defined in displaced-array and fill pointers on fill-pointer).
vector
arrays of rank one.
bit-vector
art-1b
arrays of rank one.
string
strings; art-string
and art-fat-string
arrays of rank one.
simple-bit-vector
bit vectors that are simple arrays.
simple-string
strings that are simple arrays.
simple-vector
simple-arrays of rank one, whose elements’ types are unrestricted.
This is not the same as (and vector simple-array)
!
Restriction Types for Arrays
(array element-type dimensions)
arrays whose rank and dimensions fit the restrictions described by dimensions and whose nature restricts possible elements to match element-type.
The array elements condition has nothing to do with the actual values of the elements. Rather, it is a question of whether the array’s own type permits exactly such elements as would match element-type. If anything could be stored in the array that would not match element-type, then the array does not match. If anything that would match element-type could not be stored in the array, then the array does not match.
For example, if element-type is (signed-byte 4)
, the array must
be an art-4b
array. An art-1b
array will not do, even though
its elements all do match (signed-byte 4)
, because some objects such
as the number 12 match (signed-byte 4)
but could not be stored in an
art-1b
array. Likewise an art-q
array whose elements all happen
to match (signed-byte 4)
will not do, since new elements such as
nil
or 231 which fail to match could potentially be stored in the
array.
If element-type is t
, the type to which all objects belong,
then the array must be one in which any object can be stored:
art-q
or art-q-list
.
*
as element-type means “no restriction”. Any type of
array is then allowed, whether it restricts its elements or not.
dimensions can be *
, an integer or a list.
If it is *
, the rank and dimensions are not restricted.
If it is an integer, it specifies the rank of the array.
Then any array of that rank matches.
If dimensions is a list, its length specifies the rank, and each element of dimensions restricts one dimension. If the element is an integer, that dimension’s length must equal it. If the element is *, that dimension’s length is not restricted.
(simple-array element-type dimensions)
the restrictions work as in (array element-type dimensions)
,
but in addition the array must be a simple array.
(vector element-type size)
element-type works as above. The array must be a vector. size must be an integer or *; if it is an integer, the array’s length must equal size.
(bit-vector size)
(simple-vector size)
(simple-bit-vector size)
(string size)
(simple-string size)
These require the array to match type bit-vector
, simple-vector
, etc.
This implicitly restricts the element type, so there is no point
in allowing an element-type to be given in the type specifier.
size works as in vector
.
More Obscure Types
package
packages, such as find-package
might return.
readtable
structures such as can be the value of readtable
.
pathname
pathnames (instances of the flavor pathname
).
hash-table
hash-tables (instances of the flavor hash-table
).
flavor-name
instances of that flavor, or of any flavor that contains it.
defstruct-name
named structures of that type, or of any structure that includes
that one using :include
.
Common Lisp Compatibility Types
random-state
random-states. See random
(random-fun).
This is actually a special case of using a defstruct name
as a type specifier, but it is mentioned specifically because
Common Lisp defines this type.
common
All objects of types defined by Common Lisp. This is all Lisp objects
except closures, entities, stack groups, locatives, instances,
select-methods, and compiled and microcode functions. (A few kinds
of instances, such as pathnames, are common
, because Common Lisp does
define how to manipulate pathnames, and it is considered irrelevant that
the Lisp Machine happens to implement pathnames using instances.)
stream
Anything that looks like it might be a valid I/O stream. It is impossible to tell for certain whether an object is a stream, since any function with proper behavior may be used as a stream. Therefore, use of this type specifier is discouraged. It exists for the sake of Common Lisp.
Combination Type Specifiers
(member objects)
any one of objects, as compared with eql
.
Thus, (member t nil x)
is matched only by
t
, nil
or x
.
(satisfies predicate)
objects on which the function predicate returns a non-nil
value.
Thus, (satisfies numberp)
is equivalent
as a type specifier to number
(though the system could not tell that this is so).
predicate must be a symbol, not a lambda
-expression.
(and type-specs...)
objecs that match all of the type-specs individually. Thus, (and
integer (satisfies oddp))
is the type of odd integers.
(or type-specs...)
objects that match at least one of the type-specs individually.
Thus, (or number array)
includes all numbers and all arrays.
(not type-spec)
objects that do not match type-spec.
Defines type-name as a type specifier by providing code to expand it into another type specifier–a sort of type specifier macro.
When a list starting with type-name is encountered as a type
specifier, the lambda-list is matched against the cdr of the type
specifier just as the lambda-list of an ordinary defmacro
-defined
macro is matched against the cdr of a form. Then the body is
executed and should return a new type specifier to be used instead of
the original one.
If there are optional arguments in lambda-list for which no default value
is specified, they get *
as a default value.
If type-name by itself is encountered as a type specifier, it is
treated as if it were (type-name)
; that is to say, the
lambda-list is matched against no arguments and then the body
is executed. So each argument in the lambda-list gets its
default value, and there is an error if they are not all optional.
Example:
(deftype vector (element-type size)
`(array ,element-type (,size)))
could have been used to define vector
.
(deftype odd-natural-number-below (n)
`(and (integer 0 (,n)) (satisfies oddp)))
(typep 5 '(odd-natural-number-below 6)) => t
(typep 7 '(odd-natural-number-below 6)) => nil
Returns a type specifier which object matches.
Any given object matches many different type specifiers,
including t
, so you should not attempt to rely on knowing
which type specifier would be returned for any particular object.
The one actually returned is chosen so as to be informative
for a human. Programs should generally use typep
rather than type-of
.
See also data-type
, data-type-fun.
t
if object matches type-spec. The fundamental
purpose of type specifiers is to be used in typep
or other
functions and constructs that use typep
. Examples:
(typep 5 'number) => t (typep 5 '(integer 0 7)) => t (typep 5 'bit) => nil (typep 5 'array) => nil (typep "foo" 'array) => t (typep nil 'list) => t (typep '(a b) 'list) => t (typep 'lose 'list) => nil (typep 'x '(or symbol number)) => t (typep 5 '(or symbol number)) => t
If the value of type-spec is known at compile time, the compiler
optimizes typep
so that it does not decode the argument at run
time.
In Maclisp, typep
is used with one argument. It returns a symbol
describing the type of the object it is given. This is somewhat like
what type-of
does, except in Maclisp the intention was to compare
the result with eq
to test the type of an object. The Lisp Machine
supports this usage of typep
for compatibility, but the returned
symbol is a keyword (such as :list
, for conses) which makes it
actually incompatible. This usage is considered obsolete and should
be removed from programs.
Computes the value of key-form and then executes one (or none) of the clauses according to the type of the value (call it key).
Each clause starts with a type specifier, not evaluated, which
could be the second argument to typep
. In fact, that is how it is used.
The rest of the clause is composed of forms. The type specifiers of the
clauses are matched sequentially against key. If there is a match,
the rest of that clause is executed and the values of the last form in it
are returned from the typecase
form. If no clause matches,
the typecase
form returns nil
.
typecase
, like typep
is optimized carefully by the compiler.
Note that t
, the type specifier that matches all objects, is useful
in the last clause of a typecase
. otherwise
is also permitted
instead of t
by special dispensation, with the same meaning.
Example:
(typecase foo (symbol (get-pname foo)) (string foo) (list (apply 'string-append (mapcar 'hack foo))) ((integer 0) (hack-positive-integer foo)) (t (princ-to-string foo)))
Like typecase
except that an uncorrectable error is signaled if every clause fails.
t
or otherwise
clauses are not allowed.
Like etypecase
except that the error is correctable. The first
argument is called place because it must be setf
’able (see
setf-fun). If the user proceeds from the error, a new value is read
and stored into place; then the clauses are tested again using the
new value. Errors repeat until a value is specified that makes some
clause succeed.
Converts object to an “equivalent” object that matches type-spec. Common Lisp specifies exactly which types can be converted to which other types. In general, a conversion that would lose information, such as turning a float into an integer, is not allowed as a coercion. Here is a complete list of types you can coerce to.
complex
(complex type)
Real numbers can be coerced to complex. If a rational is coerced to
type complex
, the result equals the rational, and is not complex at
all. This is because complex numbers with rational components are
canonicalized to real if possible. However, if a rational is coerced to
(complex float)
or (complex single-float)
then an actual complex
number does result.
It is permissible of course to coerce a complex number to a complex type. The real and imaginary parts are coerced individually to type if type is specified.
short-float
single-float
Rational numbers can be coerced to floating point numbers and any kind of floating point number can be coerced to any other floating point format.
float
Rational numbers are converted to single-float
’s;
floats of all kinds are left alone.
character
Strings of length one can be coerced to characters. Symbols whose print-names have length one can also be. An integer can be coerced to a character; this results in a character whose character code is the specified integer.
list
Any vector can be coerced to type list
.
The resulting list has the same elements as the vector.
vector
or array
or any restricted array type.
Any sequence (list or vector) can be coerced to any array or vector type. The new array has rank one and the same elements as the original sequence.
If you specify a type of array with restricted element type, you may
actually get an array which can hold other kinds of things as well. For
example, the Lisp Machine does not provide anything of type (array
symbol)
, but if you specify that, you will get an array which at least
can hold symbols (but can hold other things as well). If an element of
the original sequence does not fit in the new array, an error is
signaled.
t
Any object can be coerced to type t
, without change
to the object.
If the value of type-spec is known at compile time, the compiler
optimizes coerce
so that it does not decode the argument at run
time.
Since a type describes a set of possible objects, it is possible to ask whether one type is contained in another type. Another way to say this is, is one type a subtype of another?
t
if type1 is a subtype of type2.
The system cannot always tell whether type1 is a subtype of
type2. When satisfies
type specifiers are in use, this question
is mathematically undecidable. Because of this, it has not been
considered worthwhile to make the system able to answer obscure subtype
questions even when that is theoretically possible. If the answer is
not known, subtypep
returns nil
.
Thus, nil
could mean that type1 is certainly not a subtype of
type2, or it could mean that there is no way to tell whether it is a
subtype. subtypep
returns a second value to distinguish these two
situations: the second value is t
if subtypep
’s first value is
definitive, nil
if the system does not know the answer.
Examples:
(subtypep 'cons 'list) => t t (subtypep 'null 'list) => t t (subtypep 'symbol 'list) => nil t (subtypep 'list 'number) => nil t because not all lists are numbers (in fact, no lists are numbers). (subtypep 'number 'rational) => nil t because not all numbers are rational. (subtypep '(satisfies foo) '(satisfies bar)) => nil nil because the system does not attempt to figure out your code.
The following is a complete description of the actions taken by the evaluator, given a form to evaluate.
If form is a number, the result is form.
If form is a string, the result is form.
If form is a self-evaluating symbol (nil
, t
or a keyword
such as :foo
), then form itself is the result.
If form is any other symbol, the result is the value of form, considered as a variable. If form’s value is void, an error is signaled. The way symbols are bound to values is explained in variable-section below.
If form is not any of the above types, and is not a list, form itself is the result.
In all remaining cases, form is a list. The evaluator
examines the car of the list to figure out what to do next. There are
three possibilities: this form may be a special form, a macro
form, or a plain old function form. If the car is an explicit
function such as a list starting with lambda
, the form is a function
form. If it is a symbol, things depend on the symbol’s function
definition, which may be a special form definition (see
special-function), a macro definition, or an ordinary function.
If form is a special form, then it is handled accordingly; each special form works differently. All of them are documented in this manual. The internal workings of special forms are explained in more detail on special-function, but this hardly ever affects you.
If form is a macro form, then the macro is expanded as explained in chapter macros-chapter.
If form is a function form, it calls for the application of a function to arguments. The car of form is a function or the name of a function. The cdr of form is a list of subforms. The subforms are evaluated, sequentially, and each produces one argument for the function. The function is then applied to those arguments. Whatever results the function returns are the values of the original form.
There is a lot more to be said about evaluation. The way variables
work and the ways in which they are manipulated, including the binding of
arguments, is explained in variable-section. A basic explanation of
functions is in function-section. The way functions can return more
than one value is explained in multiple-value. The description of all
of the kinds of functions, and the means by which they are manipulated, is
in chapter function-chapter. Macros are explained in chapter
macros-chapter. The evalhook
facility, which lets you do something
arbitrary whenever the evaluator is invoked, is explained in
evalhook-section. Special forms are described all over the manual; each
special form is in the section on the facility it is part of.
In Zetalisp, variables are implemented using symbols. Symbols are used for many things in the language, such as naming functions, naming special forms, and being keywords; they are also useful to programs written in Lisp, as parts of data structures. But when a symbol is evaluated, its value as a variable is taken.
There are two different ways of changing the value of a variable. One
is to set the variable. Setting a variable changes its value to a
new Lisp object, and the previous value of the variable is forgotten.
Setting of variables is usually done with the setq
special form.
The other way to change the value of a variable is with binding (also called lambda-binding). We say that a variable is bound (past participle of active verb) by the action of binding; we also say that the variable is bound (state of being) after a binding has been made. When a binding is made, the variable’s old binding and value are hidden or shadowed by a new binding, which holds a new value. Setting a variable places a new value into the current binding; it does not change which binding is current. In addition, shadowed bindings’ values are not affected by setting the variable. Binding a variable does not affect the value in the old current binding but that binding ceases to be current so the value no longer applies.
The action of binding is always followed eventually by the action of unbinding. This discards the current binding of the variable, with its value. The previous binding becomes current again, and the value in it–unchanged since the newer binding was made, in normal operation–is visible again.
Binding is normally done on entry to a function and by certain special forms
(let
, do
, prog
and others). The bindings are unbound
on exit from the function or the special form, even nonlocal exit such
as go
, return
or throw
. The function or special form
is said to be the scope of the bindings made therein.
Here is a simple example of making a binding, shadowing it, unshadowing it, examining it, and unbinding it. The inner, shadowing binding is made, examined, set, examined and unbound.
(let ((a 5)) (print a) ;prints5
(let ((a "foo")) (print a) ;prints"foo"
(setq a "bar") (print a)) ;prints"bar"
(print a)) ;prints5
Every symbol has one binding which was never made and is never unbound.
This is the global binding. This binding is current whenever
no other binding has been established that would shadow it.
If you type (setq x 5)
in the Lisp listen loop, you set
the global binding of x
. Programs often set global bindings
permanently using defvar
or one of its cousins (defvar-fun).
setq-globally
and related functions can be used to set or
refer to the global binding even when it is shadowed (setq-globally-fun).
(defvar a 5) ;sets the global binding
(let ((a t))
(print a)) ;prints t
a => 5 ;the global binding is visible again
A binding does not need to have an actual value. It can be void
instead. The variable is also called void. Actually, a void binding
contains a weird internal value, which the system interprets as meaning
“there is no value here”. (This is the data type code dtp-null
,
dtp-null-var). Reference to a variable whose current binding is void
signals an error. In fact, nearly all variables’ global bindings are
void; only those that you or the system have set are not void.
variable-makunbound
makes the current binding of a variable void
again (variable-makunbound-fun).
‘Void’ used to be called ‘unbound’, and most function names, error messages and documentation still use the term ‘unbound’. The variable is also called ‘unbound’. The term ‘void’ is being adopted because it is less ambiguous. ‘Unbound’ can mean ‘void’, or ‘not bound’ (no binding established), or the past participle of ‘unbind’.
All bindings except global binding have a limited scope: one function or special form. This does not fully specify the scope, however: it may be lexical or dynamic. When a binding has lexical scope, it is visible only from code written within the function or special form that established it. Subroutines called from within the scope, but which are written elsewhere, never see the lexical binding. By contrast, a dynamic binding is visible the whole time it exists (except when it is shadowed, of course), which includes time spent in subroutines called from within the binding construct. The global binding of a symbol can be regarded as a dynamic binding that lasts from the beginning of the session to the end of the session.
Lexical and dynamic bindings are made by the same kinds of function
definitions and special forms. By default, the bindings are lexical.
You request a dynamic binding instead using a special-declaration at
the beginning of the body of the function definition or special form.
Also, some symbols are marked globally special; every binding of
such a symbol is dynamic. This is what defvar
, etc, do to a
symbol. Dynamic bindings are also called special bindings, and the
variable bound is called a special variable. Each use of a symbol
as a variable (this includes setting as well as examining) is also
marked as lexical or dynamic by the same declarations. A dynamic use
sees only dynamic bindings, and a lexical use sees only lexical
bindings.
In the examples above it makes no difference whether the bindings of
a
are lexical or dynamic, because all the code executed between the
binding and unbinding is also written lexically within the let
which made the binding. Here is an example where it makes a difference:
(defun foo () (print a)) (let ((a 5)) (foo)) >>Error: the variable A is used free but not special.
If the intention is that 5 be printed, a dynamic binding is required.
A dynamic binding would remain visible for all the execution from the
entry to the let
to the exit from the let
, including the execution
of the definition of foo
. Actually, the default is to do lexical binding.
Since the binding of a
is lexical, it is visible only for the evaluation
of expressions written inside the let
, which does not include the body
of foo
. In fact, an error happens when foo
evaluates a
,
since a
there is supposed to be lexical and no lexical binding is
visible. If you compile foo
, you get a compiler warning about a
.
The use of a
inside foo
, not lexically within any binding of a
,
is called free, and a
is called a free variable of foo
.
Free variables are erroneous unless they are special. Strictly speaking,
it is erroneous to type (setq x 5)
at top level in the Lisp listener
if x
has not been made globally special, but this is permitted
as an exception because it is so often useful.
One way to make the example work is to make a
globally special:
(defvar a) (defun foo () (print a)) (let ((a 5)) (foo))
prints 5. The global specialness of a
tells let
to make a dynamic
binding and tells the evaluation of a
in foo
to look for one.
Another way is with declarations at the point of binding and the point of use:
(defun foo () (declare (special a)) (print a)) (let ((a 5)) (declare (special a)) (foo))
A declaration at the point of binding affects only that binding, not other bindings made within it to shadow it. Another way of stating this is that a binding is affected only by a declaration in the construct that makes the binding, not by declarations in surrounding constructs. Thus,
(let ((a 5)) ;this binding is dynamic
(declare (special a))
(let ((a "foo")) ;this binding is lexical
no declaration here
... a ... ;this reference is lexical since
... ; the innermost binding is lexical
(let ()
(declare (special a))
... a ... ;this reference is dynamic, and sees value 5
...))
[Currently, for historical compatibility, bindings are affected by surrounding declarations. However, whenever this makes a difference, the compiler prints a warning to inform the programmer that the declaration should be moved.]
The classical case where dynamic binding is useful is for
parameter variables like *read-base*
:
(let ((*read-base* 16.)) (read))
reads an expression using hexadecimal numbers by default.
*read-base*
is globally special, and the subroutine of read
that reads integers uses *read-base*
free.
Here is an example where lexical bindings are desirable:
(let ((a nil)) (mapatoms (function (lambda (symbol) (push symbol a)))) a)
Because the reference to a
from within the internal function
is lexical, the only binding it can see is the one made by this let
.
mapatoms
cannot interfere by binding a
itself.
Consider: if mapatoms
makes a lexical binding of a
,
it is not visible here because this code is not written inside
the definition of mapatoms
. If mapatoms
makes a dynamic binding
of a
, it is not visible here because the reference to a
is not declared special and therefore sees only lexical bindings.
The fact that function
is used to mark the internal function
is crucial. It causes the lexical environment appropriate for
the function to be combined with the code for the function
in a lexical closure, which is passed to mapatoms
.
The last example shows downward use of lexical closures. Upward use is also possible, in which a function is closed inside a lexical environment and then preserved after the binding construct has been exited.
(defun mycons (a d) (function (lambda (x) (cond ((eq x 'car) a) ((eq x 'cdr) d))))) (defun mycar (x) (funcall x 'car)) (defun mycdr (x) (funcall x 'cdr)) (setq mc (mycons 4 t)) (mycar mc) => 4 (mycdr mc) => t
mycons
returns an object that can be called as a function
with one argument. This object retains a pointer to a lexical
environment that has a binding for a
and a binding for d
.
The function mycons
that made those bindings
has been exited, but this is irrelevant because the bindings were
not dynamic. Since the code of the lambda-expression is lexically
within the body of mycons
, that function can see the lexical bindings
made by mycons
no matter when it is called.
The function returned by mycons
records two values and
can deliver either of them when asked, and is therefore analogous
to a cons cell.
Only lexical bindings are transferred automatically downward and upward,
but dynamic bindings can be used in the same ways if explicitly requested
through the use of the function closure
. See closure for more
information.
Dynamic bindings, including the global binding, are stored (unless
shadowed) in a particular place: the symbol’s value cell.
This is a word at a fixed offset in the symbol itself. When a new
dynamic binding is made, the value in the value cell is saved away
on a stack called the special pdl. The new binding’s value
is placed in the value cell. When the new binding is unbound, the
old binding’s value is copied off of the special pdl, into the
value cell again. The function symeval
examines the
value cell of a symbol chosen at run time; therefore, it sees
the current dynamic binding of the symbol.
Lexical bindings are never stored in the symbol’s value cell. The compiler stores them in fixed slots in stack frames. The interpreter stores them in alists that live in the stack. It should be noted that if the lexical binding is made by compiled code, then all code that ought to see the binding is necessarily also compiled; if the binding is made by interpreted code, then all code that ought to see the binding is necessarily interpreted. Therefore, it is safe for the compiler and interpreter to use completely different techniques for recording lexical bindings.
Lexical binding is the default because the compiler can find with certainty all the places where a lexical binding is used, and usually can use short cuts based on this certainty. For dynamic bindings slow but general code must always be generated.
Here are the constructs used for setting variables.
The setq
special form is used to set the value of a variable or of
many variables. The first value is evaluated, and the first
variable is set to the result. Then the second value is
evaluated, the second variable is set to the result, and so on for
all the variable/value pairs. setq
returns the last value, i.e
the result of the evaluation of its last subform.
Example:
(setq x (+ 3 2 1) y (cons x nil))
x
is set to 6
, y
is set to (6)
, and the setq
form
returns (6)
. Note that the first variable was set before
the second value form was evaluated, allowing that form to use the new value of x
.
A psetq
form is just like a setq
form, except
that the variables are set “in parallel”; first all of the value forms
are evaluated, and then the variables are set to the resulting
values.
Example:
(setq a 1) (setq b 2) (psetq a b b a) a => 2 b => 1
Returns a locative to the cell in which the value of symbol is stored. symbol is an unevaluated argument, so the name of the symbol must appear explicitly in the code.
For a special variable, this is equivalent to
(value-cell-location 'symbol)
For a lexical variable, the place where the value is stored is
a matter decided by the interpreter or the compiler, but in any case
variable-location
nevertheless returns a pointer to it.
In addition, if symbol is a special variable that is closed over,
the value returned is an external value cell, the same as the value of
locate-in-closure
applied to the proper closure and symbol.
This cell always contains the closure binding’s value, which is
current only inside the closure. See external-value-cell.
t
if variable symbol is not void.
It is equivalent to
(location-boundp (variable-location symbol))
symbol is not evaluated.
Makes symbol’s current binding void. It is equivalent to
(location-makunbound (variable-location symbol))
symbol is not evaluated.
Here are the constructs used for binding variables.
Is used to bind some variables to some objects, and evaluate some forms
(the body) in the context of those bindings.
A let
form looks like
(let ((var1 vform1) (var2 vform2) ...) bform1 bform2 ...)
When this form is evaluated, first the vforms (the values) are evaluated. Then the vars are bound to the values returned by the corresponding vforms. Thus the bindings happen in parallel; all the vforms are evaluated before any of the vars are bound. Finally, the bforms (the body) are evaluated sequentially, the old values of the variables are restored, and the result of the last bform is returned.
You may omit the vform from a let
clause, in which case it is as
if the vform were nil
: the variable is bound to nil
.
Furthermore, you may replace the entire clause (the list of the variable
and form) with just the variable, which also means that the variable
gets bound to nil
. Example:
(let ((a (+ 3 3)) (b 'foo) (c) d) ...)
Within the body, a
is bound to 6
, b
is bound to foo
, c
is
bound to nil
, and d
is bound to nil
.
let*
is the same as let
except that the binding is sequential. Each
var is bound to the value of its vform before the next vform
is evaluated. This is useful when the computation of a vform depends on
the value of a variable bound in an earlier vform. Example:
(let* ((a (+ 1 2)) (b (+ a a))) ...)
Within the body, a
is bound to 3
and b
is bound to 6
.
let-if
is a variant of let
in which the binding of variables is conditional.
The let-if
special form, typically written as
(let-if cond ((var-1 val-1) (var-2 val-2)...) body...)
first evaluates the predicate form cond. If the result is non-nil
, the value forms
val-1, val-2, etc are evaluated and then the variables var-1, var-2,
etc are bound to them. If the result is nil
, the
vars and vals are ignored. Finally the body forms are evaluated.
The bindings are always dynamic, and it is the user’s responsibility to put in appropriate declarations so that the body forms consider the variables dynamic.
let-globally
is similar in form to let
(see let-fun). The
difference is that let-globally
does not bind the variables;
instead, it saves the old values and sets the variables, and sets up
an unwind-protect
(see unwind-protect-fun) to set them back. The
important consequence is that, with
let-globally
, when the current stack group (see stack-group)
co-calls some other stack group, the old values of the variables are
not restored. Thus let-globally
makes the new values visible in
all stack groups and processes that don’t bind the variables themselves,
not just in the current stack group. Therefore, let-globally
can be used for communication between stack groups and between processes.
let-globally-if
modifies and restores the variables only if the
value of condition is non-nil
. The body is executed in any case.
Since let-globally
is based on setq
, it makes sense for both
lexical and dynamic variables. But its main application exists
only for dynamic variables.
The globally
in let-globally
does not mean the same thing
as the globally
in setq-globally
and related functions.
progv
is a special form to provide the user with extra control
over binding. It binds a list of variables dynamically to a list of values,
and then evaluates some forms. The lists of variables and values
are computed quantities; this is what makes progv
different from
let
, prog
, and do
.
progv
first evaluates symbol-list and value-list, and then binds each
symbol to the corresponding value. If too few values are supplied, the
remaining symbols’ bindings are made empty. If too many values are
supplied, the excess values are ignored.
After the symbols have been bound to the values, the body forms are
evaluated, and finally the symbols’ bindings are undone.
The result returned is the value of the last form in the body.
Assuming that the variables a
, b
, foo
and bar
are globally special, we can do:
(setq a 'foo b 'bar) (progv (list a b 'b) (list b) (list a b foo bar)) => (foo nil bar nil)
During the evaluation of the body of this progv
, foo
is bound to bar
, bar
is bound to nil
, b
is
bound to nil
, and a
retains its top-level value foo
.
progw
is like progv
except that it has a different way of
deciding which variables to bind and what values to give them. Like
progv
, it always makes dynamic bindings.
First, vars-and-val-forms-form is evaluated. Its value should be a list
that looks like the first subform of a let
:
((var1 val-form-1) (var2 val-form-2) ...)
Each element of this list is processed in turn, by evaluating the val-form and binding the var dynamically to the resulting value. Finally, the body forms are evaluated sequentially, the bindings are undone, and the result of the last form is returned. Note that the bindings are sequential, not parallel.
This is a very unusual special form because of the way the evaluator is
called on the result of an evaluation. progw
is useful mainly for
implementing special forms and for functions part of whose contract is
that they call the interpreter. For an example of the latter, see
sys:*break-bindings*
(sys:*break-bindings*-var); break
implements this by using progw
.
See also %bind
(%bind-fun), which is a
subprimitive that gives you maximal control over binding.
Here are the constructs for defining global variables. Each makes the variable globally special, provides a value, records documentation, and allows the editor to find where all this was done.
defvar
is the recommended way to declare the use of a global variable in a
program. Placed at top level in a file,
(defvar variable initial-value "documentation")
declares variable globally special and records its location in the
file for the sake of the editor so that you can ask to see where the
variable is defined. The documentation string is remembered and
returned if you do (documentation 'variable 'variable)
.
If variable is void, it is initialized to the result of evaluating the form initial-value. initial-value is evaluated only if it is to be used.
If you do not wish to give variable any initial value, use the
symbol :unbound
as the initial-value form. This is treated
specially; no attempt is made to evaluate :unbound
.
Using a documentation string is better than using a comment to describe
the use of the variable, because the documentation string is accessible
to system programs that can show the documentation to you while you are
using the machine. While it is still permissible to omit
initial-value and the documentation string, it is recommended that
you put a documentation string in every defvar
.
defvar
should be used only at top level, never in function
definitions, and only for global variables (those used by more than one
function). (defvar foo 'bar)
is roughly equivalent to
(declare (special foo)) (if (not (boundp 'foo)) (setq foo 'bar))
If defvar
is used in a patch file (see patch-facility)
or is a single form (not a region) evaluated with the editor’s
compile/evaluate from buffer commands,
if there is an initial-value the variable is always set to it
regardless of whether it is void.
defconst
is the same as defvar
except that if an initial value
is given the variable is always set to it regardless of whether it is
already bound. The rationale for this is that defvar
declares a
global variable, whose value is initialized to something but will then
be changed by the functions that use it to maintain some state. On the
other hand, defconst
declares a constant, whose value will be
changed only by changes to the program, never by the operation of
the program as written. defconst
always sets the variable to the
specified value so that if, while developing or debugging the program,
you change your mind about what the constant value should be, and then
you evaluate the defconst
form again, the variable gets the new
value. It is not the intent of defconst
to declare that the
value of variable will never change; for example, defconst
is
not a license to the compiler to build assumptions about the value of
variable into programs being compiled.
As with defvar
, you should include a documentation string in every defconst
.
Defines a true constant. The compiler is permitted to assume it will never change. Therefore, if a function that refers to symbol’s value is compiled, the compiled function may contain value merged into it and may not actually refer to symbol at run time.
You should not change the value of symbol except by
reexecuting the defconstant
with a new value. If you do this,
it is necessary to recompile any compiled functions that refer
to symbol’s value.
This section describes functions which examine or set the global binding of a variable even when it is shadowed and cannot be accessed simply by evaluating the variable or setting it.
The primary use of these functions is for init files to set
variables which are bound by the load
function, such as package
or base
. (setq package (find-package 'foo))
executed from a
file being loaded has no effect beyond the end of loading that file,
since it sets the binding of package
made by load
. However, if
you use setq-globally
instead, the current binding in effect during
loading is actually not changed, but when the load
exits and the
global binding is in effect again, foo
will become the current package.
Sets each symbol’s global binding to the value that follows. The value’s are evaluated but the symbol’s are not.
Sets the global binding of symbol to value.
Makes the global binding of symbol be void.
Returns t
if the global binding of symbol is not void.
Return the value of the global binding of symbol. An error is signaled if the global binding is void.
See also pkg-goto-globally
(pkg-goto-globally-fun), a “globally”
version of pkg-goto
. Note that let-globally
is not analogous
to these functions, as it modifies the current bindings of symbols rather
than their global bindings. This is an unfortunate collision of naming
conventions.
In Lisp, a variable is something that can remember one piece of data. The primary conceptual operations on a variable are to recover that piece of data and to change it. These might be called access and update. The concept of variables named by symbols, explained above, can be generalized to any storage location that can remember one piece of data, no matter how that location is named.
For each kind of generalized variable, there are typically three
functions which implement the conceptual access, update and
locate operations. For example, symeval
accesses a symbol’s
value cell, set
updates it, and value-cell-location
returns the
value cell’s location. array-leader
accesses the contents of an
array leader element, store-array-leader
updates it, and
ap-leader
returns the location of the leader element. car
accesses the car of a cons, rplaca
updates it, and car-location
returns the location of the car.
Rather than thinking of this as two functions, which operate on a storage
location somehow deduced from their arguments, we can shift our point of
view and think of the access function as a name for the storage
location. Thus (symeval 'foo)
is a name for the value of foo
, and
(aref a 105)
is a name for the 105th element of the array a
.
Rather than having to remember the update function associated with each
access function, we adopt a uniform way of updating storage locations named
in this way, using the setf
special form. This is analogous to the
way we use the setq
special form to convert the name of a variable
(which is also a form which accesses it) into a form that updates it.
In fact, setf
is an upward compatible generalization of setq
.
Similarly, the location of the generalized variable can be obtained
using the locf
construct.
setf
is the construct for storing a new value into a generalized variable
which is identified by the form which would obtain the current value of the
variable. For example,
(setf (car x) y)
stores the value of y
into the car of the value of x
.
setf
is particularly useful in combination with structure-accessing
macros, such as those created with defstruct
, because the knowledge of the
representation of the structure is embedded inside the macro, and the programmer
shouldn’t have to know what it is in order to alter an element of the structure.
setf
is actually a macro which expands into the appropriate update
code. It has a database, explained in setf-extension, that
associates from access functions to update functions.
Takes a form called place that accesses something and “inverts” the form to produce a corresponding form to update the thing.
A setf
expands into an update form, which stores the result of evaluating
the form value into the place referenced by the place.
If multiple place‘s and value‘s are specified,
each one specifies an update, and each update is done before
the following updates’ arguments are computed.
Examples:
(setf (array-leader foo 3) 'bar) ==> (store-array-leader 'bar foo 3) (setf a 3) ==> (setq a 3) (setf (plist 'a) '(foo bar)) ==> (setplist 'a '(foo bar)) (setf (aref q 2) 56) ==> (sys:set-aref q 2 56) (setf (cadr w) x) ==> (sys:setcdr (cdr w) x)
The value of a setf
form is always the value stored by
the last update it performs. Thus, (setf (cadr w) x)
is not really the same as (rplaca (cdr w) x)
, because
the setf
returns x
and the rplaca
returns
w
. In fact, the expansion of setf
of cdr
uses
an internal function si:setcdr
which exists specifically
for this purpose.
If place invokes a macro or a substitutable function, then
setf
expands the place and starts over again. This lets you
use setf
together with defstruct
accessor macros.
sys:unknown-setf-reference
: (error
) ¶sys:unknown-locf-reference
: (error
) ¶These are signaled when setf
or locf
does not know how to expand
the place. The :form
operation on the condition instance
returns the access-form.
Stores each value into the corresponding place, with the changes taking effect in parallel. Thus,
(psetf (car x) (cdr x) (cdr x) (car x))
interchanges the car and cdr of x
.
The subforms of the places, and the values, are evaluated in order; thus, in
(psetf (aref a (tyi)) (tyi) (aref b (tyi)) (aref a (tyi)))
the first input character indexes a
, the second is stored, the third
indexes b
, and the fourth indexes a
. The parallel nature of
psetf
implies that, should the first and fourth characters be equal,
the old value of that element of a
is what is stored into the array
b
, rather than the new value which comes from the second character
read.
Sets the first place from the second, the second from the third, and
so on. The last place is not set, so it doesn’t really need to be a
setf
’able place; it can be any form. The value of the shiftf
form is the old value of the first place. Thus,
(shiftf x (car (foo)) b)
evaluates (foo)
, copies the car of that value into x
,
copies b
into the car of that value, then returns the
former value of x
.
Sets the first place from the second, the second from the third, and so on, and sets the last place from the old value of the first place. Thus, the values of the place’s are permuted among the place’s in a cyclic fashion.
With only two place’s, their values are exchanged:
(rotatef (car x) (cdr x))
is equivalent to the psetf
example above.
Exchanges the contents of place1 and place2.
This is a special case of rotatef
.
Increments the value of a generalized variable. (incf ref)
increments
the value of ref by 1. (incf ref amount)
adds amount
to ref and stores the sum back into ref.
The incf
form returns the value after incrementation.
incf
expands into a setf
form, so ref can be anything that
setf
understands as its place.
incf
is defined using define-modify-macro
, define-modify-macro-fun.
Decrements the value of a generalized variable. Just like incf
except that amount (or 1) is subtracted rather than added.
See also push
(push-fun), pop
(pop-fun), pushnew
(pushnew-fun), getf
(getf-fun) and remf
(remf-fun).
Besides the access and update conceptual operations on
generalized variables, there is a third basic operation, which we might call
locate. Given the name of a storage cell, the locate operation
returns the address of that cell as a locative pointer (see
locative). This locative pointer is a first-class Lisp data object
which is a kind of reference to the cell. It can be passed as an
argument to a function which operates on any cell,
regardless of where the cell is found. It can be used to bind the contents
of the cell, just as special variables are bound,
using the %bind
subprimitive (see %bind-fun).
Of course, this can work only on generalized variables whose implementation is really to store their value in a memory cell. A generalized variable with an update operation that encrypts the value and an access operation that decrypts it could not have the locate operation, since the value per se is not actually stored anywhere.
locf
takes a form that accesses some cell, and produces
a corresponding form to create a locative pointer to that cell.
Examples:
(locf (array-leader foo 3)) ==> (ap-leader foo 3) (locf a) ==> (value-cell-location 'a) (locf (plist 'a)) ==> (property-cell-location 'a) (locf (aref q 2)) ==> (aloc q 2)
If place invokes a macro or a substitutable function, then
locf
expands the place and starts over again. This lets you
use locf
together with defstruct
accessor macros.
In the description of evaluation on description-of-evaluation, we said that evaluation of a function form works by applying the function to the results of evaluating the argument subforms. What is a function, and what does it mean to apply it? In Zetalisp there are many kinds of functions, and applying them may do many different kinds of things. For full details, see function-functions. Here we explain the most basic kinds of functions and how they work. In particular, this section explains lambda lists and all their important features.
The simplest kind of user-defined function is the lambda-expression, which is a list that looks like:
(lambda lambda-list body1 body2...)
The first element of the lambda-expression is the symbol lambda
; the
second element is a list called the lambda list, and the rest of the
elements are called the body. The lambda list, in its simplest
form, is just a list of variables. Assuming that this simple form
is being used, here is what happens when a lambda expression is applied
to some arguments. First, the number of arguments and the number of
variables in the lambda list must be the same, or else an error is signaled.
Each variable is bound to the corresponding argument value. Then
the forms of the body are evaluated sequentially. After this, the
bindings are all undone, and the value of the last form in the body is
returned.
This may sound something like the description of let
, above. The
most important difference is that the lambda-expression is not a form at
all; if you try to evaluate a lambda-expression, you get an error because
lambda
is not a defined function. The lambda-expression is a
function, not a form. A let
form gets evaluated, and the
values to which the variables are bound come from the evaluation of some
subforms inside the let
form; a lambda-expression gets applied, and
the values are the arguments to which it is applied.
The variables in the lambda list are sometimes called parameters, by analogy with other languages. Some other terminologies would refer to these as formal parameters, and to arguments as actual parameters.
Lambda lists can have more complex structure than simply being a list of
variables. There are additional features accessible by using certain
keywords (which start with &
) and/or lists as elements of the
lambda list.
The principal weakness of simple lambda lists is that any
function written with one must only take a certain, fixed number of
arguments. As we know, many very useful functions, such as list
,
append
, +
, and so on, accept a varying number of arguments.
Maclisp solved this problem by the use of lexprs and lsubrs,
which were somewhat inelegant since the parameters had to be referred to
by numbers instead of names (e.g (arg 3)
). (For compatibility
reasons, Zetalisp supports lexprs, but they should not be
used in new programs.) Simple lambda lists also require that
arguments be matched with parameters by their position in the
sequence. This makes calls hard to read when there are a great many
arguments. Keyword parameters enable the use of other, more readable styles of call.
In general, a function in Zetalisp has zero or more positional parameters, followed if desired by a single rest parameter, followed by zero or more keyword parameters. The positional parameters may be required or optional, but all the optional parameters must follow all the required ones. The required/optional distinction does not apply to the rest parameter; all keyword parameters are optional.
The caller must provide enough arguments so that each of the required parameters gets bound, but he may provide extra arguments for some of the optional parameters. Also, if there is a rest parameter, he can provide as many extra arguments as he wants, and the rest parameter is bound to a list of all these extras. Optional parameters may have a default-form, which is a form to be evaluated to produce the default value for the parameter if no argument is supplied.
Positional parameters are matched with arguments by the position of the arguments in the argument list. Keyword parameters are matched with their arguments by matching the keyword name; the arguments need not appear in the same order as the parameters. If an optional positional argument is omitted, then no further arguments can be present. Keyword parameters allow the caller to decide independently for each one whether to specify it.
Here is the exact algorithm used to match up the arguments with the parameters:
The first required positional parameter is bound to the first
argument. apply
continues to bind successive required
positional parameters
to the successive arguments. If, during this process, there are no
arguments left but there are still some required parameters which have
not been bound yet, it is an error (“too few arguments”).
After all required parameters are handled, apply
continues with the
optional positional parameters, if any. It binds each successive
parameter to the next argument. If, during this process, there are no
arguments left, each remaining optional parameter’s default-form is
evaluated, and the parameter is bound to it. This is done one parameter
at a time; that is, first one default-form is evaluated, and then the
parameter is bound to it, then the next default-form is evaluated, and
so on. This allows the default for an argument to depend on the
previous argument.
Now, if there are no remaining parameters (rest or keyword), and there are no remaining arguments, we are finished. If there are no more parameters but there are still some arguments remaining, an error is signaled (“too many arguments”). If parameters remain, all the remaining arguments are used for both the rest parameter, if any, and the keyword parameters.
If there is a rest parameter, it is bound to a list of all
the remaining arguments. If there are no
remaining arguments, it is bound to nil
.
If there are keyword parameters, the same remaining arguments are
used to bind them, as follows.
The arguments for the keyword parameters are treated as a list
of alternating keyword symbols and associated values. Each symbol is
matched with eq
against the allowed parameter keywords, which have
by default the same names as the parameters but in the keyword
package. (You can specify the keyword symbol explicitly in the lambda
list if you must; see below.) Often the symbol arguments are constants
in the program, and it is convenient for this usage that keywords all
evaluate to themselves, but it is permissible for them to be computed by
expressions.
If any keyword parameter has not received a value when all the
arguments have been processed, the default-form for the parameter is
evaluated and the parameter is bound to its value. All keyword
parameters are optional.
There may be a keyword symbol among the arguments which does not
match any keyword parameter name. By default this is an error, but the
lambda list can specify that there should be no error using
&allow-other-keys
. Also, if one of the keyword symbols among the
arguments is :allow-other-keys
and the value that follows it is
non-nil
then there is no error. When there is no error, for either
reason, the non-matching symbols and their associated values are simply
ignored. The function can access these symbols and values through the
rest parameter, if there is one. It is common for a function to check
only for certain keywords, and pass its rest parameter to another
function using apply
; that function will check for the keywords that
concern it.
The way you express which parameters are required, optional, rest and keyword
is by means of specially recognized symbols, which are called
&-keywords
, in the lambda list. All such symbols’ print names
begin with the character ‘&
’. A list of all such symbols is the value of
the symbol lambda-list-keywords
.
The keywords used here are &key
, &optional
and &rest
.
The way they are used is best explained by means of examples;
the following are typical lambda lists, followed by descriptions
of which parameters are positional, rest or keyword; and required or optional.
(a b c)
a
, b
, and c
are all required and positional. The function must be
passed three arguments.
(a b &optional c)
a
and b
are required, c
is optional. All three are
positional. The function may be passed either two or three arguments.
(&optional a b c)
a
, b
, and c
are all optional and positional. The function may
be passed zero, one, two or three arguments.
(&rest a)
a
is a rest parameter. The function may be passed any number of arguments.
(a b &optional c d &rest e)
a
and b
are required positional, c
and d
are optional
positional, and e
is rest. The function may be passed two or more
arguments.
(&key a b)
a
and b
are both keyword parameters. A typical
call would look like
(foo :b 69 :a '(some elements))
or
(foo :a '(some elements) :b 69)
or
(foo :a '(some elements))
This illustrates that the parameters can be matched in either order, or omitted. If a keyword is specified twice, the first value is used.
(x &optional y &rest z &key a b)
x
is required positional, y
is optional positional,
z
is rest, and a
and b
are keyword.
One or more arguments are allowed. One or two arguments specify only
the positional parameters. Arguments beyond the second specify both
the rest parameter and the keyword parameters, so that
(foo 1 2 :b '(a list))
specifies 1
for x
, 2
for y
, (:b (a
list))
for z
, and (a list)
for b
. It does not
specify a
.
(&rest z &key a b c &allow-other-keys)
z
is rest, and a
, b
and c
are keyword
parameters. &allow-other-keys
says that absolutely any keyword
symbols may appear among the arguments; these symbols and the values
that follow them have no effect on the keyword parameters, but do
become part of the value of z
.
(&rest z &key &allow-other-keys)
This is equivalent to (&rest z)
. So, for that matter, is the
previous example, if the function does not use the values of a
,
b
and c
.
In all of the cases above, the default-form for each
optional parameter is nil
. To specify your own default forms,
instead of putting a symbol as the element of a lambda list, put in a
list whose first element is the symbol (the parameter itself) and whose
second element is the default-form. Only optional parameters may have
default forms; required parameters are never defaulted, and rest
parameters always default to nil
. For example:
(a &optional (b 3))
The default-form for b
is 3
. a
is a required parameter, and
so it doesn’t have a default form.
(&optional (a 'foo) &rest d &key b (c (symeval a)))
a
’s default-form is 'foo
, b
’s is nil
, and c
’s is
(symeval a)
. Note that if
the function were called on no arguments,
a
would be bound to the symbol foo
, and c
would be bound
to the value of the symbol foo
; this illustrates the fact
that each variable is bound immediately after its default-form is evaluated,
and so later default-forms may take advantage of earlier parameters
in the lambda list. b
and d
would be bound to nil
.
Occasionally it is important to know whether a certain optional
parameter was defaulted or not. Just by looking at the value one cannot
distinguish between omitting it and passing the default value
explicitly as an argument. The way to tell for sure is to put a third
element into the list: the third element should be a variable (a
symbol), and that variable is bound to nil
if the parameter was not
passed by the caller (and so was defaulted), or t
if the parameter
was passed. The new variable is called a “supplied-p” variable; it is
bound to t
if the parameter is supplied. For example:
(a &optional (b 3 c))
The default-form for b
is 3
, and the supplied-p variable for b
is c
. If the function is called with one argument, b
is bound
to 3
and c
is bound to nil
. If the function is called
with two arguments, b
is bound to the value that was passed
by the caller (which might be 3
), and c
is bound to t
.
It is possible to specify a keyword parameter’s symbol independently of its parameter name. To do this, use two nested lists to specify the parameter. The outer list is the one which can contain the default-form and supplied-p variable, if the parameter is optional. The first element of this list, instead of a symbol, is again a list, whose elements are the keyword symbol and the parameter variable name. For example:
(&key ((:a a)) ((:b b) t))
This is equivalent to (&key a (b t))
.
(&key ((:base base-value)))
This defines an argument which callers specify with the keyword
:base
, but which within the function is referred to as the
variable base-value
so as to avoid binding the value of
base
, which is a synonym for *print-base*
and controls
how numbers are printed.
It is also possible to include, in the lambda list, some other
symbols, which are bound to the values of their default-forms upon
entry to the function. These are not parameters, and they are
never bound to arguments; they just get bound, as if they appeared
in a let*
form. (Whether you use aux-variables or bind the
variables with let*
is a stylistic decision.)
To include such symbols, put them after any parameters, preceeded
by the &
-keyword &aux
. Examples:
(a &optional b &rest c &aux d (e 5) (f (cons a e)))
d
, e
, and f
are bound, when the function is
called, to nil
, 5
, and a cons of the first argument and 5.
You could, equivalently, use (a &optional b &rest c)
as
the lamda list and write (let* (d (e 5) (f (cons a e))) ...)
around the body of the function.
It is important to realize that the list of arguments to which a
rest-parameter is bound is set up in whatever way is most efficiently
implemented, rather than in the way that is most convenient for the
function receiving the arguments. It is not guaranteed to be a “real”
list. Sometimes the rest-args list is a stack list (see stack-list)
stored in the function-calling stack, and loses its validity when the
function returns. If a rest-argument is to be returned or made part of
permanent list-structure, it must first be copied (see copylist
,
copylist-fun), as you must always assume that it is one of these
special lists. The system does not detect the error of omitting to copy
a rest-argument; you will simply find that you have a value which seems
to change behind your back.
At other times the rest-args list may be an argument that was given to
apply
; therefore it is not safe to rplaca
this list as you may
modify permanent data structure. An attempt to rplacd
a rest-args
list is unsafe in this case, while in the first case it would cause
an error, since lists in the stack are impossible to rplacd
.
Has as its value the limit on the number of parameters that a lambda list may have. The implementation limit on the number of parameters allowed is at least this many. There is no promise that this many is forbidden, but it is a promise that any number less than this many is permitted.
This section documents all the keywords that may appear in the
lambda list or argument list (see lambda-list) of a function, a
macro, or a special form. Some of them are allowed everywhere, while
others are only allowed in one of these contexts; those are so
indicated. You need only know about &optional
, &key
, and
&rest
in order to understand the documentation of system functions
in this manual.
The value of this variable is a list of all of the allowed ‘&
’ keywords.
A list of them follows.
&optional
Separates the required arguments of a function from the optional arguments. See lambda-list.
&rest
Separates the required and optional arguments of a function from the rest argument. There may be only one rest argument. See &rest for full information about rest arguments. See lambda-list.
&key
Separates the positional arguments and rest argument of a function from the keyword arguments. See lambda-list.
&allow-other-keys
In a function that accepts keyword arguments, says that keywords that are not recognized are allowed. They and the corresponding values are ignored, as far as keyword arguments are concerned, but they do become part of the rest argument, if there is one.
&aux
Separates the arguments of a function from the auxiliary variables.
Following &aux
you can put entries of the form
(variable initial-value-form)
or just variable if you want it initialized to nil
or don’t care what the initial
value is.
&special
Declares the following arguments and/or auxiliary variables to be special within the scope of this function.
&local
Turns off a preceding &special
for the variables that follow.
"e
Declares that the following arguments are not to be evaluated. This is how you create a special function. See the caveats about special forms on special-form-caveat.
&eval
Turns off a preceding "e
for the arguments which follow.
&list-of
This is for macros defined by defmacro
only. Refer to &list-of.
&body
This is for macros defined by defmacro
only. It is similar to &rest
,
but declares to grindef
and the code-formatting module of the editor that
the body forms of a special form follow and should be indented accordingly.
Refer to &body.
&whole
This is for macros defined by defmacro
only. It means that the following
argument is bound to the entire macro call form being expanded. Refer to
&whole.
&environment
This is for macros defined by defmacro
only. It means that the following
argument is bound to an environment structure which records the local
macrolet
macro definitions in effect for subforms of the macro call form.
Refer to &environment.
The constructs flet
and labels
permit you to define
a function name in a lexical context only. If the same name
has a global function definition, it is shadowed temporarily.
Function definitions established by flet
(or labels
)
are to global definitions made with defun
as lexical variable bindings
made with let
are to global bindings made with defvar
.
They always have lexical scope.
Executes body with local function definitions in effect according to local-functions.
local-functions should be a list of elements which look like
(name lambda-list function-body...)
just like the cdr of a defun
form. The meaning of this element
of local-functions is to define name locally with the
indicated definition.
Within the lexical scope of body, using name as a function name accesses
the local definition.
Example:
(flet ((triple (x) (* x 3))) (print (triple -1)) (mapcar (function triple) '(1 2 1.2)))
prints the number -3 and returns a list (3 6 3.6)
.
Each local function is closed in the environment outside the flet
.
As a result, the local functions cannot call each other.
(flet ((foo (x) (bar x t)) (bar (y z) (list y z))) (foo t))
calls the local definition of foo
, which calls the global definition
of bar
, because the body of foo
is not within the scope of the
local definition of bar
.
Functions defined with flet
inside of a compiled function
can be referred to by name in a function spec of the form
(:internal outer-function-name flet-name)
.
See flet-function-spec.
Is like flet except that the local functions can call each other.
They are closed in the environment inside the labels
, so all
the local function names are accessible inside the bodies of the
local functions. labels
is one of the most ancient Lisp constructs,
but was typically not implemented in second generation Lisp systems
in which no efficient form of closure existed.
(labels ((walk (x) (typecase x (cons (walk (car x)) (walk (cdr x))) (t (if (eq x 'haha) (print 'found-it)))))) (walk foo))
allows walk
to call itself recursively because walk
’s body
is inside the scope of the definition of walk
.
See also macrolet
, an analogous construct for defining macros locally
(macrolet-fun).
This section describes some functions and special forms. Some are parts of the evaluator, or closely related to it. Some have to do specifically with issues discussed above such as keyword arguments. Some are just fundamental Lisp forms that are very important.
(eval form)
evaluates form, and returns the result.
Example:
(defvar x 43) (defvar foo 'bar) (eval (list 'cons x 'foo)) => (43 . bar)
The dynamic bindings available at the time eval
is called
are visible for dynamic variables within the expression x.
No lexical bindings are available for the evaluation of x.
It is unusual to call eval
explicitly, since usually
evaluation is done implicitly. If you are writing a simple Lisp program and
explicitly calling eval
, you are probably doing something wrong.
eval
is primarily useful in programs which deal with Lisp itself,
rather than programs about knowledge, mathematics or games.
Also, if you are only interested in getting at the dynamic value of a
symbol (that is, the contents of the symbol’s value cell), then you
should use the primitive function symeval
(see symeval-fun).
If the argument nohook is non-nil
, execution of the
evalhook is inhibited for form, but not for
evaluation of the subforms of form. See evalhook
, evalhook-fun.
evalhook
is also the way to evaluate in a specified lexical environment
if you happen to have got your hands on one.
Note: in Maclisp, the second argument to eval
is a
“binding context pointer”. There is no such thing in Zetalisp;
closures are used instead (see closure).
Within the definition of a special form, evaluates form in the current lexical environment.
(funcall f a1 a2 ... an)
applies the
function f to the arguments a1, a2, ..., an.
f may not
be a special form nor a macro; this would not be meaningful.
Example:
(cons 1 2) => (1 . 2) (setq cons 'plus) (funcall cons 1 2) => 3
This shows that the use of the symbol cons
as the name of a function
and the use of that symbol as the name of a variable do not interact.
The cons
form invokes the function named cons
.
The funcall
form evaluates the variable and gets the symbol plus
,
which is the name of a different function.
Note: the Maclisp functions subrcall
, lsubrcall
, and arraycall
are not needed on the Lisp Machine; funcall
is just as efficient.
arraycall
is provided for compatibility; it ignores its first
subform (the Maclisp array type) and is otherwise identical to aref
.
subrcall
and lsubrcall
are not provided.
apply
is like funcall
except that the last of args is
really a list of arguments to give to f rather than a single argument.
lexpr-funcall
is a synonym for apply
; formerly, apply
was
limited to the two argument case.
(apply f arglist)
applies the function f to the list of
arguments arglist. arglist should be a list; f can be any function.
Examples:
(setq fred '+) (apply fred '(1 2)) => 3 (setq fred '-) (apply fred '(1 2)) => -1 (apply 'cons '((+ 2 3) 4)) => ((+ 2 3) . 4) not (5 . 4)
Of course, arglist may be nil
.
If there is more than one element of args, then all but the last of them are individual arguments to pass to f, while the last one is a list of arguments as above.
Examples:
(apply 'plus 1 1 1 '(1 1 1)) => 6 (defun report-error (&rest args) (apply 'format *error-output* args))
apply
can also be used with a single argument. Then this argument
is a list of a function and some arguments to pass it.
Example:
(apply '(car (a))) => a
;Not the same as (eval '(car (a)))
Note: in Maclisp, apply
takes two or three arguments, and the third
argument, when passed, is interpreted as a “binding context pointer”.
So the second argument always provides all the args to pass to the function.
There are no binding context pointers in Zetalisp; true lexical scoping
exists and is interfaced in other ways.
Has as its value the limit on the number of arguments that can be dealt with in a function call. There is no promise that this many is forbidden, but it is a promise that any smaller number is acceptable.
Note that if apply
is used with exactly two arguments, the first
one being a function that takes a rest argument, there is no limit
except the size of memory on the number of elements in the second
argument to apply
.
Offers a very general way of controlling what arguments you
pass to a function. You can provide either individual arguments as in
funcall
or lists of arguments as in apply
, in any order. In
addition, you can make some of the arguments optional. If the
function is not prepared to accept all the arguments you specify, no
error occurs if the excess arguments are optional ones. Instead, the
excess arguments are simply not passed to the function.
The argument-specs are alternating keywords (or lists of keywords)
and values. Each keyword or list of keywords says what to do with the
value that follows. If a value happens to require no keywords,
provide ()
as a list of keywords for it.
Two keywords are presently defined: :optional
and :spread
.
:spread
says that the following value is a list of arguments.
Otherwise it is a single argument. :optional
says that all the
following arguments are optional. It is not necessary to specify
:optional
with all the following argument-specs, because it is
sticky.
Example:
(call #'foo () x :spread y '(:optional :spread) z () w)
The arguments passed to foo
are the value of x
, the
elements of the value of y
, the elements of the value of
z
, and the value of w
. The function foo
must be
prepared to accept all the arguments which come from x
and
y
, but if it does not want the rest, they are ignored.
(quote object)
simply returns object. quote
is used to
include constants in a form. It is useful specifically because
object is not evaluated; the quote
is how you make a form that
returns an arbitrary Lisp object.
Examples:
(quote x) => x (setq x (quote (some list))) x => (some list)
Since quote
is so useful but somewhat cumbersome to type, the reader normally
converts any form preceded by a single quote ('
) character into a quote
form.
For example,
(setq x '(some list))
is converted by read
into
(setq x (quote (some list)))
function
has two distinct, though related, meanings.
If f is a symbol or any other function spec (see function-spec),
(function f)
refers to the function definition of f.
For example, in (mapcar (function car) x)
, the function
definition of car
is passed as the first argument to mapcar
.
function
used this way is like fdefinition
except that its argument is unevaluated, and so
(function fred) is like (fdefinition 'fred)
f can also be an explicit function, or lambda-expression, a list such
as (lambda (x) (* x x))
such as could be the function definition of a
symbol. Then (function f)
represents that function, suitably
interfaced to execute in the lexical environment where it appears. To
explain:
(let (a) (mapcar (lambda (x) (push x a)) l))
attempts to call the function lambda
and evaluate (x)
for its first argument. That is no way to refer to the function
expressed by (lambda (x) (push x a))
.
(let (a) (mapcar (quote (lambda (x) (push x a))) l))
passes to mapcar
the list (lambda (x) (push x a))
.
This list does not in any way record the lexical environment
where the quote
form appeared, so it is impossible to make
this environment, with its binding of a
, available
for the execution of (push x a)
. Therefore, the reference
to a
does not work properly.
(let (a) (mapcar (function (lambda (x) (push x a))) l))
passes mapcar
a specially designed closure made from the
function represented by (lambda (x) (push x a))
. When mapcar
calls this closure, the lexical environment of the function
form
is put again into effect, and the a
in (push x a)
refers
properly to the binding made by this let
.
In addition, the compiler knows that the argument to function
should be compiled. The argument of quote
cannot be compiled
since it may be intended for other uses.
To ease typing, the reader converts #'thing
into (function thing)
.
So #'
is similar to '
except that it produces a
function
form instead of a quote
form. The last example
could be written as
(let (a) (mapcar #'(lambda (x) (push x a)) l))
Another way of explaining function
is that it causes f to be
treated the same way as it would as the car of a form. Evaluating
the form (f arg1 arg2...)
uses the function definition
of f if it is a symbol, and otherwise expects f to be a list
which is a lambda-expression. Note that the car of a form may not be
a non-symbol function spec, as that would be difficult to make sense of.
Instead, write
(funcall (function spec) args...)
You should be careful about whether you use #'
or '
. Suppose
you have a program with a variable x
whose value is assumed to
contain a function that gets called on some arguments. If you want that
variable to be the test
function, there are two things you could say:
(setq x 'test)
or
(setq x #'test)
The former causes the value of x
to be the symbol test
, whereas
the latter causes the value of x
to be the function object found in
the function cell of test
. When the time comes to call the function
(the program does (funcall x ...)
), either expression works
because calling a symbol as a function uses its function definition instead.
Using 'test
is insignificantly slower, because the function
call has to indirect through the symbol, but it allows the function
to be redefined, traced (see trace-fun), or advised (see advise-fun).
Use of #'
picks up the function definition out of
the symbol test
when the setq
is done and does not see any later changes to it.
#'
should be used only if you wish specifically to prevent redefinition
of the function from affecting this closure.
Takes no arguments and returns nil
.
Takes no arguments and returns t
.
Takes any number of arguments and returns nil
. This is often useful
as a “dummy” function; if you are calling a function that takes a function
as an argument, and you want to pass one that doesn’t do anything and
won’t mind being called with any argument pattern, use this.
comment
ignores its form and returns the symbol comment
.
It is most useful for commenting out function definitions
that are not needed or correct but worth preserving in the source.
The #|...|#
syntactic construct is an alternative method.
For comments within code about the code, it is better to use semicolons.
Example:
(comment
;; This is brain-damaged. Can someone figure out
;; how to do this right?
(defun foo (x)
...)
) ;End comment
;; prevents this definition of foo
from being used.
Declarations provide auxiliary information on how to execute a function
or expression properly. The most important declarations are special
declarations, which control the scope of variable names. Some
declarations do not affect execution at all and only provide information
about a function, for the sake of arglist
, for example.
Declarations may apply to an entire function or to any expression within
it. Declarations can be made around any subexpression by writing a
local-declare
around the subexpression or by writing a declare
at the front of the body of certain constructs. Declarations can be
made on an entire function by writing a declare
at the front of the
function’s body.
A local-declare
form looks like
(local-declare (decl1 decl2 ...) form1 form2 ...)
Each decl is in effect for the forms in the body of the
local-declare
form.
The special form declare
is used for writing local declarations
within the construct they apply to.
A declare inside a function definition, just after the argument
list, is equivalent to putting a local-declare
around the function
definition. More specifically,
(defun foo (a b) (declare (special a b)) (bar))
is equivalent to
(local-declare ((special a b)) (defun foo (a b) (bar)))
Note that
(defun foo (a b) (local-declare ((special a b)) (bar)))
does not do the job, because the declaration is not in effect for
the binding of the arguments of foo
.
declare
is preferable to local-declare
in this sort of
situation, because it allows the defun
s themselves to be the
top-level lists in the file. While local-declare
might appear to
have an advantage in that one local-declare
may go around several
defun
s, it tends to cause trouble to use local-declare
in that
fashion.
declare
has a similar meaning at the front of the body of a
progn
, prog
, let
, prog*
, let*
, or internal lambda
. For
example,
(prog (x) (declare (special x)) ...)
is equivalent to
(local-declare ((special x)) (prog (x) ...))
At top level in the file, (declare forms...)
is equivalent to
(eval-when (compile) forms...)
. This use of declare
is nearly obsolete, and should be avoided. In Common Lisp, proclaim
(below) is used for such purposes, with a different calling convention.
Elsewhere, declare
’s are ignored.
Here is a list of declarations that have system-defined meanings:
(special var1 var2 ...)
The variables var1, var2, etc will be treated as special variables in the scope of the declaration.
(unspecial var1 var2 ...)
The variables var1, var2, etc will be treated as lexical variables in the scope of the declaration, even if they are globally special.
(notinline fun1 fun2 ...)
The functions fun1, fun2 and so on will not be open coded or optimized by the compiler within the scope of the declaration.
(inline fun1 fun2 ...)
The functions fun1, fun2 and so on will be open coded or optimized by the compiler (to whatever extent it knows how) within the scope of the declaration. Merely issuing this declaration does not tell the compiler how to do any useful optimization or open coding of a function.
(ignore var1 var2 ...)
Says that the variables var1, var2, etc, which are bound in the construct in which this declaration is found, are going to be ignored. This is currently significant only in a function being compiled; the compiler issues a warning if the variables are used, and refrains from its usual warning if the variables are ignored.
(declaration decl1 decl2 ...)
Says that declarations decl1, decl2, etc are going to be used, and prevents any warning about an unrecognized type of declaration. For example:
(defun hack () (declare (declaration lose-method) (lose-method foo bar)) ... (lose foo) ...)
might be useful if (lose foo)
is a macro whose expander function
does (getdecl 'foo 'lose-method)
to see what to do.
See getdecl-fun for more information on getdecl
and declarations.
(proclaim '(declaration lose-method))
might also be advisable if you expect widespread use of lose-method
declarations.
The next two are used by the compiler and generally should not be written by users.
(def name . definition)
name will be defined for the compiler in the scope of the declaration.
The compiler uses this automatically to keep track of macros and
open-codable functions (defsubst
s) defined in the file being compiled.
Note that the cddr of this item is a function.
(propname symbol value)
(getdecl symbol propname)
will return value
in the scope of the declaration. This is how the compiler keeps track of
defdecl
s.
These declarations are significant only when they apply to an entire defun
.
(arglist . arglist)
Records arglist as the argument list of the function, to be used instead of its lambda list if anyone asks what its arguments are. This is purely documentation.
(values . values) or (:return-list . values)
Records values as the return values list of the function, to be used if anyone asks what values it returns. This is purely documentation.
(sys:function-parent parent-function-spec)
Records parent-function-spec as the parent of this function. If, in the editor, you ask to see the source of this function, and the editor doesn’t know where it is, the editor will show you the source code for the parent function instead.
For example, the accessor functions generated by defstruct
have no defuns of their own in the text of the source file.
So defstruct
generates them with sys:function-parent
declarations giving the defstruct
’s name as the parent function spec.
Visiting the accessor function with Meta-
sees the declaration
and therefore visits the text of the defstruct
.
(:self-flavor flavorname)
Instance variables of the flavor flavorname, in self
, will be
accessible in the function.
Executes the body, recognizing declarations at the front of it.
locally
is synonymous with progn
except that in Common Lisp
a declare
is allowed at the beginning of a locally
and not
at the beginning of a progn
.
locally
does differ from progn
in one context: at top level
in a file being compiled, progn
causes each of its elements
(including declarations, therefore) to be treated as if at top level.
locally
does not receive this treatment. The locally
form
is simply evaluated when the QFASL file is loaded.
Each of declarations is put into effect globally. Currently only
special
and unspecial
declarations mean anything in this way.
proclaim
’s arguments are evaluated, and the values are expected
to be declarations such as you could write in a declare
.
Thus, you would say (proclaim '(special x))
to make a special
declaration globally.
Top-level special
declarations are not the recommended way to make a
variable special. Use defvar
, defconstant
or defparameter
,
so that you can give the variable documentation. Proclaiming the
variable special should be done only when the variable is used in a file
other than the one which defines it, to enable the file to be compiled
without having to load the defining file first.
proclaim
is fairly new. Until recently, top-level declare
was
the preferred way to make global special declarations when defvar
,
etc, could not be used. Such top-level declare
’s are still
quite common. In them, the declaration would not be quoted;
for example, (declare (special x))
.
Equivalent to (proclaim (special variables...))
, this
declares each of the variables to be globally special.
This function is obsolete.
Removes any global special declarations of the variables. This function is obsolete.
Is a Common Lisp construct effectively the same as value-form. It declares that the value of value-form is an object which of type type-specifier. This is to assist compilers in generating better code for conventional machine architectures. The Lisp Machine does not make use of type declarations so this is the same as writing just value-form. type-specifier is not evaluated.
If you want the type of an object to be checked at run time, with an
error if it is not what it is supposed to be, use check-type
(check-type-fun).
When one function ends by calling another function (possibly itself), as in
(defun last (x) (cond ((atom x) x) ((atom (cdr x)) x) (t (last (cdr x)))))
it is called tail recursion. In general, if X is a form, and Y is a sub-form of X, then if the value of Y is unconditionally returned as the value of X, with no intervening computation, then we say that X tail-recursively evaluates Y.
In a tail recursive situation,
it is not strictly necessary to remember anything about the first call
to last
when the second one is activated. The stack frame for the
first call can be discarded completely, allowing last
to use a
bounded amount of stack space independent of the length of its argument.
A system which does this is called tail recursive.
The Lisp machine system works tail recursively if the variable
tail-recursion-flag
is non-nil
. This is often faster, because
it reduces the amount of time spent in refilling the hardware’s pdl
buffer. However, you forfeit a certain amount of useful debugging
information: once the outer call to last
has been removed from the
stack, you can no longer see its frame in the debugger.
If this variable is non-nil
, the calling stack frame is
discarded when a tail-recursive call is made in compiled code.
There are many things which a function can do that can make it dangerous
to discard its stack frame. For example, it may have done a *catch
;
it may have bound special variables; it may have a &rest
argument on
the stack; it may have asked for the location of an argument or local
variable. The system detects all of these conditions automatically and
retains the stack frame to ensure proper execution. Some of these
conditions occur in eval
; as a result, interpreted code is never
completely tail recursive.
The Lisp Machine includes a facility by which the evaluation of a form
can produce more than one value. When a function needs to return more
than one result to its caller, multiple values are a cleaner way of
doing this than returning a list of the values or setq
’ing special
variables to the extra values. In most Lisp function calls, multiple
values are not used. Special syntax is required both to produce
multiple values and to receive them.
The primitive for producing multiple values is values
, which takes
any number of arguments and returns that many values. If the last form
in the body of a function is a values
with three arguments, then
a call to that function returns three values. Many system functions
produce multiple values, but they all do it via values
.
Returns multiple values, its arguments. This is the primitive
function for producing multiple values. It is legal to call values
with
no arguments; it returns no values in that case.
Returns multiple values, the elements of the list. (values-list '(a b c))
is the same as (values 'a 'b 'c)
.
list may be nil
, the empty list, which causes no values to be returned.
Equivalent to (apply 'values list)
.
return
and its variants can also be used, within a block
, do
or
prog
special form, to return multiple values. They are explained on
return-fun.
Here are the special forms for receiving multiple values.
multiple-value
is a special
form used for calling a function which
is expected to return more than one value.
form is evaluated, and the variables
are set (not lambda-bound) to the values returned by form. If more values
are returned than there are variables, the extra values
are ignored. If there are more variables than values returned,
extra values of nil
are supplied. If nil
appears in the var-list,
then the corresponding value is ignored (setting nil
is not allowed anyway).
Example:
(multiple-value (symbol already-there-p) (intern "goo"))
In addition to its first value (the symbol), intern
returns a second
value, which is non-nil
if an existing symbol was found,
or else nil
if intern
had to create one. So if
the symbol goo
was already known, the variable already-there-p
is set non-nil
, otherwise it is set to nil
. The third value
returned by intern
is ignored by this form of call since there
is no third variable in the multiple-value
.
multiple-value
is usually used for effect rather than for value; however,
its value is defined to be the first of the values returned by form.
multiple-value-setq
is the Common Lisp name for this construct.
The two names are equivalent.
This is similar to multiple-value
, but locally binds the variables which
receive the values, rather than setting them, and has a body–a set of forms
which are evaluated with these local bindings in effect.
First form is evaluated. Then the variables are
bound to the values returned by form. Then the body forms
are evaluated sequentially, the bindings are undone, and the result
of the last body form is returned.
Example:
(multiple-value-bind (sym already-there) (intern string) ;; If an existing symbol was found, deallocate the string. (if already-there (return-storage (prog1 string (setq string nil)))) sym)
Evaluates the argforms, saving all of their values, and then calls function with all those values as arguments. This differs from
(funcall function argforms...)
because that would get only one argument for function from each
argform, whereas multiple-value-call
gets as many args from each
argform as the argform cares to return. This works by consing a
list of all the values returned, and applying function to it. Example:
(multiple-value-call 'append (values '(a b) '(c d)) '(e f)) => (a b c d e f)
Evaluates form, saves its values, evaluates the forms, discards their values, then returns whatever values form produced. This does not cons. Example:
(multiple-value-prog1 (values 1 2) (print 'foo)) => 1 2
multiple-value-list
evaluates form, and returns a list of
the values it returned. This is useful for when you don’t know how many values
to expect.
Example:
(setq a (multiple-value-list (intern "goo"))) a => (goo nil #<Package USER 10112147>)
This is similar to the example of multiple-value
above; a
is set
to a list of three elements, the three values returned by intern
.
Evaluates form and returns its value number n, n = 0 meaning
the first value. For example, (nth-value 1 (foo))
returns
the second of foo
’s values. nth-value
operates without consing
in compiled code if the first argument’s value is known at compile time.
When one form finished by tail recursively evaluating a subform (see
tail-recursion), all of the subform’s multiple values are passed back
by the outer form. For example, the value of a cond
is the value of
the last form in the selected clause. If the last form in that clause
produces multiple values, so does the cond
. This passing-back
of multiple values of course has no effect unless eventually one of the
special forms for receiving multiple values is reached.
If the outer form returns a value computed by a subform, but not in a
tail recursive fashion (for example, if the value of the subform is
examined first), multiple values or only single values may be returned
at the discretion of the implementation; users should not depend on
whatever way it happens to work, as it may change in the future or in
other implementations. The reason we don’t guarantee non-transmission
of multiple values is because such a guarantee would not be very useful
and the efficiency cost of enforcing it would be high. Even
setq
’ing a variable to the result of a form, then returning the
value of that variable, might pass multiple values if an
optimizing compiler realized that the setq
’ing of the variable
was unnecessary. Since extra returned values are generally ignored,
it is not vital to eliminate them.
Note that use of a form as an argument to a function never receives
multiple values from that form. That is, if the form (foo (bar))
is evaluated and the call to bar
returns many values, foo
is
still called on only one argument (namely, the first value returned),
rather than being called on all the values returned. We choose not to
generate several separate arguments from the several values, because
this would make the source code obscure; it would not be syntactically
obvious that a single form does not correspond to a single argument.
To pass all returned values to another function, use multiple-value-call
, above.
For clarity, descriptions of the interaction of several common special forms with multiple values follow. This can all be deduced from the rule given above. Note well that when it says that multiple values are not returned, it really means that they may or may not be returned, and you should not write any programs that depend on which way it actually works.
The body of a defun
or a lambda
, and variations such as the
body of a function, the body of a let
, etc., pass back multiple
values from the last form in the body.
eval
, apply
and funcall
,
pass back multiple values from the function called.
progn
passes back multiple values from its last form. progv
and
progw
do so also. prog1
and prog2
, however, do not pass
back multiple values.
Multiple values are passed back only from the last subform of an and
or an or
form,
not from previous subforms since the return is conditional. Remember
that multiple values are only passed back when the value of a subform
is unconditionally returned from the containing form. For example,
consider the form (or (foo) (bar))
. If foo
returns a non-nil
first value, then only that value is returned as the value of the
form. But if it returns nil
(as its first value), then or
returns whatever values the call to bar
returns.
cond
passes back multiple values from the last form in the selected
clause, provided that that last form’s value is returned
unconditionally. This is true if the clause has two or more forms in
it, and is always true for the last clause.
The variants of cond
such as if
, select
, selectq
, and
dispatch
pass back multiple values from the last form in the
selected clause.
If a block
form falls through the end, it returns all the values
returned by the last expression in it. If return-from
or return
is used to exit a block
form, then the values returned by the
block
form depend on the kind of return
. If return
is given
two or more subforms, then block
returns as many values as the
return
has subforms. However, if the return
has only one
subform, then the block
returns all of the values returned by that
one subform.
prog
behaves like block
if it is exited with return
(or
return-from
). If control falls through the end of a prog
, it
returns the single value nil
. do
also behaves like block
with respect to return
, but if it is exited through the exit test,
all the values of the last exit-form are returned.
unwind-protect
passes back multiple values from its protected form.
In a sense, this is an exception to the rule; but it is useful, and it
makes sense to consider the execution of the unwind forms as a byproduct of
unwinding the stack and not as part of sequential execution.
catch
passes back multiple values from the last form in its
body, if it exits normally. If a throw is done, multiple values are
passed back from the value form in the throw
.
The smallest number of values that might possibly fail to work. Returning a number of values less than this many cannot possibly run into trouble with an implementation limit on number of values returned.
Here is a description of the error conditions that the evaluator can signal. Some can be signaled by calls to compiled functions also. This is for use by those who are writing condition handlers (condition-handlers). The novice should skip this section.
sys:invalid-function
: (error
) ¶This is signaled when an object that is
supposed to be applied to arguments is not a valid Lisp function.
The condition instance supports the
operation :function
, which returns the supposed function to be called.
The :new-function
proceed type is provided; it expects one argument,
a function to call instead.
sys:invalid-lambda-list
: (sys:invalid-function
error
) ¶This condition name is present in addition to sys:invalid-function
when the function to be called looks like an interpreted function, and
the only problem is the syntax of its lambda list.
sys:too-few-arguments
: (error
) ¶This condition is signaled when a function is applied to too few arguments.
The condition instance supports the operations :function
and
:arguments
which return the function and the list of the arguments
provided.
The proceed types :additional-arguments
and :new-argument-list
are provided. Both take one argument. In the first case, the argument
is a list of arguments to pass in addition to the ones supplied. In the
second, it is a list of arguments to replace the ones actually supplied.
sys:too-many-arguments
: (error
) ¶This is similar to sys:too-few-arguments
. Instead of the
:additional-arguments
proceed type, :fewer-arguments
is
provided. Its argument is a number, which is how many of the originally
supplied arguments to use in calling the function again.
sys:undefined-keyword-argument
: (error
) ¶This is signaled when a function that takes keyword arguments is given a
keyword that it does not accept, if &allow-other-keys
was not used
in the function’s definition and :allow-other-keys
was not specified
by the caller (see allow-other-keys-kwd). The :keyword
operation
on the condition instance returns the extraneous keyword, and the
:value
operation returns the value supplied with it.
The proceed type :new-keyword
is provided. It expects one
argument, which is a keyword to use instead of the one supplied.
sys:cell-contents-error
: (error
) ¶This condition name categorizes all the errors signaled because of references to void memory locations. It includes “unbound” variables, “undefined” functions, and other things.
:address
A locative pointer to the referenced cell.
:current-address
A locative pointer to the cell which currently contains the contents that were found in the referenced cell when the error happened. This can be different from the original address in the case of dynamic variable bindings, which move between special PDLs and symbol value cells.
:cell-type
A keyword saying what type of cell was referred to: :function
,
:value
, :closure
, or nil
for a cell that is not one of
those.
:containing-structure
The object (list, array, symbol) inside which the referenced memory cell is found.
:data-type
:pointer
The data type and pointer fields of the contents of the memory cell, at the time of the error. Both are fixnums.
The proceed type :no-action
takes no argument. If the cell’s
contents are now valid, the program proceeds, using them. Otherwise
the error happens again.
The proceed type :package-dwim
looks for symbols with the same name
in other packages; but only if the containing structure is a symbol.
Two other proceed types take one argument: :new-value
and :store-new-value
.
The argument is used as the contents of the memory cell.
:store-new-value
also permanently stores the argument into the cell.
sys:unbound-variable
: (sys:cell-contents-error
error
) ¶This condition name categorizes all errors of variables whose values are void.
: sys:unbound-special-variable ¶
: sys:unbound-closure-variable ¶
: sys:unbound-instance-variable ¶These condition names appear in addition to sys:unbound-variable
to subcategorize
the kind of variable reference that the error happened in.
sys:undefined-function
: (sys:cell-contents-error
error
) ¶This condition name categorizes errors of function specs that are undefined.
sys:wrong-type-argument
: (error
) ¶This is signaled when a function checks the type of its argument and
rejects it; for example, if you do (car 1)
.
The condition instance supports these extra operations:
:arg-name
The name of the erroneous argument. This may be nil
if there is no
name, or if the system no longer remembers which argument it was.
:old-value
The value that was supplied for the argument.
:function
The function which received and rejected the argument.
:description
A type specifier which says what sort of object was expected for this argument.
The proceed type :argument-value
is provided; it expects one argument,
which is a value to use instead of the erroneous value.
Lisp provides a variety of structures for flow of control.
Function application is the basic method for construction of programs. Operations are written as the application of a function to its arguments. Usually, Lisp programs are written as a large collection of small functions, each of which implements a simple operation. These functions operate by calling one another, and so larger operations are defined in terms of smaller ones.
A function may always call itself in Lisp. The calling of a function by itself is known as recursion; it is analogous to mathematical induction.
The performing of an action repeatedly (usually with some
changes between repetitions) is called iteration, and is provided as
a basic control structure in most languages. The do statement of
PL/I, the for statement of ALGOL/60, and so on are examples of
iteration primitives. Lisp provides two general iteration facilities:
do
and loop
, as well as a variety of special-purpose iteration
facilities. (loop
is sufficiently complex that it is explained
in its own chapter later in the manual; see loop-fun.)
A conditional construct is one which allows a program
to make a decision, and do one thing or another based on some logical
condition. Lisp provides the simple one-way conditionals and
and or
,
the simple two-way conditional if
, and more general multi-way
conditionals such as cond
and selectq
.
The choice of which form to use in any particular situation is a matter
of personal taste and style.
There are some non-local exit control structures, analogous
to the leave, exit, and escape constructs in many modern
languages.
Zetalisp provides for both static (lexical) non-local exits with
block
and return-from
and dynamic non-local exits with catch
and throw
. Another kind of non-local exit is the goto, provided
by the tagbody
and go
constructs.
Zetalisp also provides a coroutine capability, explained in the section on stack-groups (stack-group), and a multiple-process facility (see process). There is also a facility for generic function calling using message passing; see flavor.
The body forms are evaluated in order from left to right and the value
of the last one is returned.
progn
is the primitive control structure construct for "compound
statements".
Example:
(foo (cdr a) (progn (setq b (extract frob)) (car b)) (cadr b))
Lambda-expressions, cond
forms, do
forms, and
many other control structure forms use progn
implicitly, that is,
they allow multiple forms in their bodies.
prog1
is similar to progn
, but it returns the value of its first form rather
than its last.
It is most commonly used to evaluate an expression with side effects, and return
a value which must be computed before the side effects happen.
Example:
(setq x (prog1 y (setq y x)))
interchanges the values of the variables x and y. prog1
never
returns multiple values.
prog2
is similar to progn
and prog1
, but it returns its
second form. It is included largely for compatibility with old programs.
if
is the simplest conditional form. The “if-then” form looks like:
(if predicate-form then-form)
predicate-form is evaluated, and if the result is non-nil
, the
then-form is evaluated and its result is returned. Otherwise, nil
is returned.
In the “if-then-else” form, it looks like
(if predicate-form then-form else-form)
predicate-form is evaluated, and if the result is non-nil
, the
then-form is evaluated and its result is returned. Otherwise, the
else-form is evaluated and its result is returned.
If there are more than three subforms, if
assumes you want more than
one else-form; if the predicate returns nil
, they are evaluated
sequentially and the result of the last one is returned.
If condition evaluates to something non-nil
, the body is
executed and its value(s) returned. Otherwise, the value of the when
is nil
and the body is not executed.
If condition evaluates to nil
, the body is
executed and its value(s) returned. Otherwise, the value of the unless
is nil
and the body is not executed.
The cond
special form consists of the symbol cond
followed by
several clauses. Each clause consists of a predicate form, called
the condition, followed by zero or more body forms.
(cond (condition body body...) (condition) (condition body ...) ... )
The idea is that each clause represents a case which is selected if its condition is satisfied and the conditions of all preceding clauses were not satisfied. When a clause is selected, its body forms are evaluated.
cond
processes its clauses in order from left to right. First,
the condition of the current clause is evaluated. If the result is
nil
, cond
advances to the next clause. Otherwise, the cdr of
the clause is treated as a list of body forms which are
evaluated in order from left to right. After evaluating the
body forms, cond
returns without inspecting any remaining
clauses. The value of the cond
form is the value of the
last body form evaluated, or the value of the condition if there
were no body forms in the clause. If cond
runs out of clauses,
that is, if every condition evaluates to nil
, and thus no case is
selected, the value of the cond
is nil
.
Example:
(cond ((zerop x) ;First clause: (+ y 3)) ; (zerop x) is the condition. ; (+ y 3) is the body. ((null y) ;A clause with 2 body forms: (setq y 4) ; this (cons x z)) ; and this. (z) ;A clause with no body forms: the condition is ; justz
. Ifz
is non-nil
, it is returned. (t ;A condition of t 105) ; is always satisfied. ) ;This is the end of the cond.
cond-every
has the same syntax as cond
, but executes every clause whose
condition is satisfied, not just the first. If a condition is the symbol
otherwise
, it is satisfied if and only if no preceding condition is
satisfied. The value returned
is the value of the last body form in the last clause whose condition
is satisfied. Multiple values are not returned.
and
evaluates the forms one at a time,
from left to right. If any form evaluates to nil
, and
immediately returns nil
without evaluating the remaining
forms. If all the forms evaluate to non-nil
values, and
returns
the value of the last form.
and
can be used in two different ways. You can use it as a logical
and
function, because it returns a true value only if all of its
arguments are true:
(if (and socrates-is-a-person all-people-are-mortal) (setq socrates-is-mortal t))
Because the order of evaluation is well-defined, you can do
(if (and (boundp 'x) (eq x 'foo)) (setq y 'bar))
knowing that the x
in the eq
form will not be evaluated if x
is found to be void.
You can also use and
as a simple conditional form:
(and (setq temp (assq x y)) (rplacd temp z))
(and bright-day glorious-day (princ "It is a bright and glorious day."))
but when
is usually preferable.
Note: (and) => t
, which is the identity for the and
operation.
or
evaluates the forms one by one from left to right.
If a form evaluates to nil
, or
proceeds to evaluate the
next form. If there are no more forms, or
returns nil
.
But if a form evaluates to a non-nil
value, or
immediately returns
that value without evaluating any remaining forms.
As with and
, or
can be used either as a logical or
function,
or as a conditional:
(or it-is-fish it-is-fowl) (or it-is-fish it-is-fowl (print "It is neither fish nor fowl.")
but it is often possible and cleaner to use unless
in the latter case.
Note: (or) => nil
, the identity for this operation.
selectq
is a conditional which chooses one of its clauses to execute
by comparing the value of a form against various constants using eql
.
Its form is as follows:
(selectq key-form (test body...) (test body...) (test body...) ...)
The first thing selectq
does is to evaluate key-form; call the resulting
value key. Then selectq
considers
each of the clauses in turn. If key matches the clause’s
test, the body of the clause
is evaluated, and selectq
returns the value of the last
body form. If there are no matches, selectq
returns nil
.
A test may be any of:
If the key is eql
to the symbol, it matches.
If the key is eql
to the number, it matches.
key must have the same type and the same value
as the number.
If the key is eql
to one of the elements of the list,
then it matches. The elements of the list should be symbols
or numbers.
t
or otherwise
The symbols t
and otherwise
are special tests which match anything.
Either symbol may be used, it makes no difference;
t
is mainly for compatibility with Maclisp’s caseq
construct.
To be useful, this should be the last clause in the selectq
.
Example:
(selectq x (foo (do-this)) (bar (do-that)) ((baz quux mum) (do-the-other-thing)) (otherwise (ferror nil "Never heard of ~S" x)))
is equivalent to
(cond ((eq x 'foo) (do-this)) ((eq x 'bar) (do-that)) ((memq x '(baz quux mum)) (do-the-other-thing)) (t (ferror nil "Never heard of ~S" x)))
Note that the tests are not evaluated; if you want them to
be evaluated use select
rather than selectq
.
case
is the Common Lisp name for this construct.
caseq
is the Maclisp name; it identical
to selectq
, which is not totally compatible with Maclisp,
because selectq
accepts otherwise
as well as t
where caseq
would not accept otherwise
, and because Maclisp
does some error-checking that selectq
does not. Maclisp programs
that use caseq
work correctly so long as they don’t use the
symbol otherwise
as a key.
Like case
except that an uncorrectable error is signaled if
every clause fails. t
or otherwise
clauses are not allowed.
Like ecase
except that the error is correctable. The first argument
is called place because it must be setf
’able.
If the user proceeds from the error, a new value is read and stored into
place; then the clauses are tested again using the new value.
Errors repeat until a value is specified which makes some clause succeed.
Also see defselect
(defselect-fun), a special form for defining a function
whose body is like a selectq
.
select
is like selectq
, except that the elements of the
tests are evaluated before they are used.
This creates a syntactic ambiguity: if (bar baz)
is seen the
first element of a clause, is it a list of two forms, or is it one
form? select
interprets it as a list of two forms. If you
want to have a clause whose test is a single form, and that form
is a list, you have to write it as a list of one form.
Example:
(select (frob x) (foo 1) ((bar baz) 2) (((current-frob)) 4) (otherwise 3))
is equivalent to
(let ((var (frob x))) (cond ((eq var foo) 1) ((or (eq var bar) (eq var baz)) 2) ((eq var (current-frob)) 4) (t 3)))
selector
is like select
, except that you get to specify the function
used for the comparison instead of eq
. For example,
(selector (frob x) equal (('(one . two)) (frob-one x)) (('(three . four)) (frob-three x)) (otherwise (frob-any x)))
is equivalent to
(let ((var (frob x))) (cond ((equal var '(one . two)) (frob-one x)) ((equal var '(three . four)) (frob-three x)) (t (frob-any x))))
select-match
is like select
but each clause can specify a pattern
to match the key against. The general form of use looks like
(select-match key-form (pattern condition body...) (pattern condition body...) ... (otherwise body...))
The value of key-form is matched against the patterns one at a
time until a match succeeds and the accompanying condition evaluates
to something non-nil
. At this point the body of that clause is
executed and its value(s) returned. If all the patterns/conditions
fail, the body of the otherwise
clause (if any) is executed. A
pattern can test the shape of the key object, and set variables
which the condition form can refer to. All the variables set by the
patterns are bound locally to the select-match
form.
The patterns are matched using list-match-p
(list-match-p-fun).
Example:
(select-match '(a b c) (`(,x b ,x) t (vector x)) (`((,x ,y) b . ,ignore) t (list x y)) (`(,x b ,y) (symbolp x) (cons x y)) (otherwise 'lose-big))
returns (a . c)
, having checked (symbolp 'a)
. The first clause
matches only if the there are three elements, the first and third
elements are equal
and the second element is b
. The second
matches only if the first element is a list of length two and the second
element is b
. The third clause accepts any list of length three
whose second element is b
. The fourth clause accepts anything that did
not match the previous clauses.
select-match
generates highly optimized code using special
instructions.
(dispatch byte-specifier number clauses...)
is the same
as select
(not selectq
), but the key is obtained by evaluating
(ldb byte-specifier number)
.
byte-specifier and number are both evaluated. Byte specifiers
and ldb
are explained on ldb-fun.
Example:
(princ (dispatch (byte 2 13) cat-type (0 "Siamese.") (1 "Persian.") (2 "Alley.") (3 (ferror nil "~S is not a known cat type." cat-type))))
It is not necessary to include all possible values of the byte which is dispatched on.
selectq-every
has the same syntax as selectq
, but, like
cond-every
, executes every selected clause instead of just the first
one. If an otherwise
clause is present, it is selected if and only
if no preceding clause is selected. The value returned is the value of
the last form in the last selected clause. Multiple values are not
returned. Example:
(selectq-every animal ((cat dog) (setq legs 4)) ((bird man) (setq legs 2)) ((cat bird) (put-in-oven animal)) ((cat dog man) (beware-of animal)))
(eq x y) => t
if and only if x and y are the same object.
It should be noted that things that print the same are not necessarily eq
to each other.
In particular, numbers with the same value
need not be eq
, and two similar lists are usually not eq
.
Examples:
(eq 'a 'b) => nil (eq 'a 'a) => t (eq (cons 'a 'b) (cons 'a 'b)) => nil (setq x (cons 'a 'b)) (eq x x) => t
Note that in Zetalisp equal fixnums are eq
; this is not true in Maclisp.
Equality does not imply eq
-ness for other types of numbers. To compare numbers,
use =
; see =-fun.
(neq x y)
= (not (eq x y))
. This is provided
simply as an abbreviation for typing convenience.
eql
is the same as eq
except that if x and y are numbers
of the same type they are eql
if they are =
.
The equal
predicate returns t
if its arguments are similar
(isomorphic) objects.
Two numbers are equal
if they have the same value and type (for
example, a float is never equal
to a fixnum, even if =
is true of them).
For conses, equal
is defined
recursively as the two cars being equal
and the two cdrs
being equal. Two strings are equal
if they have the same length,
and the characters composing them are the same; see string=
,
string=-fun. Alphabetic case is significant. All other objects
are equal
if and only if they are eq
. Thus equal
could have
been defined by:
(defun equal (x y) (cond ((eq x y) t) ((and (numberp x) (numberp y)) (= x y)) ((and (stringp x) (stringp y)) (string-equal x y)) ((and (consp x) (consp y)) (and (equal (car x) (car y)) (equal (cdr x) (cdr y))))))
As a consequence of the above definition, it can be seen that
equal
may compute forever when applied to looped list structure.
In addition, eq
always implies equal
; that is, if (eq a b)
then (equal a b)
. An intuitive definition of equal
(which is
not quite correct) is that two objects are equal
if they look the
same when printed out. For example:
(setq a '(1 2 3)) (setq b '(1 2 3)) (eq a b) => nil (equal a b) => t (equal "Foo" "foo") => nil
equalp
is a broader kind of equality than equal
. Two objects that
are equal
are always equalp
. In addition,
numbers of different types are equalp
if they are =
. Two character
objects are equalp
if they are char-equal
(that is, they are compared
ignoring font, case and meta bits).
Two arrays of any sort are equalp
if they have the same dimensions
and corresponding elements are equalp
. In particular, this means
that two strings are equalp
if they match ignoring case and font information.
(equalp "Foo" "foo") => t (equalp '1 '1.0) => t (equalp '(1 "Foo") '(1.0 "foo")) => t
Because equalp
is a Common Lisp function, it regards a string as having
character objects as its elements:
(equalp "Foo" #(#/F #/o #/o)) => t (equalp "Foo" #(#/F #/o #/o)) => nil
not
returns t
if x is nil
, else nil
.
null
is the same as not
; both functions are included for the sake
of clarity. Use null
to check whether something is nil
; use not
to invert the sense of a logical value. Some people prefer to distinguish
between nil
as falsehood and nil
as the empty list by writing:
(cond ((not (null lst)) ... )
( ... ))
rather than
(cond (lst ... )
( ... ))
There is no loss of efficiency, since these compile into exactly the same instructions.
The do
special form provides a simple generalized iteration facility,
with an arbitrary number of “index variables” whose values are saved
when the do
is entered and restored when it is left, ie they are
bound by the do
. The index variables are used in the iteration
performed by do
. At the beginning, they are initialized to
specified values, and then at the end of each trip around the loop the
values of the index variables are changed according to specified
rules. do
allows the programmer to specify a predicate which
determines when the iteration will terminate. The value to be
returned as the result of the form may, optionally, be specified.
do
comes in two varieties, new-style and old-style. The old-style
do
is obsolete and exists for Maclisp compatibility only.
The more general, “new-style” do
looks like:
(do ((var init repeat) ...) (end-test exit-form ...) body...)
The first item in the form is a list of zero or more index variable
specifiers. Each index variable specifier is a list of the name of a
variable var, an initial value form init, which defaults to nil
if it is omitted, and a repeat value form repeat. If repeat is
omitted, the var is not changed between repetitions. If init is
omitted, the var is initialized to nil
.
An index variable specifier can also be just the name of a variable,
rather than a list. In this case, the variable has an initial value of
nil
, and is not changed between repetitions.
All assignment to the index variables is done in parallel. At the
beginning of the first iteration, all the init forms are evaluated,
then the vars are bound to the values of the init forms, their
old values being saved in the usual way. Note that the init forms
are evaluated before the vars are bound, ie lexically
outside of the do
. At the beginning of each succeeding
iteration those vars that have repeat forms get set to the
values of their respective repeat forms. Note that all the
repeat forms are evaluated before any of the vars is set.
The second element of the do
-form is a list of an end-testing
predicate form end-test, and zero or more forms, called the
exit-forms. This resembles a cond
clause. At the beginning of
each iteration, after processing of the variable specifiers, the
end-test is evaluated. If the result is nil
, execution proceeds
with the body of the do
. If the result is not nil
, the
exit-forms are evaluated from left to right and then do
returns.
The value of the do
is the value of the last exit-form, or
nil
if there were no exit-forms (not the value of the
end-test, as you might expect by analogy with cond
).
Note that the end-test gets evaluated before the first time the body
is evaluated. do
first initializes the variables from the init
forms, then it checks the end-test, then it processes the body, then
it deals with the repeat forms, then it tests the end-test
again, and so on. If the end-test
returns a non-nil
value the
first time, then the body is not executed.
If the second element of the form is nil
, there is no end-test
nor exit-forms, and the body of the do
is executed only
once. In this type of do
it is an error to have repeats. This
type of do
is no more powerful than let
; it is obsolete
and provided only for Maclisp compatibility.
If the second element of the form is (nil)
, the end-test is
never true and there are no exit-forms. The body of the do
is executed over and over. The resulting infinite loop can be terminated by use
of return
or throw
.
do
implicitly creates a block
with name nil
, so return
can be used lexically within a do
to exit it immediately. This
unbinds the do
variables and the do
form returns whatever values
were specified in the return
form. See block-and-return-section
for more information on these matters. The body of the do
is
actually treated as a tagbody
, so that it may contain go
tags
(see go-to), but this usage is discouraged as it is often unclear.
Examples of the new form of do
:
(do ((i 0 (1+ i)) ; This is just the same as the above example, (n (array-length foo-array))) ((= i n)) ; but written as a new-styledo
. (aset 0 foo-array i)) ; Note how thesetq
is avoided.
(do ((z list (cdr z)) ; z starts aslist
and is cdr’d each time. (y other-list) ; y starts asother-list
, and is unchanged by the do. (x) ; x starts asnil
and is not changed by thedo
. w) ; w starts asnil
and is not changed by thedo
. (nil) ; The end-test isnil
, so this is an infinite loop. body) ; Presumably the body usesreturn
somewhere.
The construction
(do ((x e (cdr x)) (oldx x x)) ((null x)) body)
exploits parallel assignment to index variables. On the first
iteration, the value of oldx
is whatever value x
had before
the do
was entered. On succeeding iterations, oldx
contains
the value that x
had on the previous iteration.
The body of a do
may contains no forms at all. Very often an
iterative algorithm can be most clearly expressed entirely in the
repeats and exit-forms of a new-style do
, and the body
is empty. For example,
(do ((x x (cdr x)) (y y (cdr y)) (z nil (cons (f x y) z))) ;exploits parallel assignment. ((or (null x) (null y)) (nreverse z)) ;typical use ofnreverse
. ) ;nodo
-body required. is like(maplist 'f x y)
(see maplist-fun).
The old-style do
exists only for Maclisp
compatibility. It looks like:
(do var init repeat end-test body...)
The first time through the loop var gets the value of the init form;
the remaining times through the loop it gets the value of the repeat form,
which is re-evaluated each time. Note that the init form is evaluated
before var is bound, ie lexically outside of the do
.
Each time around the loop, after var is set,
end-test is evaluated. If it is non-nil
, the do
finishes
and returns nil
. If the end-test evaluated to nil
, the body of
the loop is executed. As with the new-style do, return
and go
may be used in the body, and they have the same meaning.
Also see loop
(loop-fun), a general iteration facility based on a keyword
syntax rather than a list-structure syntax.
In a word, do*
is to do
as let*
is to let
.
do*
works like do
but binds and steps the variables sequentially
instead of in parallel. This means that the init form for one
variable can use the values of previous variables. The repeat forms
refer to the new values of previous variables instead of their old
values. Here is an example:
(do* ((x xlist (cdr x)) (y (car x) (car x))) (print (list x y)))
On each iteration, y’s value is the car of x. The same
construction with do
might get an error on entry since x
might not be bound yet.
do-named
is like do
but defines a block
with a name
explicitly specified by the programmer in addition to the block
named nil
which every do
defines. This makes it possible to
use return-from
to return from this do-named
even from within
an inner do
. An ordinary return
there would return from the
inner do
instead. do-named
is obsolete now that block
,
which is more general and more coherent, exists. See
block-and-return-section for more information on block
and
return-from
.
The syntax of do-named
is like do
except that the symbol do-named
is
immediately followed by the block
name, which should be a symbol.
Example:
(do-named george ((a 1 (1+ a)) (d 'foo)) ((> a 4) 7) (do ((c b (cdr c))) ((null c)) ... (return-from george (cons b d)) ...))
is equivalent to
(block george (do ((a 1 (1+ a)) (d 'foo)) ((> a 4) 7) (do ((c b (cdr c))) ((null c)) ... (return-from george (cons b d)) ...)))
t
as the name of a do-named
behaves somewhat peculiarly, and
therefore should be avoided.
This special form offers a combination of the features of do*
and
those of do-named
. It is obsolete, as is do-named
,
since it is cleaner to use block
.
dotimes
is a convenient abbreviation for the most common integer
iteration. dotimes
performs body the number of times given by
the value of count, with index bound to 0
, 1
, etc. on
successive iterations. When the count is exhausted, the value of
value-expression is returned; or nil
, if value-expression
is missing.
Example:
(dotimes (i (truncate m n)) (frob i))
is equivalent to:
(do ((i 0 (1+ i)) (count (truncate m n))) (( i count)) (frob i))
except that the name count
is not used. Note that i
takes on
values starting at zero rather than one, and that it stops before taking
the value (truncate m n)
rather than after. You can use return
and
go
and tagbody
-tags inside the body, as with do
.
dotimes
forms return the value of value-expression, or nil
,
unless returned from explicitly with return
. For example:
(dotimes (i 5) (if (eq (aref a i) 'foo) (return i)))
This form searches the array that is the value of a
, looking for
the symbol foo
. It returns the fixnum index of the first element
of a
that is foo
, or else nil
if none of the elements
are foo
.
dolist
is a convenient abbreviation for the most common list
iteration. dolist
performs body once for each element in the
list which is the value of list, with item bound to the
successive elements. If the list is exhausted, the value of
value-expression is returned; or nil
, if
value-expression is missing.
Example:
(dolist (item (frobs foo)) (mung item))
is equivalent to:
(do ((lst (frobs foo) (cdr lst)) (item)) ((null lst)) (setq item (car lst)) (mung item))
except that the name lst
is not used.
You can use return
and go
and tagbody
-tags inside the body, as with do
.
Executes the forms in the body over and over, or until a non-local exit
(such as return
).
The static non-local exit allows code deep within a construct to jump
to the end of that construct instantly, not executing anything except
unwind-protect
’s on the way. The construct which defines a static level
that can be exited non-locally is called block
and the construct which
exits it is called return-from
. The block
being exited must be lexically
visible from the return-from
which says to exit it; this is what ‘static’ means. By contrast, catch
and throw
provide for dynamic non-local
exits; refer to the following section.
Here is an example of using a static non-local exit:
(block top (let ((v1 (do-1))) (when (all-done v1) (return-from top v1)) (do-2)) (do-3) ... (do-last))
If (all-done v1)
returns non-nil
, the entire block
immediately returns the value of v1
. Otherwise, the rest of the
body of the block is executed sequentially, and ultimately the value or
values of (do-last)
are returned.
Note that the return-from
form is very unusual: it does not ever
return a value itself, in the conventional sense. It isn’t useful to
write (setq a (return-from foo 3))
, because when the
return-from
form is evaluated, the containing block
is
immediately exited, and the setq
never happens.
The fact that block
’s and return-from
’s are matched up lexically
means you cannot do this:
(defun foo (a) (block foo1 (bar a))) (defun bar (x) (return-from foo1 x))
The (return-from foo1 x)
gets an error because there is no lexically
visible block
named foo1
. The suitable block
in the caller, foo
,
is not even noticed.
Static handling allows the compiler to produce good code for return-from
.
It is also useful with functional arguments:
(defun first-symbol (list) (block done (mapc #'(lambda (elt) (if (symbolp elt) (return-from done elt))) list)))
The return-from done
sees the block done
lexically.
Even if mapc
had a block
in it named done
it would
have no effect on the execution of first-symbol
.
When a function is defined with defun
with a name which is a symbol,
a block
whose name is the function name is automatically placed around
the body of the function definition. For example,
(defun foo (a) (if (evenp a) (return-from foo (list a))) (1+ a)) (foo 4) => (4) (foo 5) => 6
A function written explicitly with lambda
does not have a block
unless you write one yourself.
A named prog
, or a do-named
, implicitly defines a block
with
the specified name. So you can exit those constructs with return-from
.
In fact, the ability to name prog
’s was the original way to define
a place for return-from
to exit, before block
was invented.
Every prog
, do
or loop
, whether named or not, implicitly
defines a block
named nil
. Thus, named prog
’s define two
block
’s, one named nil
and one named whatever name you specify.
As a result, you can use return
(an abbreviation for return-from nil
)
to return from the innermost lexically containing prog
, do
or
loop
(or from a block nil
if you happen to write one).
This function is like assq
, but it returns an additional value
which is the index in the table of the entry it found. For example,
(defun assqn (x table) (do ((l table (cdr l)) (n 0 (1+ n))) ((null l) nil) (if (eq (caar l) x) (return (values (car l) n)))))
There is one exception to this: a prog
, do
or loop
with
name t
defines only the block named t
, no block named nil
.
The compiler used to make use of this feature in expanding certain built-in
constructs into others.
Executes body, returning the values of the last form in body,
but permitting non-local exit using return-from
forms present
lexically within body. name is not evaluated, and is used
to match up return-from
forms with their block
’ss.
(block foo (return-from foo 24) t) => 24 (block foo t) => t
Performs a non-local exit from the innermost lexically containing
block
whose name is name. name is not evaluated.
When the compiler is used, return-from
’s are matched up with
block
’s at compile time.
values is evaluated and its values
become the values of the exited block
form.
A return-from
form may appear as or inside an argument to a regular
function, but if the return-from
is executed then the function will never
actually be called. For example,
(block done (foo (if a (return-from done t) nil)))
foo
is actually called only if a
’s value is nil
.
This style of coding is not recommended when foo
is actually a function.
return-from
can also be used with zero value forms, or with several
value forms. Then one value is returned from each value form.
Originally return-from
always returned only one value from each
value form, even when there was only one value form. Passing
back all the values when there is a single values form is a later
change, which is also the Common Lisp standard. In fact, the single
value form case is much more powerful and subsumes all the others.
For example,
(return-from foo 1 2)
is equivalent to
(return-from foo (values 1 2))
and
(return-from foo)
is equivalent to
(return-from foo (values))
It is unfortunate that the case of one value form is treated differently from all other cases, but the power of being able to propagate any number of values from a single form is worth it.
To return precisely one value, use (return-from foo (values form))
.
It is legal to write simply (return-from foo)
, which returns no
values from the block
.
See multiple-value for more information.
Is equivalent to (return-from nil values)
.
It returns from a block
whose name is nil
.
In addition, break
(see break-fun) recognizes the typed-in form
(return value)
specially. break
evaluates value
and returns it.
This function is like return
except that each element of list
is returned as a separate value from the block
that is exited.
return-list
is obsolete, since (return (values-list list))
does the same thing.
Jumping to a label or tag is another kind of static non-local exit. Compared with
return-from
, it allows more flexibility in choosing where to send
control to, but does not allow values to be sent along. This is because
the tag does not have any way of saying what to do with any
values.
To define a tag, the tagbody
special form is used.
In the body of a tagbody
, all lists are treated as forms to be
evaluated (called statements when they occur in this context).
If no goto happens, all the forms are evaluated in sequence
and then the tagbody
form returns nil
. Thus, the statements
are evaluated only for effect.
An element of the tagbody
’s body which is a symbol is not a statement
but a tag instead. It identifies a place in the sequence of statements
which you can go to. Going to a tag is accomplished by the form
(go tag)
, executed at any point lexically within the tagbody
.
go
transfers control immediately to the first statement following
tag in its tagbody
, pausing only to deal with any
unwind-protect
s that are being exited as a result. If there are
no more statements after tag in its tagbody
, then that tagbody
returns nil
immediately.
All lexically containing tagbody
’s are eligible to contain the
specified tag, with the innermost tagbody
taking priority. If no
suitable tag is found, an error is signaled. The compiler matches
go
’s with tags at compile time and issues a compiler warning if no
tag is found. Example:
(block nil (tagbody (setq x some frob) loop do something (if some predicate (go endtag)) do something more (if (minusp x) (go loop)) endtag (return z)))
is a kind of iteration made out of go-to’s. This
tagbody
can never exit normally because the return
in the last
statement takes control away from it. This use of a return
and block
is how one encapsulates a tagbody
to produce a non-nil
value.
It works to go
from an internal lambda
function to a tag
in a lexically containing function, as in
(defun foo (a) (tagbody t1 (bar #'(lambda () (go t1)))))
If bar
ever invokes its argument, control goes to t1
and
bar
is invoked anew. Not very useful, but it illustrates the technique.
Executes all the elements of statements-and-tags which are lists (the statements),
and then returns nil
. But meanwhile, all elements of statements-and-tags
which are symbols (the tags) are available for use with go
in any of the
statements. Atoms other than symbols are meaningless in a tagbody
.
The reason that tagbody
returns nil
rather than the value of the last
statement is that the designers of Common Lisp decided that one could not
reliably return a value from the tagbody
by writing it as the last statement
since some of the time the expression for the desired value would be a symbol
rather than a list, and then it would be taken as a tag rather than the last statement
and it would not work.
The go
special form is used to “go-to” a tag defined
in a lexically containing tagbody
form (or other form which
implicitly expands into a tagbody
, such as prog
, do
or loop
).
tag must be a symbol. It is not evaluated.
prog
is an archaic special form which provides temporary variables,
static non-local exits, and tags for go
. These aspects of prog
were individually abstracted out to inspire let
, block
and
tagbody
. Now prog
is obsolete, as it is much cleaner to use
let
, block
, tagbody
or all three of them, or do
or
loop
. But prog
appears in so many programs that it cannot be
eliminated.
A typical prog
looks like (prog (variables...) body...)
,
which is equivalent to
(block nil (let (variables...) (tagbody body...)))
If the first subform of a prog
is a non-nil
symbol (rather than
a list of variables), it is the name of the prog
, and return-from
(see return-from-fun) can be used to return from it. A named prog
looks like
(prog name (variables...) body...)
and is equivalent to
(block name (block nil (let (variables...) (tagbody body...))))
The prog*
special form is almost the same as prog
. The only
difference is that the binding and initialization of the temporary
variables is done sequentially, so each one can depend on the
previous ones. Thus, the equivalent code would use let*
rather
than let
.
catch
is a special form used with the throw
function to do
non-local exits. First tag is evaluated; the result is called the tag
of the catch
. Then the body forms are evaluated sequentially,
and the values of the last form are returned. However, if,
during the evaluation of the body, the
function throw
is called with the same tag as the tag of the
catch
, then the evaluation of the body is aborted, and the
catch
form immediately returns the values of the second
argument to throw
without further evaluating the current body form or
the rest of the body.
The tag’s are used to match up throw
’s with catch
’s.
(catch 'foo form)
catches a (throw 'foo form)
but
not a (throw 'bar form)
. It is an error if throw
is done
when there is no suitable catch
(or catch-all
; see below).
Any Lisp object may be used as a catch
tag.
The values t
and nil
for tag are special: a catch
whose
tag is one of these values catches throws regardless of tag. These are only
for internal use by unwind-protect
and catch-all
respectively.
The only difference between t
and nil
is in the error checking;
t
implies that after a “cleanup handler” is executed control will be
thrown again to the same tag, therefore it is an error if a specific
catch for this tag does not exist higher up in the stack. With nil
,
the error check isn’t done. Example:
(catch 'negative (values (mapcar #'(lambda (x) (cond ((minusp x) (throw 'negative (values x :negative))) (t (f x)) ))) y) :positive))
returns a list of f
of each element of y
, and :positive
, if they are all
positive, otherwise the first negative member of y
, and :negative
.
The catch-continuation
special form makes it convenient to
discriminate whether exit is normal or due to a throw.
The body is executed inside a catch
on tag (which is
evaluated). If body returns normally, the function
non-throw-cont is called, passing all the values returned by the
last form in body as arguments. This function’s values are returned
from the catch-continuation
.
If on the other hand a throw to tag occurs, the values thrown are passed to the function throw-cont, and its values are returned.
If a continuation is explicitly written as nil
, it is
not called at all. The arguments that would have been passed to it are
returned instead. This is equivalent to using values
as the
function; but explicit nil
is optimized, so use that.
catch-continuation-if
differs only in that the catch is not done if
the value of the cond-form is nil
. In this case, the non-throw
continuation if any is always called.
In the general case, consing is necessary to record the multiple values,
but if a continuation is an explicit #'(lambda ...)
with a
fixed number of arguments, or if a continuation is nil
, it is open
coded and the consing is avoided.
throw
is the primitive for exiting from a surrounding catch
.
tag is evaluated, and the result is matched (with eq
) against
the tags of all active catch
’es; the innermost matching one is exited.
If no matching catch
is dynamically active, an error is signaled.
All the values of values-form are returned from the exited catch
.
catch
’es with tag nil
always match any throw
. They are
really catch-all
’s. So do catch
’es with tag t
, which are
unwind-protect
’s, but if the only matching catch
’es are these
then an error is signaled anyway. This is because an unwind-protect
always throws again after its cleanup forms are finished; if there
is nothing to catch after the last unwind-protect
, an error will
happen then, and it is better to detect the error sooner.
The values t
, nil
, and 0
for tag are reserved and used
for internal purposes. nil
may not be used, because it would cause
confusion in handling of unwind-protect
’s. t
may only be
used with *unwind-stack
. 0
and nil
are used internally when
returning out of an unwind-protect
.
sys:throw-tag-not-seen
: (error
) ¶This is signaled when throw
(or *unwind-stack
) is used and
there is no catch
for the specified tag. The condition instance
supports these extra operations:
:tag
The tag being thrown to.
:value
The value being thrown (the second argument to throw
).
:count
:action
The additional two arguments given to *unwind-stack
, if that was used.
The error occurs in the environment of the throw
; no unwinding has yet taken place.
The proceed type :new-tag
expects one argument, a tag to throw to instead.
This is a generalization of throw
provided for program-manipulating
programs such as the debugger.
tag and value are the same as the corresponding arguments to
throw
.
A tag of t
invokes a special feature whereby the entire stack is
unwound, and then the function action is called (see below). During
this process unwind-protect
’s receive control, but catch-all
’s do
not. This feature is provided for the benefit of system programs which
want to unwind a stack completely.
active-frame-count, if non-nil
, is the number of frames
to be unwound. The definition of a frame is implementation-dependent.
If this counts down to zero before a suitable catch
is found, the *unwind-stack
terminates and
that frame returns value to whoever called it.
This is similar to Maclisp’s freturn
function.
If action is non-nil
, whenever the *unwind-stack
would be
ready to terminate (either due to active-frame-count or due to
tag being caught as in throw
), instead action is called
with one argument, value. If tag is t
, meaning throw out
the whole way, then the function action is not allowed to return.
Otherwise the function action may return and its value will be
returned instead of value from the catch
–or from an arbitrary
function if active-frame-count is in use. In this case the
catch
does not return multiple values as it normally does when
thrown to. Note that it is often useful for action to be a
stack-group.
Note that if both active-frame-count and action are nil
,
*unwind-stack
is identical to throw
.
Sometimes it is necessary to evaluate a form and make sure that certain side-effects take place after the form is evaluated; a typical example is:
(progn (turn-on-water-faucet) (hairy-function 3 nil 'foo) (turn-off-water-faucet))
The non-local exit facilities of Lisp create situations in which the
above code won’t work, however: if hairy-function
should use
throw
, return
or go
to transfer control outside of the
progn
form, then (turn-off-water-faucet)
will never be evaluated
(and the faucet will presumably be left running). This is particularly
likely if hairy-function
gets an error and the user tells the
debugger to give up and flush the computation.
In order to allow the above program to work, it can
be rewritten using unwind-protect
as follows:
(unwind-protect (progn (turn-on-water-faucet) (hairy-function 3 nil 'foo)) (turn-off-water-faucet))
If hairy-function
transfers control out of the
evaluation of the unwind-protect
, the
(turn-off-water-faucet)
form is evaluated during the
transfer of control, before control arrives at the
catch
, block
or go
tag to which it is being transferred.
If the progn
returns normally, then the (turn-off-water-faucet)
is evaluated, and the unwind-protect
returns the result of the progn
.
The general form of unwind-protect
looks like
(unwind-protect protected-form cleanup-form1 cleanup-form2 ...)
protected-form is evaluated, and when it returns or when it attempts
to transfer control out of the unwind-protect
, the cleanup-forms
are evaluated. The value of the unwind-protect
is the value of
protected-form. Multiple values returned by the protected-form
are propagated back through the unwind-protect
.
The cleanup forms are run in the variable-binding environment that you
would expect: that is, variables bound outside the scope of the
unwind-protect
special form can be accessed, but variables bound
inside the protected-form can’t be. In other words, the stack is
unwound to the point just outside the protected-form, then the
cleanup handler is run, and then the stack is unwound some more.
(catch-all form)
is like (catch some-tag form)
except that it catches a
throw
to any tag at all. Since the tag thrown to
is one of the returned values, the caller of catch-all
may continue
throwing to that tag if he wants. The one thing that catch-all
does not catch is a *unwind-stack
with a tag of t
.
catch-all
is a macro which expands into catch
with a tag of nil
.
catch-all
returns all the values thrown to it, or returned by the
body, plus three additional values: the tag thrown to, the
active-frame-count, and the action. The tag value is nil
if the
body returned normally. The last two values are the third and fourth
arguments to *unwind-stack
(see *unwind-stack-fun) if that was
used, or nil
if an ordinary throw
was done or if the body
returned normally.
If you think you want this, most likely you are mistaken and you really
want unwind-protect
.
Mapping is a type of iteration in which a function is successively applied to pieces of a list. There are several options for the way in which the pieces of the list are chosen and for what is done with the results returned by the applications of the function.
For example, mapcar
operates on successive elements of the list.
As it goes down the list, it calls the function giving it an element
of the list as its one argument: first the car, then the
cadr, then the caddr, etc., continuing until the end of the
list is reached. The value returned by mapcar
is a list of the
results of the successive calls to the function. An example of the
use of mapcar
would be mapcar
’ing the function abs
over
the list (1 -2 -4.5 6.0e15 -4.2)
, which would be written as
(mapcar (function abs) '(1 -2 -4.5 6.0e15 -4.2))
.
The result is (1 2 4.5 6.0e15
4.2)
.
In general, the mapping functions take any number of arguments. For example,
(mapcar f x1 x2 ... xn)
In this case f must be a function of n arguments.
mapcar
proceeds
down the lists x1, x2, ..., xn in parallel.
The first argument to f
comes from x1, the second from x2, etc.
The iteration stops as soon as any of the lists is exhausted.
(If there are no lists at all, then there are no lists to be exhausted,
so f is called repeatedly without end. This is an
obscure way to write an infinite loop. It is supported for
consistency.) If you want to call a function of many arguments
where one of the arguments successively takes on the values of the elements
of a list and the other arguments are constant, you can use a circular
list for the other arguments to mapcar
. The function circular-list
is useful for creating such lists; see circular-list-fun.
There are five other mapping functions besides mapcar
. maplist
is like mapcar
except that the function is applied to the list and
successive cdrs of that list rather than to successive elements of the
list. map
(or mapl
) and mapc
are like maplist
and mapcar
respectively, except that they don’t return any useful value. These
functions are used when the function is being called merely for its
side-effects, rather than its returned values. mapcan
and
mapcon
are like mapcar
and maplist
respectively, except
that they combine the results of the function using nconc
instead
of list
. That is, mapcon
could have been defined by
(defun mapcon (f x y) (apply 'nconc (maplist f x y)))
Of course, this definition is less general than the real one.
Sometimes a do
or a straightforward recursion is preferable to a
map; however, the mapping functions should be used wherever they
naturally apply because this increases the clarity of the code.
Often f is a lambda-expression, rather than a symbol; for example,
(mapcar (function (lambda (x) (cons x something))) some-list)
The functional argument to a mapping function must be a function, acceptable
to apply
–it cannot be a macro or the name of a special form.
Here is a table showing the relations between the six map functions.
applies function to | successive | successive | | sublists | elements | ---------------+--------------+---------------+ its own | | | second | map(l) | mapc | argument | | | ---------------+--------------+---------------+ list of the | | | returns function | maplist | mapcar | results | | | ---------------+--------------+---------------+ nconc of the | | | function | mapcon | mapcan | results | | | ---------------+--------------+---------------+
Note that map
and mapl
are synonymous. map
is the
traditional name of this function. mapl
is the Common Lisp name.
In Common Lisp, the function map
does something different and
incompatible; see cli:map
, cli:map-fun. mapl
works the same
in traditional Zetalisp and Common Lisp.
There are also functions (mapatoms
and mapatoms-all
)
for mapping over all symbols in certain
packages. See the explanation of packages (package).
You can also do what the mapping functions do in a different way by using
loop
. See loop-fun.
This chapter discusses functions that manipulate conses, and higher-level structures made up of conses such as lists and trees. It also discusses hash tables and resources, which are related facilities.
A cons is a primitive Lisp data object that is extremely simple: it knows about two other objects, called its car and its cdr.
A list is recursively defined to be the symbol nil
, or a cons whose
cdr is a list. A typical list is a chain of conses: the cdr of each is
the next cons in the chain, and the cdr of the last one is the symbol
nil
. The cars of each of these conses are called the elements
of the list. A list has one element for each cons; the empty list,
nil
, has no elements at all. Here are the printed representations
of some typical lists:
(foo bar) ;This list has two elements. (a (b c d) e) ;This list has three elements.
Note that the second list has three elements: a
, (b c d)
, and e
.
The symbols b
, c
, and d
are not elements of the list itself.
(They are elements of the list which is the second element of the original
list.)
A dotted list is like a list except that the cdr of the last cons does
not have to be nil
. This name comes from the printed
representation, which includes a “dot” character (period). Here is an example:
(a b . c)
This dotted list is made of two conses. The car of the first cons is the
symbol a
, and the cdr of the first cons is the second cons. The car of
the second cons is the symbol b
, and the cdr of the second cons is
the symbol c
.
A tree is any data structure made up of conses whose cars and cdrs are other conses. The following are all printed representations of trees:
(foo . bar) ((a . b) (c . d)) ((a . b) (c d e f (g . 5) s) (7 . 4))
These definitions are not mutually exclusive. Consider a cons whose
car is a
and whose cdr is (b (c d) e)
. Its printed
representation is
(a b (c d) e)
It can be thought of and treated as a cons, or as a list of four
elements, or as a tree containing six conses. You can even think of it
as a dotted list whose last cons just happens to have nil
as a
cdr. Thus, lists and dotted lists and trees are not fundamental data
types; they are just ways of thinking about structures of conses.
A circular list is like a list except that the cdr of the last cons,
instead of being nil
, is the first cons of the list. This means that
the conses are all hooked together in a ring, with the cdr of each cons
being the next cons in the ring. These are legitimate Lisp objects,
but dealing with them requires special techniques; straightforward
tree-walking recursive functions often loop infinitely when given a
circular list. The printer is is an example of both aspects of the
handling of circular lists: if *print-circle*
is non-nil
the
printer uses special techniques to detect circular structure and print
it with a special encoding, but if *print-circle*
is nil
the
printer does not check for circularity and loops infinitely unless
*print-level*
or *print-length*
imposes a “time limit”.
See *print-circle*-var for more information on *print-circle*
and related matters.
The Lisp Machine internally uses a storage scheme called cdr-coding to represent conses. This scheme is intended to reduce the amount of storage used in lists. The use of cdr-coding is invisible to programs except in terms of storage efficiency; programs work the same way whether or not lists are cdr-coded or not. Several of the functions below mention how they deal with cdr-coding. You can completely ignore all this if you want. However, if you are writing a program that allocates a lot of conses and you are concerned with storage efficiency, you may want to learn about the cdr-coded representation and how to control it. The cdr-coding scheme is discussed in cdr-code.
Returns the car of x.
Example:
(car '(a b c)) => a
Returns the cdr of x.
Example:
(cdr '(a b c)) => (b c)
Officially car
and cdr
are only applicable to conses and locatives.
However, as a matter of convenience, car
and cdr
of nil
return nil
.
car
or cdr
of anything else is an error.
All of the compositions of up to four car
’s and cdr
’s are
defined as functions in their own right. The names of these functions
begin with c
and end with r
, and in between is a sequence of
a
’s and d
’s corresponding to the composition performed by the
function.
Example:
(cddadr x) is the same as (cdr (cdr (car (cdr x))))
The error checking for these functions is exactly the same as for car
and cdr
above.
cons
is the primitive function to create a new cons, whose
car is x and whose cdr is y.
Examples:
(cons 'a 'b) => (a . b) (cons 'a (cons 'b (cons 'c nil))) => (a b c) (cons 'a '(b c d)) => (a b c d)
(ncons x)
is the same as (cons x nil)
.
The name of the function is from “nil-cons”.
xcons
(“exchanged cons”) is like cons
except that the order of
the arguments is reversed.
Example:
(xcons 'a 'b) => (b . a)
Creates a cons in a specific area. (Areas are
an advanced feature of storage management, explained in chapter
area-chapter; if you aren’t interested in them, you can safely skip
all this stuff). The first two arguments are the same as the two
arguments to cons
, and the third is the number of the area in which
to create the cons.
Example:
(cons-in-area 'a 'b my-area) => (a . b)
(ncons-in-area x area-number)
= (cons-in-area x nil area-number)
(xcons-in-area x y area-number) = (cons-in-area y x area-number)
Adds an element item to the front of a list that is stored in place. A new cons is allocated whose car is item and whose cdr is the old contents of place. This cons is stored into place.
The form
(push (hairy-function x y z) variable)
replaces the commonly-used construct
(setq variable (cons (hairy-function x y z) variable))
and is intended to be more explicit and esthetic.
place can be any form that setf
can store into.
For example,
(push x (get y z)) ==> (putprop y (cons x (get y z)) z)
The returned value of push
is not defined.
Removes an element from the front of the list that is stored in
place. It finds the cons in place, stores the cdr of the cons
back into place, and returns the car of that cons. place
can be any form that setf
can store into.
Example:
(setq x '(a b c)) (pop x) => a x => (b c)
The backquote reader macro facility is also generally useful for creating list structure, especially mostly-constant list structure, or forms constructed by plugging variables into a template. It is documented in the chapter on macros; see macro.
car-location
returns a locative pointer to the cell containing
the car of cons.
Note: there is no cdr-location
function; it is difficult because of
the cdr-coding scheme (see cdr-code). Instead, the cons itself
serves as a kind of locative to its cdr (see contents-fun).
The functions rplaca
and rplacd
are used to make alterations
in already-existing list structure; that is, to change the cars and
cdrs of existing conses. The structure is altered rather than copied.
Exercise caution when using these functions, as strange side-effects
can occur if they are used to modify portions of list structure which
have become shared unbeknownst to the programmer. The nconc
,
nreverse
, nreconc
, nbutlast
and delq
functions and
others, described below, have the same property, because they call
rplaca
or rplacd
.
Changes the car of x to y and returns (the modified) x. x must be a cons or a locative. y may be any Lisp object.
Example:
(setq g '(a b c))
(rplaca (cdr g) 'd) => (d c)
Now g => (a d c)
Changes the cdr of x to y and returns (the modified) x. x must be a cons or a locative. y may be any Lisp object.
Example:
(setq x '(a b c))
(rplacd x 'd) => (a . d)
Now x => (a . d)
(setf (car x) y)
and (setf (car x) y)
are much like rplaca
and rplacd
,
but they return y rather than x.
Constructs and returns a list of its arguments.
Example:
(list 3 4 'a (car '(b . c)) (+ 6 -2)) => (3 4 a b 4)
list
could have been defined by:
(defun list (&rest args) (let ((list (make-list (length args)))) (do ((l list (cdr l)) (a args (cdr a))) ((null a) list) (rplaca l (car a)))))
list*
is like list
except that the last cons
of the constructed list is dotted. It must be given at least
one argument.
Example:
(list* 'a 'b 'c 'd) => (a b c . d)
This is like
(cons 'a (cons 'b (cons 'c 'd)))
More examples:
(list* 'a 'b) => (a . b) (list* 'a) => a
Returns the length of list-or-array. The length of a list is the number of elements in it; the number of times you can cdr it before you get a non-cons.
Examples:
(length nil) => 0 (length '(a b c d)) => 4 (length '(a (b c) d)) => 3 (length "foobar") => 6
length
could have been defined by:
(defun length (x) (if (arrayp x) (array-active-length x) (do ((n 0 (1+ n)) (y x (cdr y))) ((null y) n))))
Returns the length of list, or nil
if list is circular.
(The function length
would loop forever if given a circular list.)
These functions take a list as an argument, and return the first,
second, etc. element of the list. first
is identical to car
,
second
is identical to cadr
, and so on. The reason these names
are provided is that they make more sense when you are thinking of the
argument as a list rather than just as a cons.
restn
returns the rest of the elements of a list, starting with
element n (counting the first element as the zeroth). Thus
rest
or rest1
is identical to cdr
, rest2
is identical to cddr
,
and so on. The reason these names are provided is that they make more
sense when you are thinking of the argument as a list rather than just
as a cons.
Returns t
if list is nil
, nil
if list is a cons
cell. Signals an error if list is not a list. This is the way
Common Lisp recommends for terminating a loop which cdr
’s down a list.
However, Lisp Machine system functions generally prefer to test for the
end of the list with atom
; it is regarded as a feature that these
functions do something useful for dotted lists.
(nth n list)
returns the n’th element of list, where
the zeroth element is the car of the list.
If n is greater than the length of the list, nil
is returned.
Examples:
(nth 1 '(foo bar gack)) => bar (nth 3 '(foo bar gack)) => nil
Note: this is not the same as the InterLisp function called nth
,
which is similar to but not exactly the same as the Lisp Machine function
nthcdr
.
Also, some people have used macros and functions called nth
of their own in
their Maclisp programs, which may not work the same way; be careful.
nth
could have been defined by:
(defun nth (n list) (do ((i n (1- i)) (l list (cdr l))) ((zerop i) (car l))))
(nthcdr n list)
cdrs list n times,
and returns the result.
Examples:
(nthcdr 0 '(a b c)) => (a b c) (nthcdr 2 '(a b c)) => (c)
In other words, it returns the n’th cdr of the list.
If n is greater than the length of the list, nil
is returned.
This is similar to InterLisp’s function nth
, except that the
InterLisp function is one-based instead of zero-based; see the
InterLisp manual for details.
nthcdr
could have been defined by:
(defun nthcdr (n list) (do ((i 0 (1+ i)) (list list (cdr list))) ((= i n) list)))
last
returns the last cons of list. If list is nil
, it
returns nil
. Note that last
is unfortunately not analogous
to first
(first
returns the first element of a list, but
last
doesn’t return the last element of a list); this is a
historical artifact.
Examples:
(setq x '(a b c d)) (last x) => (d) (rplacd (last x) '(e f)) x => '(a b c d e f)
last
could have been defined by:
(defun last (x) (cond ((atom x) x) ((atom (cdr x)) x) ((last (cdr x)))))
object is evaluated and matched against pattern;
the value is t
if it matches, nil
otherwise.
pattern is made with backquotes (backquote); whereas
normally a backquote expression says how to construct list structure out
of constant and variable parts, in this context it says how to match
list structure against constants and variables. Constant parts of the
backquote expression must match exactly; variables preceded by commas
can match anything but set the variable to what was matched. (Some of
the variables may be set even if there is no match.) If a variable
appears more than once, it must match the same thing (equal
list
structures) each time. ,ignore
can be used to match anything and
ignore it.
For example, `(x (,y) . ,z)
is a pattern that matches a list of
length at least two whose first element is x
and whose second
element is a list of length one; if a list matches, the caadr
of the
list is stored into the value of y and the cddr
of the list is
stored into z.
Variables set during the matching remain set after the list-match-p
returns; in effect, list-match-p
expands into code which can
setq
the variables. If the match fails, some or all of the
variables may already have been set.
Example:
(list-match-p foo `((a ,x) ,ignore . ,c))
is t
if foo
’s value is a list of two or more elements,
the first of which is a list of two elements;
and in that case it sets x
to (cadar foo)
and
c
to (cddr foo)
. An equivalent expression would be
(let ((tem foo)) (and (consp tem) (consp (car tem)) (eq (caar tem) 'a) (consp (cdar tem)) (progn (setq x (cadar tem)) t) (null (cddar tem)) (consp (cdr tem)) (setq c (cddr tem))))
but list-match-p
is faster.
list-match-p
generates highly optimized code using special
instructions.
list-in-area
is exactly the same as list
except that it takes
an extra argument, an area number, and creates the list in that area.
list*-in-area
is exactly the same as list*
except that it takes
an extra argument, an area number, and creates the list in that area.
Creates and returns a list containing length elements.
length should be a fixnum. area, if specified, is the area in
which to create the list (see area). If it is nil
, the area used
is the value of working-storage-area
.
initial-element is stored in each element of the new list.
make-list
always creates a cdr-coded list (see cdr-code).
Examples:
(make-list 3) => (nil nil nil) (make-list 4 :initial-element 7) => (7 7 7 7)
The keyword :initial-value
may be used in place of
:initial-element
.
When make-list
was originally implemented, it took exactly two
arguments: the area and the length. This obsolete form is still
supported so that old programs can continue to work, but the new
keyword-argument form is preferred.
Constructs a circular list whose elements are args
, repeated
infinitely. circular-list
is the same as list
except that the list itself
is used as the last cdr, instead of nil
.
circular-list
is especially useful with mapcar
, as in the expression
(mapcar (function +) foo (circular-list 5))
which adds each element of foo
to 5.
circular-list
could have been defined by:
(defun circular-list (&rest elements) (setq elements (copylist* elements)) (rplacd (last elements) elements) elements)
Returns a list which is equal
to list, but not eq
.
copylist
does not copy any elements of the list, only the conses of the list itself.
The returned list is fully cdr-coded (see cdr-code) to minimize storage.
If list is dotted, that is, if (cdr (last list))
is a non-nil
atom, then the copy also has this property.
You may optionally specify the area in which to create the new copy.
This is the same as copylist
except that the last cons of the
resulting list is never cdr-coded (see cdr-code). This makes for
increased efficiency if you nconc
something onto the list later.
copyalist
is for copying association lists (see
assoc-lists-section). The list is copied, as in copylist
.
In addition, each element of list which is a cons is replaced in the
copy by a new cons with the same car and cdr. You may optionally
specify the area in which to create the new copy.
The arguments to append
are lists. The result is a list which is the
concatenation of the arguments.
The arguments are not changed (cf nconc
).
Example:
(append '(a b c) '(d e f) nil '(g)) => (a b c d e f g)
append
makes copies of the conses of all the lists it is given,
except for the last one. So the new list shares the conses
of the last argument to append, but all of the other conses are newly
created. Only the lists are copied, not the elements of the lists.
A version of append
which only accepts two arguments could have been defined by:
(defun append2 (x y) (cond ((null x) y) ((cons (car x) (append2 (cdr x) y)) )))
The generalization to any number of arguments could then be made (relying on
car of nil
being nil
):
(defun append (&rest args) (if (< (length args) 2) (car args) (append2 (car args) (apply (function append) (cdr args)))))
These definitions do not express the full functionality of append
;
the real definition minimizes storage utilization by turning all the
arguments that are copied into one cdr-coded list.
To copy a list, use copylist
(see copylist-fun); the old practice
of using append
to copy lists is unclear and obsolete.
nconc
takes lists as arguments. It returns a list which is the arguments
concatenated together. The arguments are changed, rather than copied
(cf append
, append-fun).
Example:
(setq x '(a b c)) (setq y '(d e f)) (nconc x y) => (a b c d e f) x => (a b c d e f)
Note that the value of x
is now different, since its last cons has
been rplacd
’d to the value of y
. If the nconc
form were
evaluated again, it would yield a piece of circular list structure,
whose printed representation would be (a b c d e f d e f d e f ...)
, repeating forever.
nconc
could have been defined by:
(defun nconc (x y) ;for simplicity, this definition (cond ((null x) y) ;only works for 2 arguments. (t (rplacd (last x) y) ;hooky
onto x x))) ;and return the modifiedx
.
(revappend x y)
is exactly the same as
(nconc (reverse x) y)
except that it is more
efficient. Both x and y should be lists.
revappend
could have been defined by:
(defun revappend (x y) (cond ((null x) y) (t (revappend (cdr x) (cons (car x) y)))))
(nreconc x y)
is exactly the same as
(nconc (nreverse x) y)
except that it is more
efficient. Both x and y should be lists.
nreconc
could have been defined by:
(defun nreconc (x y) (cond ((null x) y) ((nreverse1 x y)) ))
using the same nreverse1
as above.
1
) ¶This creates and returns a list with the same elements as list, excepting the last n elements.
Examples:
(butlast '(a b c d)) => (a b c) (butlast '(a b c d) 3) => (a) (butlast '(a b c d) 4) => nil (butlast nil) => nil
The name is from the phrase “all elements but the last”.
1
) ¶This is the destructive version of butlast
; it changes the cdr of
the last cons but n of the list to nil
. The value is list,
as modified. If list does not have more than n elements then it
is not really changed and the value is nil
.
Examples:
(setq foo '(a b c d)) (nbutlast foo) => (a b c) foo => (a b c) (nbutlast foo 2) => (a) foo => (a) (nbutlast foo) => nil foo => (a)
Returns a list of length n, whose elements are the
first n elements of list
. If list is fewer than
n elements long, the remaining elements of the returned list
are nil
.
Examples:
(firstn 2 '(a b c d)) => (a b) (firstn 0 '(a b c d)) => nil (firstn 6 '(a b c d)) => (a b c d nil nil)
Returns a “tail” of list, i.e one of the conses that makes up list, or nil
.
(nleft n list)
returns the last n elements of list.
If n is too large, nleft
returns list.
(nleft n list tail)
takes cdr of list enough times
that taking n more cdrs would yield tail, and returns that.
You can see that when tail is nil
this is the same as the two-argument case.
If tail is not eq
to any tail of list, nleft
returns nil
.
Examples:
(setq x '(a b c d e f)) (nleft 2 x) => (e f) (nleft 2 x (cddddr x)) => (c d e f)
list should be a list, and tail should be one of the conses
that make up list. ldiff
(meaning ‘list difference’) returns
a new list, whose elements are those elements of list that appear
before tail.
Examples:
(setq x '(a b c d e)) (setq y (cdddr x)) => (d e) (ldiff x y) => (a b c) (ldiff x nil) => (a b c d e) (ldiff x x) => nil
but
(ldiff '(a b c d) '(c d)) => (a b c d)
since the tail was not eq
to any part of the list.
Return the same things as the corresponding non-safe
functions,
except nil
if the non-safe
function would get an error.
These functions are about as fast as the non-safe
functions.
The same effect could be had by handling the sys:wrong-type-argument
error, but that would be slower.
Examples:
(car-safe '(a . b)) => a (car-safe nil) => nil (car-safe 'a) => nil (car-safe "foo") => nil (cadr-safe '(a . b)) => nil (cadr-safe 3) => nil
copytree
copies all the conses of a tree and makes a new maximally
cdr-coded tree with the same fringe. If area is specified, the new
tree is constructed in that area.
Compares two trees recursively to all levels. Atoms must match under the
function test (which defaults to eql
). Conses must match recursively in
both the car and the cdr.
If test-not is specified instead of test, two atoms match if
test-not returns nil
.
(subst new old tree)
substitutes new for all occurrences of old
in tree, and returns the modified copy of tree. The original tree
is unchanged, as subst
recursively copies all of tree replacing
elements equal
to old as it goes.
Example:
(subst 'Tempest 'Hurricane '(Shakespeare wrote (The Hurricane))) => (Shakespeare wrote (The Tempest))
subst
could have been defined by:
(defun subst (new old tree) (cond ((equal tree old) new) ;if item equal to old, replace. ((atom tree) tree) ;if no substructure, return arg. ((cons (subst new old (car tree)) ;otherwise recurse. (subst new old (cdr tree))))))
Note that this function is not destructive; that is, it does not change the car or cdr of any already-existing list structure.
To copy a tree, use copytree
(see copytree-fun); the old practice
of using subst
to copy trees is unclear and obsolete.
The Common Lisp version of subst
replaces with new every atom or
subtree in tree which matches old, returning a new tree. List
structure is copied as necessary to avoid clobbering parts of tree.
This differs from the traditional subst
function, which always
copies the entire tree.
test or test-not is used to do the matching. If test is
specified, a match happens when test returns non-nil
; otherwise,
if test-not is specified, a match happens when it returns nil
.
If neither is specified, then eql
is used for test.
The first argument to the test or test-not function is always
old. The second argument is normally a leaf or subtree of
tree. However, if key is non-nil
, then it is called with
the subtree as argument, and the result of this becomes the second
argument to the test or test-not function.
Because (subst nil nil tree)
is a widely used idiom for copying
a tree, even though it is obsolete, there is no practical possibility of
installing this function as the standard subst
for a long time.
nsubst
is a destructive version of subst
. The list structure of
tree is altered by replacing each occurrence of old with
new. No new list structure is created. The keyword arguments are
as in cli:subst
.
A simplified version of nsubst
, handling only the three required
arguments, could be defined as
(defun nsubst (new old tree) (cond ((eql tree old) new) ;If item matches old, replace. ((atom tree) tree) ;If no substructure, return arg. (t ;Otherwise, recurse. (rplaca tree (nsubst new old (car tree))) (rplacd tree (nsubst new old (cdr tree))) tree)))
Replaces with new every atom or subtree in tree which satisfies
predicate. List structure is copied as necessary so that the
original tree is not modified. key, if non-nil
, is a function
applied to each tree node to get the object to match against. If key
is nil
or omitted, the tree node itself is used.
Similar, but replaces tree nodes which do not satisfy predicate.
Like subst-if
and subst-if-not
except that they destructively
modify tree itself and return it, creating no new list structure.
Performs multiple parallel replacements on tree, returning a new tree. tree itself is not modified because list structure is copied as necessary. If no substitutions are made, the result is tree. alist is an association list (see assoc-lists-section). Each element of alist specifies one replacement; the car is what to look for, and the cdr is what to replace it with.
test, test-not and key control how matching is done between
nodes of the tree (cons cells or atoms) and objects to be replaced. See
cli:subst
, above, for the details of how they work. The first
argument to test or test-not is the car of an element of
alist.
Example:
(sublis '((x . 100) (z . zprime)) '(plus x (minus g z x p) 4)) => (plus 100 (minus g zprime 100 p) 4)
A simplified sublis
could be defined by:
(defun sublis (alist tree) (let ((tem (assq tree alist))) (cond (tem (cdr tem)) ((atom tree) tree) (t (let ((car (sublis alist (car tree))) (cdr (sublis alist (cdr tree)))) (if (and (eq (car tree) car) (eq (cdr tree) cdr)) tree (cons car cdr)))))))
nsublis
is like sublis
but changes the original tree
instead of allocating new structure.
A simplified nsublis
could be defined by:
(defun nsublis (alist tree) (let ((tem (assq tree alist))) (cond (tem (cdr tem)) ((atom tree) tree) (t (rplaca tree (nsublis alist (car tree))) (rplacd tree (nsublis alist (cdr tree))) tree))))
This section explains the internal data format used to store conses inside the Lisp Machine. Casual users don’t have to worry about this; you can skip this section if you want. It is only important to read this section if you require extra storage efficiency in your program.
The usual and obvious internal representation of conses in any implementation of Lisp is as a pair of pointers, contiguous in memory. If we call the amount of storage that it takes to store a Lisp pointer a ‘word’, then conses normally occupy two words. One word (say it’s the first) holds the car, and the other word (say it’s the second) holds the cdr. To get the car or cdr of a list, you just reference this memory location, and to change the car or cdr, you just store into this memory location.
Very often, conses are used to store lists. If the above representation
is used, a list of n elements requires two times n words of
memory: n to hold the pointers to the elements of the list, and
n to point to the next cons or to nil
. To optimize this
particular case of using conses, the Lisp Machine uses a storage
representation called cdr-coding to store lists. The basic goal is to
allow a list of n elements to be stored in only n locations,
while allowing conses that are not parts of lists to be stored in the
usual way.
The way it works is that there is an extra two-bit field in every word
of memory, called the cdr-code field. There are three meaningful
values that this field can have, which are called cdr-normal
, cdr-next
,
and cdr-nil
. The regular, non-compact way to store a cons is by two
contiguous words, the first of which holds the car and the second of
which holds the cdr. In this case, the cdr-code of the first word is
cdr-normal
. (The cdr-code of the second word doesn’t matter; as we will
see, it is never looked at.) The cons is represented by a pointer to
the first of the two words. When a list of n elements is stored in
the most compact way, pointers to the n elements occupy n
contiguous memory locations. The cdr-codes of all these locations are
cdr-next
, except the last location whose cdr-code is cdr-nil
. The
list is represented as a pointer to the first of the n words.
Now, how are the basic operations on conses defined to work based on
this data structure? Finding the car is easy: you just read the
contents of the location addressed by the pointer. Finding the cdr is
more complex. First you must read the contents of the location
addressed by the pointer, and inspect the cdr-code you find there. If
the code is cdr-normal
, then you add one to the pointer, read the
location it addresses, and return the contents of that location; that
is, you read the second of the two words. If the code is cdr-next
, you
add one to the pointer, and simply return that pointer without doing any
more reading; that is, you return a pointer to the next word in the
n-word block. If the code is cdr-nil
, you simply return nil
.
If you examine these rules, you will find that they work fine even if you mix the two kinds of storage representation within the same list.
How about changing the structure? Like car
, rplaca
is very easy; you
just store into the location addressed by the pointer. To do rplacd
you must read the location addressed by the pointer and examine the cdr-code. If the code is cdr-normal
, you just store into the location one
greater than that addressed by the pointer; that is, you store into the
second word of the two words. But if the cdr-code is cdr-next
or
cdr-nil
, there is a problem: there is no memory cell that is storing the
cdr of the cons. That is the cell that has been optimized out; it just
doesn’t exist.
This problem is dealt with by the use of invisible pointers. An invisible pointer is a special kind of pointer, recognized by its data type (Lisp Machine pointers include a data type field as well as an address field). The way they work is that when the Lisp Machine reads a word from memory, if that word is an invisible pointer then it proceeds to read the word pointed to by the invisible pointer and use that word instead of the invisible pointer itself. Similarly, when it writes to a location, it first reads the location, and if it contains an invisible pointer then it writes to the location addressed by the invisible pointer instead. (This is a somewhat simplified explanation; actually there are several kinds of invisible pointer that are interpreted in different ways at different times, used for things other than the cdr-coding scheme.)
Here’s how to do rplacd
when the cdr-code is cdr-next
or cdr-nil
. Call
the location addressed by the first argument to rplacd
l. First,
you allocate two contiguous words in the same area that l points to.
Then you store the old contents of l (the car of the cons) and
the second argument to rplacd
(the new cdr of the cons) into these two
words. You set the cdr-code of the first of the two words to cdr-normal
.
Then you write an invisible pointer, pointing at the first of the two
words, into location l. (It doesn’t matter what the cdr-code of
this word is, since the invisible pointer data type is checked first,
as we will see.)
Now, whenever any operation is done to the cons (car
, cdr
, rplaca
, or
rplacd
), the initial reading of the word pointed to by the Lisp pointer
that represents the cons finds an invisible pointer in the addressed
cell. When the invisible pointer is seen, the address it contains is
used in place of the original address. So the newly-allocated two-word
cons is used for any operation done on the original object.
Why is any of this important to users? In fact, it is all invisible to
you; everything works the same way whether or not compact representation
is used, from the point of view of the semantics of the language. That
is, the only difference that any of this makes is a difference in
efficiency. The compact representation is more efficient in most cases.
However, if the conses are going to get rplacd
’ed, then invisible
pointers will be created, extra memory will be allocated, and the
compact representation will degrade storage efficiency rather
than improve it. Also, accesses that go through invisible pointers are
somewhat slower, since more memory references are needed. So if you
care a lot about storage efficiency, you should be careful about which
lists get stored in which representations.
You should try to use the normal representation for those data
structures that will be subject to rplacd
operations, including
nconc
and nreverse
, and the compact representation for other
structures. The functions cons
, xcons
, ncons
, and their
area variants make conses in the normal representation. The functions
list
, list*
, list-in-area
, make-list
, and append
use
the compact representation. The other list-creating functions,
including read
, currently make normal lists, although this might get
changed. Some functions, such as sort
, take special care to operate
efficiently on compact lists (sort
effectively treats them as
arrays). nreverse
is rather slow on compact lists, currently, since
it simple-mindedly uses rplacd
, but this may be changed.
(copylist x)
is a suitable way to copy a
list, converting it into compact form (see copylist-fun).
Zetalisp includes functions which simplify the maintenance
of tabular data structures of several varieties. The simplest is
a plain list of items
There are functions to add (cons
), remove (delete
, delq
,
del
, del-if
, del-if-not
, remove
, remq
, rem
,
rem-if
, rem-if-not
),
and search for (member
, memq
, mem
) items in a list.
Association lists are very commonly used. An association list
is a list of conses. The car of each cons is a “key” and the cdr
is a “datum”, or a list of associated data. The functions
assoc
, assq
, ass
, memass
, and rassoc
may be used to retrieve the data, given the key. For example,
((tweety . bird) (sylvester . cat))
is an association list with two elements. Given a symbol representing the name of an animal, it can retrieve what kind of animal this is.
Structured records can be stored as association lists or as stereotyped cons-structures where each element of the structure has a certain car-cdr path associated with it. However, these are better implemented using structure macros (see defstruct) or as flavors (flavor).
Simple list-structure is very convenient, but may not be efficient enough
for large data bases because it takes a long time to search a long list.
Zetalisp includes hash table facilities for more efficient
but more complex tables (see hash-table), and
a hashing function (sxhash
) to aid users in constructing their own facilities.
Returns nil
if item is not one of the
elements of list. Otherwise, it returns the sublist of list
beginning with the first occurrence of item; that is, it returns the
first cons of the list whose car is item. The comparison is made by
eq
. Because memq
returns nil
if it doesn’t find anything,
and something non-nil
if it finds something, it is often used as a
predicate.
Examples:
(memq 'a '(1 2 3 4)) => nil (memq 'a '(g (x a y) c a d e a f)) => (a d e a f)
Note that the value returned by memq
is eq
to the portion of the list
beginning with a
.
Thus rplaca
on the result of memq
may be used,
if you first check to make sure memq
did not return nil
.
Example:
(let ((sublist (memq x z))) ;Search forx
in the listz
. (if (not (null sublist)) ;If it is found, (rplaca sublist y))) ;Replace it withy
.
memq
could have been defined by:
(defun memq (item list) (cond ((null list) nil) ((eq item (car list)) list) (t (memq item (cdr list)))))
memq
is hand-coded in microcode and therefore especially fast.
It is equivalent to cli:member
with eq
specified as
the test argument.
member
is like memq
, except equal
is used for the comparison,
instead of eq
. Note that the member
function of Common Lisp,
which is cli:member
, is similar but thoroughly incompatible (see below).
member
could have been defined by:
(defun member (item list) (cond ((null list) nil) ((equal item (car list)) list) (t (member item (cdr list)))))
The Common Lisp member
function. It is
like memq
or member
except that there is more generality
in how elements of list are matched against item–and
the default is incompatible.
test, test-not and key are used in matching the elements,
just as described under cli:subst
(see cli:subst-fun). If
neither test nor test-not is specified, the default is to
compare with eql
, whereas member
compares with equal
.
Usually test is a commutative predicate such as
eq
, equal
, =
, char-equal
or string-equal
.
It can also be a non-commutative predicate. The predicate
is called with item as its first argument and the element of list
as its second argument. Example:
(cli:member 4 '(1.5 2.5 2 3.5 4.5 8) :test '<) => (4.5 8)
Searches the elements of list for one which satisfies predicate.
If one is found, the value is the tail of list whose car is that element.
Otherwise the value is nil
.
If key is non-nil
, then predicate is applied to (funcall
key element)
rather than to the element itself.
Searches for an element which does not satisfy predicate.
Otherwise like member-if
.
Is equivalent to
(cli:member item list :test predicate)
The function mem
antedates cli:member
.
Searches list for an element which
is eq
to item, like memq.
However, it returns the numeric index
in the list at which it found the first occurence of item, or
nil
if it did not find it at all. This function is sort of
the complement of nth
(see nth-fun); like nth
, it is zero-based.
Examples:
(find-position-in-list 'a '(a b c)) => 0 (find-position-in-list 'c '(a b c)) => 2 (find-position-in-list 'e '(a b c)) => nil
See also the generic sequence function position
(position-fun).
Is like find-position-in-list
, except that the comparison is done
with equal
instead of eq
.
Returns t
if sublist is a sublist of list (i.e
one of the conses that makes up list). Otherwise returns nil
.
Another way to look at this is that tailp
returns t
if
(nthcdr n list)
is sublist, for some value of n.
tailp
could have been defined by:
(defun tailp (sublist list) (do list list (cdr list) (null list) (if (eq sublist list) (return t))))
(delq item list)
returns the list with all
occurrences of item removed. eq
is used for the comparison.
The argument list is actually modified (rplacd
’ed) when instances
of item are spliced out. delq
should be used for value, not
for effect. That is, use
(setq a (delq 'b a))
rather than
(delq 'b a)
These two are not equivalent when the first element
of the value of a
is b
.
(delq item list n)
is like (delq item list)
except only the first
n instances of item are deleted. n is allowed to be zero.
If n is greater than or equal to the number of occurrences of item in the
list, all occurrences of item in the list are deleted.
Example:
(delq 'a '(b a c (a b) d a e)) => (b c (a b) d e)
delq
could have been defined by:
(defun delq (item list &optional (n -1)) (cond ((or (atom list) (zerop n)) list) ((eq item (car list)) (delq item (cdr list) (1- n))) (t (rplacd list (delq item (cdr list) n)))))
If the third argument (n) is not supplied, it defaults to -1
which
is effectively infinity since it can be decremented any number of times without
reaching zero.
delete
is the same as delq
except that equal
is used for the comparison
instead of eq
.
Common Lisp programs have a different, incompatible function called
delete
; see cli:delete-fun. This function may be useful in
non-Common-Lisp programs as well, where it can be referred to as
cli:delete
.
del
is the same as delq
except that it takes an extra argument
which should be a predicate of two arguments, which is used for the
comparison instead of eq
. (del 'eq a b)
is the same as
(delq a b)
. See also mem
, mem-fun.
Use of del
is equivalent to
(cli:delete item list :test predicate)
remq
is similar to delq
, except that the list is not altered;
rather, a new list is returned.
Examples:
(setq x '(a b c d e f)) (remq 'b x) => (a c d e f) x => (a b c d e f) (remq 'b '(a b c b a b) 2) => (a c a b)
remove
is the same as remq
except that equal
is used for the
comparison instead of eq
. Common Lisp programs have a different,
incompatible function called remove
; see cli:remove-fun. This function
may be useful in non-Common-Lisp programs as well, where it can be
referred to as cli:remove
.
rem
is the same as remq
except that it takes an extra argument
which should be a predicate of two arguments, which is used for the
comparison instead of eq
. (rem 'eq a b)
is the same as
(remq a b)
. See also mem
, mem-fun.
The function rem
in Common Lisp programs is actually cli:rem
,
a remainder function. See cli:rem-fun.
predicate should be a function of one argument.
A new list is made by applying predicate to
all of the elements of list and removing the ones for which the predicate
returns nil
. One of this function’s names (rem-if-not
)
means “remove if this condition is not true”; i.e it keeps the elements
for which predicate is true. The other name (subset
) refers to
the function’s action if list is considered to represent a mathematical set.
Example:
(subset #'minusp '(1 2 -4 2 -3)) => (-4 -3)
predicate should be a function of one argument.
A new list is made by applying predicate to
all of the elements of list and removing the ones for which the predicate
returns non-nil
. One of this function’s names (rem-if
)
means “remove if this condition is true”. The other name (subset-not
)
refers to the function’s action if list is considered to represent
a mathematical set.
del-if
is just like rem-if
except that it modifies list
rather than creating a new list.
del-if-not
is just like rem-if-not
except that it modifies list
rather than creating a new list.
See also the generic sequence functions delete-if
, delete-if-not
,
remove-if
and remove-if-not
(remove-if-fun).
Returns t
if predicate returns
non-nil
when applied to every element of list,
or nil
if predicate returns nil
for some element.
If step-function is present, it replaces cdr
as the function used to get to the next element of the list;
cddr
is a typical function to use here.
In Common Lisp programs, the name every
refers to a different,
incompatible function which serves a similar purpose. It is documented
in the manual under the name cli:every
. See cli:every-fun.
Returns a tail of list such that the car
of the tail is the first element that the predicate returns
non-nil
when applied to,
or nil
if predicate returns nil
for every element.
If step-function is present, it replaces cdr
as the function used to get to the next element of the list;
cddr
is a typical function to use here.
In Common Lisp programs, the name some
refers to a different,
incompatible function which serves a similar purpose. It is documented
in the manual under the name cli:some
. See cli:some-fun.
A list can be used to represent an unordered set of objects, simply by
using it in a way that ignores the order of the elements. Membership in
the set can be tested with memq
or member
, and some other
functions in the previous section also make sense on lists representing
sets. This section describes several functions specifically intended
for lists that represent sets.
It is often desirable to avoid adding duplicate elements in the list.
The set functions attempt to introduce no duplications, but do not
attempt to eliminate duplications present in their arguments. If you
need to make absolutely certain that a list contains no duplicates, use
remove-duplicates
or delete-duplicates
(see
remove-duplicates-fun).
t
if every element of list1 matches some element of list2.
The keyword arguments control how matching is done.
Either test or test-not should be a function of two arguments.
Normally it is called with an element of list1 as the first argument
and an element of list2 as the second argument.
If test is
specified, a match happens when test returns non-nil
; otherwise,
if test-not is specified, a match happens when it returns nil
.
If neither is specified, then eql
is used for test.
If key is non-nil
, it should be a function of one argument.
key is applied to each list element to get a key to be passed
to test or test-not instead of the element.
Returns a list like list but with item as an additional element if no existing element matches item. It is done like this:
(if (cli:member (if key (funcall key item) item) list other-args...) list (cons item list))
The keyword arguments work as in subsetp
.
Pushes item onto list-place unless item matches an existing element of the value stored in that place. Equivalent to
(setf list-place (adjoin item list-place keyword-args...))
except for order of evaluation. Compare with push
, push-fun.
Returns a list representing the set which is the union of the sets represented by the arguments. Anything which is an element of at least one of the arguments is also an element of the result.
Each element of each list is compared, using eq
, with all elements
of the other lists, to make sure that no duplications are introduced
into the result. As long as no individual argument list contains
duplications, the result does not either.
It is best to use union
with only two arguments so that
your code will not be sensitive to the difference between the
traditional version of union
and the Common Lisp version
cli:union
, below.
If lists are regarded as sets of their elements, intersection
returns a list which is the intersection of the lists which are
supplied as arguments. If list contains no duplicate elements,
neither does the value returned by intersection
. Elements are
compared using eq
.
It is best to use intersection
with only two arguments so that
your code will not be sensitive to the difference between the
traditional version of intersection
and the Common Lisp version
cli:intersection
, below.
If lists are regarded as sets of their elements, nunion
modifies
list to become the union of the lists which are supplied as
arguments. This is done by adding on, at the end, any elements of the
other lists that were not already in list. If none of the arguments
contains any duplicate elements, neither does the value returned by
nunion
. Elements are compared using eq
.
It is not safe to assume that list has been modified properly in place,
as this will not be so if list is nil
. Rather, you
must store the value returned by nunion
in place of list.
It is best to use nunion
with only two arguments so that
your code will not be sensitive to the difference between the
traditional version of nunion
and the Common Lisp version
cli:nunion
, below.
Like intersection
but produces the value by deleting elements from list
until the desired result is reached, and then returning list as modified.
It is not safe to assume that list has been modified properly in place,
as this will not be so if the first element was deleted. Rather, you
must store the value returned by nintersection
in place of list.
It is best to use nintersection
with only two arguments so that
your code will not be sensitive to the difference between the
traditional version of nintersection
and the Common Lisp version
cli:nintersection
, below.
The Common Lisp versions of the above functions, which accept only two sets to
operate on, but permit additional arguments to control how elements are
matched. These keyword arguments work the same as in subsetp
.
Returns a list which has all the elements of list1 which do not match any
element of list2. The keyword arguments control comparison of elements
just as in subsetp
.
The result contains no duplicate elements as long as list1 contains none.
Returns a list which has all the elements of list1 which do not match any
element of list2, and also all the elements of list2 which do not match
any element of list1. The keyword arguments control comparison of elements
just as in subsetp
.
The result contains no duplicate elements as long as neither list1 nor list2 contains any.
Like set-difference
but destructively modifies list1 to produce the value.
See the caveat in nintersection
, above.
Like set-exclusive-or
but may destructively modify both list1 and list2
to produce the value. See the caveat in nintersection
, above.
In all the alist-searching functions, alist elements which are nil
are ignored; they do not count as equivalent to (nil . nil)
. Elements
which are not lists cause errors.
pairlis
takes two lists and makes an association list which associates
elements of the first list with corresponding elements of the second
list.
Example:
(pairlis '(beef clams kitty) '(roast fried yu-shiang)) => ((beef . roast) (clams . fried) (kitty . yu-shiang))
If tail is non-nil
, it should be another alist. The new
alist continues with tail following the newly constructed mappings.
pairlis
is defined as:
(defun pairlis (cars cdrs &optional tail) (nconc (mapcar 'cons cars cdrs) tail))
Returns (cons (cons acar acdr) tail)
.
This adds one additional mapping from acar to acdr onto
the alist tail.
(assq item alist)
looks up item in the association list
(list of conses) alist. The value is the first cons whose car
is eq
to x, or nil
if there is none such.
Examples:
(assq 'r '((a . b) (c . d) (r . x) (s . y) (r . z))) => (r . x) (assq 'fooo '((foo . bar) (zoo . goo))) => nil (assq 'b '((a b c) (b c d) (x y z))) => (b c d)
It is okay to rplacd
the result of assq
as long as it is not nil
,
if your intention is to “update” the “table” that was assq
’s second argument.
Example:
(setq values '((x . 100) (y . 200) (z . 50))) (assq 'y values) => (y . 200) (rplacd (assq 'y values) 201) (assq 'y values) => (y . 201)
A common trick is to say
(cdr (assq x y))
.
Since the cdr of nil
is guaranteed to be nil
,
this yields nil
if no pair is found (or if a pair is
found whose cdr is nil
.)
assq
could have been defined by:
(defun assq (item list) (cond ((null list) nil) ((eq item (caar list)) (car list)) ((assq item (cdr list))) ))
assoc
is like assq
except that the comparison uses equal
instead of eq
.
Example:
(assoc '(a b) '((x . y) ((a b) . 7) ((c . d) .e))) => ((a b) . 7)
assoc
could have been defined by:
(defun assoc (item list) (cond ((null list) nil) ((equal item (caar list)) (car list)) ((assoc item (cdr list))) ))
The Common Lisp version of assoc
, this function returns the first
element of alist which is a cons whose car matches item, or
nil
if there is no such element.
test and test-not are used in comparing elements, as in
cli:subst
(cli:subst-fun), but note that there is no
key argument in cli:assoc
.
cli:assoc
is incompatible with the traditional function assoc
in that, like most Common Lisp functions, it uses eql
by default
rather than equal
for the comparison.
ass
is the same as assq
except that it takes an extra argument
which should be a predicate of two arguments, which is used for the
comparison instead of eq
. (ass 'eq a b)
is the same as
(assq a b)
. See also mem
, mem-fun.
This function is part of The mem
, rem
, del
series, whose
names were chosed partly because they created a situation in which
this function simply had to be called ass
. It’s too bad that
cli:assoc
is so general and subsumes ass
, which is equivalent
to
(cli:assoc item alist :test predicate)
Returns the first element of alist which is a cons whose car
satisfies predicate, or nil
if there is no such element.
Returns the first element of alist which is a cons whose car does
not satisfy predicate, or nil
if there is no such element.
memass
searches alist just like ass
, but returns the
portion of the list beginning with the pair containing item,
rather than the pair itself. (car (memass x y z)) = (ass x y
z)
. See also mem
, mem-fun.
The reverse-association functions are like assq
, assoc
, etc
but match or test the cdrs of the alist elements instead of the cars.
For example, rassq
could have been defined by:
(defun rassq (item in-list) (do l in-list (cdr l) (null l) (and (eq item (cdar l)) (return (car l)))))
(sassq item alist fcn)
is like (assq item alist)
except
that if item is not found in alist, instead of returning nil
,
sassq
calls the function fcn with no arguments. sassq
could
have been defined by:
(defun sassq (item alist fcn) (or (assq item alist) (apply fcn nil)))
sassq
and sassoc
(see below) are of limited use.
These are primarily leftovers from Lisp 1.5.
(sassoc item alist fcn)
is like (assoc item alist)
except that if
item is not found in alist, instead of returning nil
, sassoc
calls
the function fcn with no arguments. sassoc
could have been
defined by:
(defun sassoc (item alist fcn) (or (assoc item alist) (apply fcn nil)))
When you are creating a list that will not be needed any more once the function that creates it is finished, it is possible to create the list on the stack instead of by consing it. This avoids any permanent storage allocation, as the space is reclaimed as part of exiting the function. By the same token, it is a little risky; if any pointers to the list remain after the function exits, they will become meaningless.
These lists are called temporary lists or stack lists.
You can create them explicitly using the special forms
with-stack-list
and with-stack-list*
. &rest
arguments also
sometimes create stack lists.
If a stack list, or a list which might be a stack list, is to be
returned or made part of permanent list-structure, it must first be
copied (see copylist
, copylist-fun). The system cannot
detect the error of omitting to copy a stack list; you will simply find
that you have a value that seems to change behind your back.
These special forms create stack lists that live inside the stack frame of the function that they are used in. You should assume that the stack lists are only valid until the special form is exited.
(with-stack-list (foo x y) (mumblify foo))
is equivalent to
(let ((foo (list x y))) (mumblify foo))
except for the fact that foo
’s value in the first example is a stack
list.
The list created by with-stack-list*
looks like the one created by
list*
. tail’s value becomes the ultimate cdr rather than an
element of the list.
Here is a practical example. condition-resume
(see
condition-resume-fun) might have been defined as follows:
(defmacro condition-resume (handler &body body) `(with-stack-list* (eh:condition-resume-handlers ,handler eh:condition-resume-handlers) . ,body))
It is an error to do rplacd
on a stack list (except for the
tail of one made using with-stack-list*
). rplaca
works
normally.
sys:rplacd-wrong-representation-type
: (error
) ¶This is signaled if you rplacd
a stack list (or a list overlayed
with an array or other structure).
From time immemorial, Lisp has had a kind of tabular data structure called a property list (plist for short). A property list contains zero or more entries; each entry associates from a keyword symbol (called the property name, or sometimes the indicator) to a Lisp object (called the value or, sometimes, the property). There are no duplications among the property names; a property-list can have only one property at a time with a given name.
This is very similar to an association list. The important difference is that a
property list is an object with a unique identity; the operations for
adding and removing property-list entries are side-effecting operations
which alter the property-list rather than making a new one. An
association list with no entries would be the empty list ()
, i.e
the symbol nil
. There is only one empty list, so all empty
association lists are the same object. Each empty property-list is a
separate and distinct object.
The implementation of a property list is a memory cell containing a list with an even number (possibly zero) of elements. Each pair of elements constitutes a property; the first of the pair is the name and the second is the value. (It would have been possible to use an alist to hold the pairs; this format was chosen when Lisp was young.) The memory cell is there to give the property list a unique identity and to provide for side-effecting operations.
The term ‘property list’ is sometimes incorrectly used to refer to the list of entries inside the property list, rather than the property list itself. This is regrettable and confusing.
How do we deal with “memory cells” in Lisp? That is, what kind of Lisp object is a property list? Rather than being a distinct primitive data type, a property list can exist in one of three forms:
1. Any cons can be used as a property list. The cdr of the cons holds the list of entries (property names and values). Using the cons as a property list does not use the car of the cons; you can use that for anything else.
2. The system associates a property list with every symbol (see symbol-plist-section). A symbol can be used where a property list is expected; the property-list primitives automatically find the symbol’s property list and use it.
3. A flavor instance may have a property list. The property list functions operate on instances by sending messages to them, so the flavor can store the property list any way it likes. See si:property-list-mixin-flavor.
4. A named structure may have a property list. The property list
functions automatically call named-structure-invoke
when
a named structure is supplied as the property list. See named-structure.
5. A property list can be a memory cell in the middle of some data structure,
such as a list, an array, an instance, or a defstruct. An arbitrary memory
cell of this kind is named by a locative (see locative). Such locatives
are typically created with the locf
special form (see locf-fun).
Property lists of the first kind
are called disembodied property lists because they are not associated with
a symbol or other data structure.
The way to create a disembodied property list is (ncons nil)
,
or (ncons data)
to store data in the car of the property list.
Suppose that, inside a program which deals with blocks, the property
list of the symbol b1
contains this list (which would be the
value of (symbol-plist 'b1)
):
(color blue on b6 associated-with (b2 b3 b4))
The list has six elements, so there are three properties.
The first property’s name is the symbol color
, and its value
is the symbol blue
. One says that “the value of b1
’s color
property is blue
”, or, informally, that “b1
’s color
property
is blue
.” The program is probably representing the information that
the block represented by b1
is painted blue. Similarly, it is probably
representing in the rest of the property list that block b1
is on
top of block b6
, and that b1
is associated with blocks
b2
, b3
, and b4
.
get
looks up plist’s property-name property. If it finds such a property,
it returns the value; otherwise, it returns default-value. If plist is a symbol,
the symbol’s associated property list is used. For example, if the property
list of foo
is (baz 3)
, then
(get 'foo 'baz) => 3 (get 'foo 'zoo) => nil (get 'foo 'baz t) => 3 (get 'foo 'zoo t) => t
getl
is like get
, except that the second argument is a list
of property names. getl
searches down plist for any
of the names in property-name-list, until it finds a property whose
name is one of them.
If plist is a symbol, the symbol’s associated property list is used.
getl
returns the portion of the list inside plist beginning
with the first such property that it found. So the car of the returned
list is a property name, and the cadr
is the property value. If none
of the property names on property-name-list are on the property list, getl
returns nil
. For example, if the property list of foo
were
(bar (1 2 3) baz (3 2 1) color blue height six-two)
then
(getl 'foo '(baz height)) => (baz (3 2 1) color blue height six-two)
When more than one of the names in property-name-list is present in
plist, which one getl
returns depends on the order of the properties.
This is the only thing that depends on that order. The order maintained
by putprop
and defprop
is not defined (their behavior with respect
to order is not guaranteed and may be changed without notice).
This gives plist an property-name-property of x.
After this is done, (get plist property-name)
returns x.
If plist is a symbol, the symbol’s associated property list is used.
Example:
(putprop 'nixon t 'crook)
It is more modern to write
(setf (get plist property-name) x)
which avoids the counterintuitive order in which putprop
takes its arguments.
defprop
is a form of putprop
with unevaluated arguments,
which is sometimes more convenient for typing. Normally only a symbol
makes sense as the first argument.
Example:
(defprop foo bar next-to)
is the same as
(putprop 'foo 'bar 'next-to)
This removes plist’s property-name property, by splicing it out of the property
list. It returns that portion of the list inside plist of which the
former property-name-property was the car. car
of what remprop
returns is what get
would have returned with the same arguments.
If plist is a symbol, the symbol’s associated property list is used.
For example, if the property list of foo
was
(color blue height six-three near-to bar)
then
(remprop 'foo 'height) => (six-three near-to bar)
and foo
’s property list would be
(color blue near-to bar)
If plist has no property-name-property, then remprop
has no side-effect
and returns nil
.
Equivalent to (get (locf place) property default)
, except that getf
is
defined in Common Lisp, which does not have locf
or locatives of any kind.
(setf (getf place property) value)
can be used to store
properties into the property list at place.
Equivalent to (remprop (locf place) property)
, except that remf
is
defined in Common Lisp.
Like
(getl (locf place) list-of-properties)
but returns
slightly different values. Specifically, it searches the property list for a property
name which is memq
in list-of-properties, then returns three values:
the property name found
the value of that property
the property list cell found, whose car is propname and whose cadr is value.
If nothing is found, all three values are nil
.
It is possible to continue searching down the property list by using
cddr
of the third value as the argument to another call to
get-properties
.
A hash table is a Lisp object that works something like a property list. Each hash table has a set of entries, each of which associates a particular key with a particular value (or sequence of values). The basic functions that deal with hash tables can create entries, delete entries, and find the value that is associated with a given key. Finding the value is very fast even if there are many entries, because hashing is used; this is an important advantage of hash tables over property lists. Hashing is explained in hash-section.
A given hash table stores a fixed number of values for each key; by default, there is only one value. Each time you specify a new value or sequence of values, the old one(s) are lost.
There are three standard kinds of hash tables, which differ in how
they compare keys: with eq
, with eql
or with equal
. In
other words, there are hash tables which hash on Lisp objects
(using eq
or eql
) and there are hash tables which hash on
trees (using equal
).
You can also create a nonstandard hash table with any comparison
function you like, as long as you also provide a suitable hash
function. Any two objects which would be regarded as the same by the
comparison function should produce the same hash code under the hash
function. See the :compare-function
and :hash-function
keywords under make-hash-table
, below.
The following discussion refers to the eq
kind of hash table; the
other kinds are described later, and work analogously.
eq
hash tables are created with the function make-hash-table
, which
takes various options. New entries are added to hash tables with the
puthash
function. To look up a key and find the associated value(s),
the gethash
function is used. To remove an entry, use remhash
.
Here is a simple example.
(setq a (make-hash-table)) (puthash 'color 'brown a) (puthash 'name 'fred a) (gethash 'color a) => brown (gethash 'name a) => fred
In this example, the symbols color
and name
are being used as
keys, and the symbols brown
and fred
are being used as the
associated values. The hash table remembers one value for each key,
since we did not specify otherwise, and has two items in it, one of
which associates from color
to brown
, and the other of which
associates from name
to fred
.
Keys do not have to be symbols; they can be any Lisp object. Likewise
values can be any Lisp object. Since eq
does not work reliably on
numbers (except for fixnums), they should not be used as keys in an
eq
hash table. Use an eql
hash table if you want to hash on
numeric values.
When a hash table is first created, it has a size, which is the number of entries it has room for. But hash tables which are nearly full become slow to search, so if more than a certain fraction of the entries become in use, the hash table is automatically made larger, and the entries are rehashed (new hash values are recomputed, and everything is rearranged so that the fast hash lookup still works). This is transparent to the caller; it all happens automatically.
The describe
function (see describe-fun) prints a variety of
useful information when applied to a hash table.
This hash table facility is similar to the hasharray facility of Interlisp,
and some of the function names are the same. However, it is not compatible.
The exact details and the order of arguments are designed to be consistent
with the rest of Zetalisp rather than with Interlisp. For instance,
the order of arguments to maphash
is different, we do not have the Interlisp
“system hash table”, and we do not have the
Interlisp restriction that keys and values may not be nil
.
Note, however, that the order of arguments to gethash
, puthash
, and remhash
is not consistent with the Zetalisp’s get
, putprop
, and remprop
,
either. This is an unfortunate result of the haphazard historical development of Lisp.
Hash tables are implemented as instances of the flavor hash-table
.
The internals of a hash table are subject to change without notice.
Hash tables should be manipulated only with the functions and operations described below.
These functions create new hash tables. make-equal-hash-table
creates an equal
hash table. make-hash-table
normally creates
an eq
hash table, but this can be overridden by keywords as
described below. Valid option keywords are:
:size
Sets the initial size of the hash table, in entries, as a fixnum. The default is 64. The actual size is rounded up from the size you specify to the next size that is good for the hashing algorithm. The number of entries you can actually store in the hash table before it is rehashed is at least the actual size times the rehash threshold (see below).
:test
This keyword is the Common Lisp way to specify the kind of hashing
desired. The value must be eq
, eql
or equal
. The one
specified is used as the compare function and an appropriate hash
function is chosen automatically to go with it.
:compare-function
Specifies a function of two arguments which compares two keys to see if
they count as the same for retrieval from this table. For reasonable
results, this function should be an equivalence relation. The default is
eq
. For make-equal-hash-table
the default is equal
; that is
the only difference between that function and make-hash-table
.
:hash-function
Specifies a function of one argument which, given a key, computes its hash code.
The hash code may be any Lisp object. The purpose of the hash function
is to map equivalent keys into identical objects: if two keys would
cause the compare function to return non-nil
, the hash function must
produce identical (eq
) hash codes for them.
For an eq
hash table, the key itself is a suitable hash code, so
no hash function is needed. Then this option’s value should be
nil
(identity
would also work, but slower). nil
is the
default in make-hash-table
. make-equal-hash-table
specifies an appropriate function which uses sxhash
.
:number-of-values
A positive integer which specifies how many values to associate with each key. The default is one.
:area
Specifies the area in which the hash table should be created. This is
just like the :area
option to make-array
(see make-array-fun).
Defaults to nil
(i.e default-cons-area
).
:rehash-function
Specifies the function to be used for rehashing when the table becomes full. Defaults to the internal rehashing function that does the usual thing. If you want to write your own rehashing function, you must know all the internals of how hash tables work. These internals are not documented here, as the best way to learn them is to read the source code.
:rehash-size
Specifies how much to increase the size of the hash table when it becomes
full. This can be a fixnum which is the number of entries to add, or
it can be a float which is the ratio of the new size to the old size.
The default is 1.3
, which causes the table to be made 30% bigger
each time it has to grow.
:rehash-threshold
Sets a maximum fraction of the entries which can be in use before the
hash table is made larger and rehashed. The default is 0.7s0
.
Alternately, an integer may be specified. It is the exact number of
filled entries at which a rehash should be done. When the rehash
happens, if the threshold is an integer it is increased in the same
proportion as the table has grown.
:rehash-before-cold
If non-nil
, this hash table should be rehashed (if that is necessary
due to garbage collection) by disk-save
. This avoids a delay
for rehashing the hash table the first time it is referenced after
booting the saved band.
:actual-size
Specifies exactly the size for the hash table. Hash tables used by
the microcode for flavor method lookup must be a power of two in size.
This differs from :size
in that :size
is rounded up to a
nearly prime number, but :actual-size
is used exactly as
specified. :actual-size
overrides :size.
t
if object is a hash table.
(hash-table-p object)
is equivalent to
(typep object 'hash-table)
The following functions are equivalent to sending appropriate messages to the hash table.
Finds the entry in hash-table whose key is key, and return the
associated value. If there is no such entry, returns default-value.
Returns also a second value, which is t
if an entry was found or
nil
if there is no entry for key in this table.
Returns also a third value, a list which overlays the hash table entry. Its car is the key; the remaining elements are the values in the entry. This is how you can access values other than the first, if the hash table contains more than one value per entry.
Creates an entry associating key to value; if there is already an entry for key, then replace the value of that entry with value. Returns value. The hash table automatically grows if necessary.
If the hash table associates more than one value with each key, the remaining values in the entry are taken from extra-values.
Removes any entry for key in hash-table. Returns t
if there was an
entry or nil
if there was not.
This specifies new value(s) for key like puthash
, but returns
values describing the previous state of the entry, just like
gethash
. It returns the previous (replaced)
associated value as the first value, and returns t
as the second value
if the entry existed previously.
For each occupied entry in hash-table, call function. The arguments passed to function are the key of the entry, the value(s) of the entry (however many there are), and the extra-args (however many there are).
If the hash table has more than one value per key, all the values, in order, are supplied as successive arguments.
Like maphash
, but accumulates and returns a list of all the
values returned by function when it is applied to the items in
the hash table.
Removes all the entries from hash-table. Returns the hash table itself.
Returns the number of filled entries in hash-table.
Hash tables are instances, and support the following operations:
hash-table
: :size ¶Returns the number of entries in the hash table. Note that the hash table is rehashed when only a fraction of this many (the rehash threshold) are full.
hash-table
: :filled-entries ¶Returns the number of entries that are currently occupied.
hash-table
: :get-hash key ¶hash-table
: :put-hash key &rest values ¶hash-table
: :swap-hash key &rest values ¶hash-table
: :rem-hash key ¶hash-table
: :map-hash function &rest extra-args ¶hash-table
: :map-hash-return function ¶hash-table
: :clear-hash ¶hash-table
: :filled-entries ¶Are equivalent to the functions gethash
, puthash
, swaphash
,
remhash
, maphash
, maphash-return
, clrhash
and
hash-table-count
except that the hash table need not be specified as
an argument because it is the object that receives the message. Those
functions (documented in the previous section) actually work by invoking
these operations.
hash-table
: :modify-hash key function &rest additional-args ¶Passes the value associated with key in the table to function; whatever function returns is stored in the table as the new value for key. Thus, the hash association for key is both examined and updated according to function.
The arguments passed to function are key, the value associated with key,
a flag (t
if key is actually found in the hash table), and the
additional-args that you specify.
If the hash table stores more than one value per key, only the first value is examined and updated.
The eq
type hash tables actually hash on the address of the
representation of the object. equal
hash tables do so too, if given
keys containing unusual objects (other than symbols, numbers, strings
and lists of the above). When the copying garbage collector changes the
addresses of objects, it lets the hash facility know so that the next gethash
will rehash the table based on the new object addresses.
There may eventually be an option to make-hash-table
which tells it
to make a “non-GC-protecting” hash table. This is a special kind of hash table
with the property that if one of its keys becomes garbage, i.e is an object
not known about by anything other than the hash table, then the entry for that
key will be removed silently from the table. When this option exists it will be
documented in this section.
Hashing is a technique used in algorithms to provide fast retrieval of data in large tables. A function, known as the hash function, takes an object that might be used as a key, and produces a number associated with that key. This number, or some function of it, can be used to specify where in a table to look for the datum associated with the key. It is always possible for two different objects to hash to the same value; that is, for the hash function to return the same number for two distinct objects. Good hash functions are designed to minimize this by evenly distributing their results over the range of possible numbers. However, hash table algorithms must still deal with this problem by providing a secondary search, sometimes known as a rehash. For more information, consult a textbook on computer algorithms.
sxhash
computes a hash code of a tree, and returns it as a fixnum.
A property of sxhash
is that (equal x y)
always implies
(= (sxhash x) (sxhash y))
. The number returned by sxhash
is
always a non-negative fixnu. sxhash
tries to
compute its hash code in such a way that common permutations of an object,
such as interchanging two elements of a list or changing one character in
a string, always change the hash code.
Here is an example of how to use sxhash
in maintaining
hash tables of trees:
(defun knownp (x &aux i bkt) ;look up x
in the table
(setq i (abs (remainder (sxhash x) 176)))
;The remainder should be reasonably randomized.
(setq bkt (aref table i))
;bkt is thus a list of all those expressions that
;hash into the same number as does x.
(memq x bkt))
For an “intern” for trees, one could write:
(defun sintern (x &aux bkt i tem) (setq i (abs (remainder (sxhash x) 2n-1))) ;2n-1 stands for a power of 2 minus one. ;This is a good choice to randomize the ;result of the remainder operation. (setq bkt (aref table i)) (cond ((setq tem (memq x bkt)) (car tem)) (t (aset (cons x bkt) table i) x)))
If sxhash
is given a named structure or a flavor instance, or if
such an object
is part of a tree that is sxhash
’ed, it asks the object to supply
its own hash code by performing the :sxhash
operation if the object
supports it. This should return a suitable nonnegative hash code. The
easiest way to compute one is usually by applying sxhash
to one or
more of the components of the structure or the instance variables of the
instance.
For named structures and flavor instances that do not handle the
:sxhash
operation, and other unusual kinds of objects,
sxhash
can optionally use the object’s address as its hash code,
if you specify a non-nil
second argument. If you use this
option, you must be prepared to deal with hash codes changing due to
garbage collection.
sxhash
provides what is called “hashing on equal
”; that is, two
objects that are equal
are considered to be “the same” by
sxhash
. If two strings differ only in alphabetic case,
sxhash
returns the same thing for both of them, making it
suitable for equalp
hashing as well in some cases.
Therefore, sxhash
is useful for retrieving data when
two keys that are not the same object but are equal
are considered
the same. If you consider two such keys to be different, then you need
“hashing on eq
”, where two different objects are always considered
different. In some Lisp implementations, there is an easy way to create
a hash function that hashes on eq
, namely, by returning the virtual
address of the storage associated with the object. But in other
implementations, of which Zetalisp is one, this doesn’t work,
because the address associated with an object can be changed by the
relocating garbage collector. The hash tables created by make-hash-table
deal with this problem by using the appropriate subprimitives so that they
interface correctly with the garbage collector. If you need a hash table
that hashes on eq
, it is already provided; if you need an
eq
hash function for some other reason, you must build it yourself,
either using the provided eq
hash table facility or carefully using
subprimitives.
Storage allocation is handled differently by different computer systems. In many languages, the programmer must spend a lot of time thinking about when variables and storage units are allocated and deallocated. In Lisp, freeing of allocated storage is normally done automatically by the Lisp system; when an object is no longer accessible to the Lisp environment, the garbage collector reuses its storage for some other object. This relieves the programmer of a great burden, and makes writing programs much easier.
However, automatic freeing of storage incurs an expense: more computer resources must be devoted to the garbage collector. If a program is designed to allocate temporary storage, which is then left as garbage, more of the computer must be devoted to the collection of garbage; this expense can be high. In some cases, the programmer may decide that it is worth putting up with the inconvenience of having to free storage under program control, rather than letting the system do it automatically, in order to prevent a great deal of overhead from the garbage collector.
It usually is not worth worrying about freeing of storage when the units of storage are very small things such as conses or small arrays. Numbers are not a problem, either; fixnums and short floats do not occupy storage, and the system has a special way of garbage-collecting the other kinds of numbers with low overhead. But when a program allocates and then gives up very large objects at a high rate (or large objects at a very high rate), it can be worthwhile to keep track of that one kind of object manually. Within the Lisp Machine system, there are several programs that are in this position. The Chaosnet software allocates and frees “packets”, which are moderately large, at a very high rate. The window system allocates and frees certain kinds of windows, which are very large, moderately often. Both of these programs manage their objects manually, keeping track of when they are no longer used.
When we say that a program “manually frees” storage, it does not really mean that the storage is freed in the same sense that the garbage collector frees storage. Instead, a list of unused objects is kept. When a new object is desired, the program first looks on the list to see if there is one around already, and if there is it uses it. Only if the list is empty does it actually allocate a new one. When the program is finished with the object, it returns it to this list.
The functions and special forms in this section perform the above
function. The set of objects forming each such list is called a
resource; for example, there might be a Chaosnet packet resource.
defresource
defines a new resource; allocate-resource
allocates
one of the objects; deallocate-resource
frees one of the objects
(putting it back on the list); and using-resource
temporarily
allocates an object and then frees it.
The defresource
special form is used to define a new resource. The
form looks like this:
(defresource name parameters doc-string keyword value keyword value ...)
name should be a symbol; it is the name of the resource and gets a
defresource
property of the internal data structure representing the resource.
parameters is a lambda-list giving names and default values (if &optional
is used) of parameters to an object of this type. For example, if one had a resource
of two-dimensional arrays to be used as temporary storage in a calculation, the
resource would typically have two parameters, the number of rows and the number of
columns. In the simplest case parameters is ()
.
The documentation string is recorded for (documentation name 'resource)
to access. It may be omitted.
The keyword options control how the objects of the resource are made and kept track of. The following keywords are allowed:
:constructor
The value is either a form or the name of a function. It is responsible for making an object, and will be used when someone tries to allocate an object from the resource and no suitable free objects exist. If the value is a form, it may access the parameters as variables. If it is a function, it is given the internal data structure for the resource and any supplied parameters as its arguments; it will need to default any unsupplied optional parameters. This keyword is required.
:free-list-size
The value is the number of objects which the resource data structure should have room, initially, to remember. This is not a hard limit, since the data structure will be made bigger if necessary.
:initial-copies
The value is a number (or nil
which means 0). This many objects will
be made as part of the evaluation of the defresource
; thus is useful to
set up a pool of free objects during loading of a program. The default is
to make no initial copies.
If initial copies are made and there are parameters, all the parameters must
be &optional
and the initial copies will have the default values of the
parameters.
:initializer
The value is a form or a function as with :constructor
. In
addition to the parameters, a form here may access the variable
object
(in the current package). A function gets the object as
its second argument, after the data structure and before the
parameters. The purpose of the initializer function or form is to
clean up the contents of the object before each use. It is called or
evaluated each time an object is allocated, whether just constructed
or being reused.
:finder
The value is a form or a function as with :constructor
and sees the
same arguments. If this option is specified, the resource system does not keep
track of the objects. Instead, the finder must do so. It will be called
inside a without-interrupts
and must find a usable object somehow and return it.
:matcher
The value is a form or a function as with :constructor
. In addition to
the parameters, a form here may access the variable object
(in the current package).
A function gets the object as its second argument, after the data structure and
before the parameters. The job of the matcher is to make sure that the object
matches the specified parameters. If no matcher is supplied, the system will remember
the values of the parameters (including optional ones that defaulted) that were used
to construct the object, and will assume that it matches those particular values for
all time. The comparison is done with equal
(not eq
). The matcher is
called inside a without-interrupts
.
:checker
The job of the checker is to determine whether the object is safe to allocate.
The value is a form or a function, as above. In addition to the
parameters, a form here may access the variables object
and in-use-p
(in the current package). A function receives these as its second and third
arguments, after the data structure and before the parameters. If no checker
is supplied, the default checker looks only at in-use-p
; if the object has
been allocated and not freed it is not safe to allocate, otherwise it is. The
checker is called inside a without-interrupts
.
If these options are used with forms (rather than functions), the forms
get compiled into functions as part of the expansion of defresource
.
The functions, whether user-provided or generated from forms, are given
names like (:property resource-name si:resource-constructor)
;
these names are not guaranteed not to change in the future.
Most of the options are not used in typical cases. Here is an example:
(defresource two-dimensional-array (rows columns) :constructor (make-array (list rows columns)))
Suppose the array was usually going to be 100 by 100, and you wanted to preallocate one during loading of the program so that the first time you needed an array you wouldn’t have to spend the time to create one. You might simply put
(using-resource (foo two-dimensional-array 100 100) )
after your defresource
, which would allocate a 100 by 100 array and then
immediately free it. Alternatively you could write:
(defresource two-dimensional-array (&optional (rows 100) (columns 100)) :constructor (make-array (list rows columns)) :initial-copies 1)
Here is an example of how you might use the :matcher
option. Suppose you wanted
to have a resource of two-dimensional arrays, as above, except that when you allocate
one you don’t care about the exact size, as long as it is big enough. Furthermore
you realize that you are going to have a lot of different sizes and if you always
allocated one of exactly the right size, you would allocate a lot of different arrays
and would not reuse a pre-existing array very often. So you might write:
(defresource sloppy-two-dimensional-array (rows columns) :constructor (make-array (list rows columns)) :matcher (and ( (array-dimension-n 1 object) rows) ( (array-dimension-n 2 object) columns)))
Allocates an object from the resource specified by resource-name. The various forms
and/or functions given as options to defresource
, together with any
parameters given to allocate-resource
, control how a suitable object
is found and whether a new one has to be constructed or an old one can be reused.
Note that the using-resource
special form is usually what you want to
use, rather than allocate-resource
itself; see below.
Frees the object resource-object, returning it to the free-object list of the resource specified by resource-name.
The body forms are evaluated sequentially with variable bound to an object allocated from the resource named resource, using the given parameters. The parameters (if any) are evaluated, but resource is not.
using-resource
is often more convenient than calling
allocate-resource
and deallocate-resource
.
Furthermore it is careful to free the object when the body is exited,
whether it returns normally or via throw
. This is done by using
unwind-protect
; see unwind-protect-fun.
Here is an example of the use of resources:
(defresource huge-16b-array (&optional (size 1000)) :constructor (make-array size :type 'art-16b)) (defun do-complex-computation (x y) (using-resource (temp-array huge-16b-array) ... ;Within the body, the array can be used. (aset 5 temp-array i) ...)) ;The array is deallocated at the end.
Frees all objects in resource-name. This is like doing
deallocate-resource
on each one individually. This function is
often useful in warm-boot initializations.
Calls function on each object created in resource-name. Each time
function is called, it receives three fixed arguments, plus whatever
extra-args were specified. The three fixed arguments are an object
of the resource; t
if the object is currently allocated (“in use”);
and the resource data structure itself.
Forgets all of the objects being remembered by the resource specified by resource-name.
Future calls to allocate-resource
will create new objects. This function is
useful if something about the resource has been changed incompatibly, such that the
old objects are no longer usable. If an object of the resource is in use when
clear-resource
is called, an error will be signaled when that object is
deallocated.
The constructor, initializer, matcher and checker functions receive the internal resource data structure as an argument. This is a named structure array whose elements record the objects both free and allocated, and whose array leader contains sundry other information. This structure should be accessed using the following primitives:
Returns the index’th object remembered by the resource. Both free and allocated objects are remembered.
Returns t
if the index’th object remembered by the
resource has been allocated and not deallocated.
Simply defined resources will not reallocate an object in this state.
Returns the list of parameters from which the index’th object was originally created.
Returns the number of objects currently remembered by the resource.
This will include all objects ever constructed, unless
clear-resource
has been used.
Returns a function, created by defresource
, which accepts the
supplied parameters as arguments, and returns a complete list of
parameter values, including defaults for the optional ones.
When small temporary data structures are allocated so often that they
amount to a considerable drain of storage space, an ordinary resource
may be unacceptably slow. Here is a simple technique that
provides in such cases nearly all the benefit of a resource while
costing nearly nothing. The function read
uses it to allocate a
buffer for reading tokens of input.
(defvar buffer-for-reuse nil) (defsubst get-buffer () (or (do (old) ((%store-conditional (locf buffer-for-reuse) (setq old buffer-for-reuse) nil) old)) (construct-new-buffer)))) (defsubst free-buffer (buffer) (setq buffer-for-reuse buffer))
To allocate a buffer for use, do (get-buffer)
.
To free it when you are done with it, call free-buffer
.
It is assumed that construct-new-buffer
is the function
which can create a new buffer when there is none available for
reuse.
This technique keeps track of at most one buffer which has been freed
and may be reused. It is not effective in this simple form when more
than one buffer is needed at any given time by one application.
In the case of read
, only one token is being read in at any time.
It is safe for more than one process to call read
because
get-buffer
is designed to guarantee that a request cannot get a
buffer already handed out and not freed. Likewise, nothing terrible
happens if there is an error inside read
and read
is called
recursively within the debugger. The only problem is that multiple
buffers will be allocated, which means that some of them will be lost.
But the cost of this is minor in the cases where this technique
is applicable. For example, if two processes are reading files,
process switching will probably happen a few times a second, each time
costing one buffer not reused. This is insignificant compared to the
storage used up for other purposes by reading large amounts of data.
This chapter discusses the symbol as a Lisp data type. The Lisp system uses symbols as variables and function names, but these applications of symbols are discussed in chapter evaluator-chapter.
Each symbol has associated with it a value cell, which refers to
one Lisp object. This object is called the symbol’s value, since it is
what you get when you evaluate the symbol as a dynamic variable in a program.
Variables and how they work are described in variable-section. We also say
the the symbol is bound to the object which is its value. The symbols
nil
and t
are always bound to themselves; they may not be assigned,
bound, or otherwise used as variables. The same is true of symbols in the
keyword package.
The value cell can also be void, referring to no Lisp object, in which case the symbol is said to be void or unbound. This is the initial state of a symbol when it is created. An attempt to evaluate a void symbol causes an error.
Lexical variable bindings are not stored in symbol value cells. The functions in this section have no interaction with lexical bindings.
symeval
is the basic primitive for retrieving a symbol’s value.
(symeval symbol)
returns symbol’s current binding.
This is the function called by eval
when it is given a symbol to
evaluate. If the symbol is unbound, then symeval
signals an
error. symbol-value
is the Common Lisp name for this function.
set
is the primitive for assignment of symbols. The symbol’s value
is changed to value; value may be any Lisp object. set
returns
value.
Example:
(set (cond ((eq a b) 'c) (t 'd)) 'foo)
either sets c
to foo
or sets d
to foo
.
(setf (symeval symbol) value)
is a more modern
way to do this.
t
if symbol’s value cell is not void.
Makes symbol’s value cell void.
Example:
(setq a 1)
a => 1
(makunbound 'a)
a => causes an error.
makunbound
returns its argument.
Returns a locative pointer to symbol’s value cell. See the section on locatives (locative). It is preferable to write
(locf (symeval symbol))
which is equivalent, instead of calling this function explicitly.
This is actually the internal value cell; there can also be an external value cell. For details, see the section on closures (closure).
For historical compatibility, value-cell-location
of a quoted symbol is
recognized specially by the compiler and treated like variable-location
(variable-location-fun). However, such usage results in a compiler warning,
and eventually this compatibility feature will be removed.
Every symbol also has associated with it a function cell. The function
cell is similar to the value cell; it refers to a Lisp object.
When a function is referred to by name, that is, when a symbol is passed to apply
or appears as the car of a form to be evaluated, that symbol’s function cell
is used to find its definition, the functional object which is to be applied.
For example, when evaluating (+ 5 6)
,
the evaluator looks in +
’s function cell to find the definition of +
,
in this case a compiled function object, to apply to 5 and 6.
Maclisp does not have function cells; instead, it looks for special
properties on the property list. This is one of the major incompatibilities
between the two dialects.
Like the value cell, a function cell can be void, and it can be bound
or assigned. (However, to bind a function cell you must use the
%bind
subprimitive; see %bind-fun.)
The following functions are analogous to the value-cell-related
functions in the previous section.
Returns symbol’s definition, the contents of its
function cell. If the function cell is void, fsymeval
signals an error. symbol-function
is the Common Lisp name for this function.
Stores definition, which may be any Lisp object, into symbol’s function cell. It returns definition.
(setf (fsymeval symbol) definition)
is a more modern
way to do this.
nil
if symbol’s function cell is void,
i.e if symbol is undefined.
Otherwise it returns t
.
Causes symbol to be undefined, i.e its function cell to be void. It returns symbol.
Returns a locative pointer to symbol’s function cell. See the section on locatives (locative). It is preferable to write
(locf (fsymeval symbol))
rather than calling this function explicitly.
Since functions are the basic building block of Lisp programs, the system provides a variety of facilities for dealing with functions. Refer to chapter function-chapter for details.
Every symbol has an associated property list. See plist for documentation of property lists. When a symbol is created, its property list is initially empty.
The Lisp language itself does not use a symbol’s property list for anything. (This was not true in older Lisp implementations, where the print-name, value-cell, and function-cell of a symbol were kept on its property list.) However, various system programs use the property list to associate information with the symbol. For instance, the editor uses the property list of a symbol which is the name of a function to remember where it has the source code for that function, and the compiler uses the property list of a symbol which is the name of a special form to remember how to compile that special form.
Because of the existence of print-name, value, function, and package cells,
none of the Maclisp system property names (expr
, fexpr
, macro
, array
,
subr
, lsubr
, fsubr
, and in former times value
and
pname
) exist in Zetalisp.
Returns the list which represents the property list of symbol.
Note that this is not actually a property list; you cannot do get
on it. This value is like what would be the cdr of a property list.
symbol-plist
is the Common Lisp name.
Sets the list which represents the property list of symbol to list.
setplist
is to be used with caution (or not at all),
since property lists sometimes contain internal system properties, which
are used by many useful system functions. Also it is inadvisable to have the property
lists of two different symbols be eq
, since the shared list structure will
cause unexpected effects on one symbol if putprop
or remprop
is done to the other.
setplist
is equivalent to
(setf (plist symbol) list)
Returns a locative pointer to the location of symbol’s
property-list cell. This locative pointer may be passed to get
or
putprop
with the same results as if as symbol itself had been
passed. It is preferable to write
(locf (plist symbol))
rather than using this function.
Every symbol has an associated string called the print-name, or pname
for short. This string is used as the external representation of the symbol:
if the string is typed in to read
, it is read as a reference to that symbol
(if it is interned), and if the symbol is printed, print
types out the
print-name.
If a symbol is uninterned, #:
is normally printed as a prefix
before the symbol’s print-name. If the symbol is interned, a package
prefix may be printed, depending on the current package and how it relates
to the symbol’s home package.
For more information, see the sections on the reader (see reader), printer (see printer), and packages (see package).
Every symbol has a package cell which, for interned
symbols, is used to point to the package which the symbol belongs to. For an
uninterned symbol, the package cell contains nil
. For
information about packages in general, see the chapter on packages, package.
For information about package cells, see symbol-package-cell-discussion.
The functions in this section are primitives for creating symbols.
However, before discussing them, it is important to point out that most
symbols are created by a higher-level mechanism, namely the reader and
the intern
function. Nearly all symbols in Lisp are created
by virtue of the reader’s having seen a sequence of input characters that
looked like the printed representation (p.r) of a symbol. When the
reader sees such a p.r, it calls intern
(see intern-fun),
which looks up the sequence of characters in a big table and sees whether any symbol
with this print-name already exists. If it does, read
uses the
already-existing symbol. If it does not, then intern
creates a new
symbol and puts it into the table; read
uses that new symbol.
A symbol that has been put into such a table is called an interned symbol. Interned symbols are normally created automatically; the first time that someone (such as the reader) asks for a symbol with a given print-name, that symbol is automatically created.
These tables are called packages. For more information, turn to the chapter on packages (package).
An uninterned symbol is a symbol that has not been recorded
or looked up in a package. It is used simply as a data object,
with no special cataloging. An uninterned symbol prints with a
prefix #:
when escaping is in use, unless *print-gensym*
is nil
.
This allows uninterned symbols to be distinguishable and to read back in as
uninterned symbols. See *print-gensym*-var.
The following functions can be used to create uninterned symbols explicitly.
Creates a new uninterned symbol, whose print-name is the string
pname. The value and function cells are void and the
property list is empty. If permanent-p is specified, it is
assumed that the symbol is going to be interned and probably kept around
forever; in this case it and its pname are put in the proper areas.
If permanent-p is nil
(the default), the symbol goes in the
default area and the pname is not copied. permanent-p is mostly
for the use of intern
itself.
Examples:
(setq a (make-symbol "foo")) => foo (symeval a) => ERROR!
Note that the symbol is not interned; it is simply created and returned.
Returns a new uninterned symbol with the same print-name
as symbol. If copy-props is non-nil
, then the
value and function-definition of the new symbol are
the same as those of symbol, and the property list of
the new symbol is a copy of symbol’s. If copy-props
is nil
, then the new symbol’s function and value are void, and
its property list is empty.
Invents a print-name and creates a new symbol with that print-name. It returns the new, uninterned symbol.
The invented print-name is a prefix (the value of si:*gensym-prefix
)
followed by the decimal representation of a number (the value of si:*gensym-counter
),
e.g g0001
. The number is increased by one every time gensym
is called.
If the argument x is present and is a fixnum, then si:*gensym-counter
is
set to x. If x is a string or a symbol, then si:*gensym-prefix
is set to it,
so it becomes the prefix for this and successive calls to gensym
.
After handling the argument, gensym
creates a symbol as it would with no argument.
Examples:
if (gensym) => #:g0007 then (gensym 'foo) => #:foo0008 (gensym 32.) => #:foo0032 (gensym) => #:foo0033
Note that the number is in decimal and always has four digits.
#:
is the prefix normally printed before uninterned symbols.
gensym
is usually used to create a symbol which should not normally
be seen by the user, and whose print-name is unimportant, except to
allow easy distinction by eye between two such symbols.
The optional argument is rarely supplied.
The name comes from ‘generate symbol’, and the symbols produced by it
are often called “gensyms”.
"t"
) (a-package package
) ¶Creates and returns a new symbol whose name starts with prefix, interned in a-package, and distinct from any symbol already present there. This is done by trying names one by one until a name not already in use is found, which may be very slow.
Zetalisp includes several types of numbers, with different
characteristics. Most numeric functions accept any type of numbers as
arguments and do the right thing. That is to say, they are generic.
In Maclisp, there are generic numeric functions (like plus
) and there
are specific numeric functions (like +
) which only operate on a certain
type of number, but are much more efficient.
In Zetalisp, this distinction does not exist; both function
names exist for compatibility but they are identical. The microprogrammed
structure of the machine makes it possible to have only the generic
functions without loss of efficiency.
The types of numbers in Zetalisp are:
Fixnums are 25-bit twos-complement binary integers. These are the preferred, most efficient type of number.
Bignums are arbitrary-precision binary integers.
Ratios represent rational numbers exactly as the quotient of two integers, each of which can be a fixnum or a bignum. Ratios with a denominator of one are not normally created, as an integer is returned instead.
Full size floats are floating-point numbers. They have a mantissa of 31 bits and an exponent of 11 bits, providing a precision of about 9 digits and a range of about 10^300. Stable rounding is employed.
Short floats are another form of floating-point number, with a mantissa of 17 bits and an exponent of 8 bits, providing a precision of about 5 digits and a range of about 10^38. Stable rounding is employed. Short floats are useful because, like fixnums, and unlike full-size floats, they don’t require any storage. Computing with short floats is more efficient than with full-size floats because the operations are faster and consing overhead is eliminated.
Complexnums represent complex numbers with a real part and an imaginary
part, which can be any type of number except complexnums. (They must be
both rational or both floats of the same type). It is impossible to
make a complexnum whose real part is rational and whose imaginary part
is the intreger zero; it is always changed into a real number. However, it is
possible to create complexnums with an imaginary part of 0.0, and such numbers may result from
calculations involving complexnums. In fact, 5.0 and 5.0+0.0i are always distinct;
they are not eql
, and arithmetic operations will never canonicalize a complexnum
with floating-point zero imaginary part into a real number.
Generally, Lisp objects have a unique identity; each exists, independent
of any other, and you can use the eq
predicate to determine whether
two references are to the same object or not. Numbers are the exception
to this rule; they don’t work this way. The following function may return
either t
or nil
. Its behavior is considered undefined;
as this manual is written, it returns t
when interpreted but nil
when compiled.
(defun foo () (let ((x (float 5))) (eq x (car (cons x nil)))))
This is very strange from the point of view of Lisp’s usual object
semantics, but the implementation works this way, in order to gain
efficiency, and on the grounds that identity testing of numbers is not
really an interesting thing to do. So the rule is that the result
of applying eq
to numbers is undefined, and may return either
t
or nil
on what appear to be two pointers to the same
numeric object. The only reasonable ways to compare numbers are
=
(see =-fun) and eql
(eql-fun), and other
things (equal
or equalp
) based on them.
Conversely, fixnums and short floats have the unusual property that
they are always eq
if they are equal in value. This is because
they do not point to storage; the “pointer” field of a fixnum is actually
its numeric value, and likewise for short floats. Stylisticly it is
better to avoid depending on this, by using eql
rather than
eq
. Also, comparing floats of any sort for exact equality, even
with =
which is guaranteed to consider only the numeric values, is
usually unwise since round-off error can make the answer unpredictable
and meaningless.
The distinction between fixnums and bignums is largely transparent to
the user. The user simply computes with integers, and the system
represents some as fixnums and the rest (less efficiently) as bignums.
The system automatically converts back and forth between fixnums and
bignums based solely on the size of the integer. There are a few low
level functions which only work on fixnums; this fact is noted in
their documentation. Also, when using eq
on numbers the user
needs to be aware of the fixnum/bignum distinction.
Integer computations cannot overflow, except for division by zero,
since bignums can be of arbitrary size. Floating-point computations
can get exponent overflow or underflow, if the result is too large or small
to be represented. Exponent overflow always signals an error.
Exponent underflow normally signals an error, and assumes 0.0
as the answer
if the user says to proceed from the error. However, if the value of the
variable zunderflow
is non-nil
, the error is skipped
and computation proceeds with 0.0
in place of the result that was too small.
When an arithmetic function of more than one argument is given arguments of different numeric types, uniform coercion rules are followed to convert the arguments to a common type, which is also the type of the result (for functions which return a number). When an integer meets a ratio, the result is a ratio. When an integer or ratio meets a float, the result is a float of the same sort. When a short-float meets a full-size float, the result is a full-size float.
If any argument of the arithmetic function is complex, the other arguments are converted to complex. The components of a complex result must be both full-size floats, both small-floats, or both rational; if they differ, the one whose type comes last in that list is converted to match the other. Finally, if the components of the result are rational and the imaginary part is zero, the result is simply the real part. If, however, the components are floats, the value is always complex even if the imaginary part is zero.
Thus if the constants in a numerical algorithm are written as short floats (assuming this provides adequate precision), and if the input is a short float, the computation is done with short floats and the result is a short float, while if the input is a full-size float the computation is done in full precision and the result is a full-size float.
Zetalisp never automatically converts between full-size floats and short floats in the same way as it automatically converts between fixnums and bignums since this would lead either to inefficiency or to unexpected numerical inaccuracies. (When a short float meets a full-size float, the result is a full-size float, but if you use only one type, all the results are of the same type too.) This means that a short float computation can get an exponent overflow error even when the result could have been represented as a full-size float.
Floating-point numbers retain only a certain number of bits of precision; therefore, the results of computations are only approximate. Full-size floats have 31 bits and short floats have 17 bits, not counting the sign. The method of approximation is “stable rounding”. The result of an arithmetic operation is the float which is closest to the exact value. If the exact result falls precisely halfway between two representable floats, the result is rounded down if the least-significant bit is 0, or up if the least-significant bit is 1. This choice is arbitrary but insures that no systematic bias is introduced.
Unlike Maclisp, Zetalisp does not have number declarations in the compiler. Note that because fixnums and short floats require no associated storage they are as efficient as declared numbers in Maclisp. Bignums and full-size floats are less efficient; however, bignum and float intermediate results are garbage-collected in a special way that avoids the overhead of the full garbage collector.
The different types of numbers can be distinguished by their printed
representations. If a number has an exponent separated by ‘s
’, it
is a short float. If a number has an exponent separated by ‘f
’, it
is a full-size float. A leading or embedded (but not trailing)
decimal point, and/or an exponent separated by ‘e
’, indicates a
float; which kind is controlled by the variable
*read-default-float-format*
, which is usually set to specify
full-size floats. Short floats require a special indicator so that
naive users will not accidentally compute with the lesser precision.
Fixnums and bignums have similar printed representations since there is
no numerical value that has a choice of whether to be a fixnum or a
bignum; an integer is a bignum if and only if its magnitude is too big
for a fixnum. See the examples on flonum-examples, in the
description of what the reader understands.
When this is nil
, floating point exponent underflow is an error.
When this is t
, exponent underflow proceeds, returning zero as the value.
The same thing could be accomplished with a condition handler.
However, zunderflow
is useful for Maclisp compatibility, and is also faster.
sys:floating-exponent-overflow
: (sys:arithmetic-error
error
) ¶sys:floating-exponent-underflow
: (sys:arithmetic-error
error
) ¶sys:floating-exponent-overflow
is signaled when the result of an
arithmetic operation should be a floating point number, but the exponent
is too large to be represented in the format to be used for the value.
sys:floating-exponent-underflow
is signaled when the exponent is too
small.
The condition instance provides two additional operations:
:function
, which returns the arithmetic function that was called,
and :small-float-p
, which is t
if the result was supposed to be
a short float.
sys:floating-exponent-overflow
provides the :new-value
proceed
type. It expects one argument, a new value.
sys:floating-exponent-underflow
provides the :use-zero
proceed
type, which expects no argument.
Unfortunately, it is not possible to make the arguments to the operation available. Perhaps someday they will be.
Returns t
if x is zero. Otherwise it returns nil
.
If x is not a number, zerop
causes an error. For floats,
this only returns t
for exactly 0.0
or 0.0s0
.
For complex numbers, it returns t
if both real and imaginary
parts are zero.
Returns t
if its argument is a positive number, strictly greater
than zero. Otherwise it returns nil
.
If x is not a number, plusp
causes an error.
Returns t
if its argument is a negative number, strictly
less than zero. Otherwise it returns nil
.
If x is not a number, minusp
causes an error.
Returns t
if number is odd, otherwise nil
.
If number is not a fixnum or a bignum, oddp
causes an error.
Returns t
if number is even, otherwise nil
.
If number is not a fixnum or a bignum, evenp
causes an error.
Tests the sign of a number. signp
is present only for
Maclisp compatibility and is not recommended for use in new programs.
signp
returns t
if x is a number which
satisfies the test, nil
if it is not a number or does not meet
the test. test is not evaluated, but x is. test can be
one of the following:
l
x < 0
le
x lessOrEqual
0
e
x = 0
n
x notEquals
0
ge
x greaterOrEqual
0
g
x > 0
Examples:
(signp ge 12) => t (signp le 12) => nil (signp n 0) => nil (signp g 'foo) => nil
See also the data-type predicates integerp
, rationalp
,
realp
, complexp
,
floatp
, bigp
, small-floatp
, and numberp
(fixp-fun).
All of these functions require that their arguments be numbers; they signal an error if given a non-number. Equality tests work on all types of numbers, automatically performing any required coercions (as opposed to Maclisp in which generally only the spelled-out names work for all kinds of numbers). Ordering comparisons allow only real numbers, since they are meaningless on complex numbers.
Returns t
if all the arguments are numerically equal. They need not
be of the same type; 1 and 1.0 are considered equal. Character objects
are also allowed, and in effect coerced to integers for comparison.
See also eql
, eql-fun, which insists that both the type and the value
match when its arguments are numbers.
>
compares each pair of successive arguments. If any argument
is not greater than the next, >
returns nil
. But if the
arguments are monotonically strictly decreasing, the result is t
.
Zero arguments are always monotonically decreasing, and so is
a single argument.
Examples:
(>) => t (> 3) => t (> 4 3) => t (> 4 3 2 1 0) => t (> 4 3 1 2 0) => nil
greaterp
is the Maclisp name for this function.
greaterOrEqual
compares each pair of successive arguments. If any argument
is less than the next, greaterOrEqual
returns nil
. But if the
arguments are monotonically decreasing or equal, the result is t
.
>=
is the Common Lisp name for this function.
<
compares each pair of successive arguments. If any argument
is not less than the next, <
returns nil
. But if the
arguments are monotonically strictly increasing, the result is t
.
Examples:
(<) => t (< 3) => t (< 3 4) => t (< 1 1) => nil (< 0 1 2 3 4) => t (< 0 1 3 2 4) => nil
lessp
is the Maclisp name for this function.
lessOrEqual
compares its arguments from left to right. If any argument
is greater than the next, lessOrEqual
returns nil
. But if the
arguments are monotonically increasing or equal, the result is t
.
<=
is the Common Lisp name for this function.
t
if no two arguments are numerically equal.
This is the same as (not (= ...))
when there are two arguments,
but not when there are more than two.
With zero or one argument, the value is always t
, since
there is no pair of arguments that fail to be equal.
//=
is the Common Lisp name for this function.
In Common Lisp syntax, it would be written /=
.
Returns the largest of its arguments, which must not be complex.
Example:
(max 1 3 2) => 3
max
requires at least one argument.
Returns the smallest of its arguments, which must not be complex.
Example:
(min 1 3 2) => 1
min
requires at least one argument.
All of these functions require that their arguments be numbers, and signal
an error if given a non-number. They work on all types of numbers,
automatically performing any required coercions (as opposed to Maclisp,
in which generally only the spelled-out versions work for all kinds
of numbers, and the ‘$
’ versions are needed for floats).
Returns the sum of its arguments. If there are no arguments, it returns
0
, which is the identity for this operation.
plus
and $+
are Maclisp names, supported for
compatibility.
With only one argument, -
returns the negative of its argument.
With more than one argument, -
returns its first argument minus
all of the rest of its arguments.
Examples:
(- 1) => -1 (- -3.0) => 3.0 (- 3 1) => 2 (- 9 2 1) => 6
-$
is a Maclisp name, supported for compatibility.
Returns the negative of x, just like -
with one argument.
Returns its first argument minus all of the rest of its arguments.
If there are at least two arguments, difference
is equivalent to
-
.
Returns |x|
, the absolute value of the number x.
abs
for real numbers could have been defined as
(defun abs (x) (cond ((minusp x) (minus x)) (t x)))
abs
of a complex number could be computed, though imprecisely, as
(sqrt (^ (realpart x) 2) (^ (imagpart x) 2))
Returns the product of its arguments. If there are no arguments, it
returns 1
, which is the identity for this operation.
times
and *$
are Maclisp names, supported for compatibility.
With more than one argument, //
it returns the first argument divided by all of the rest of its arguments.
With only one argument, (// x)
is the same as (// 1 x)
.
The name of this function is written //
rather than /
because
/
is the escape character in traditional Lisp syntax and must be
escaped in order to suppress that significance. //$
is a Maclisp
name, supported for compatibility.
//
of two integers returns an integer even if the mathematically
correct value is not an integer. More precisely, the value is the
same as the first value returned by truncate
(see below). This
will eventually be changed, and then the value will be a ratio if
necessary so that the it is mathematically correct. All code that
relies on //
to return an integer value rather than a ratio should
be converted to use truncate
(or floor
or ceiling
, which
may simplify the code further). In the mean time, use the function
cli://
if you want a rational result.
Examples:
(// 3 2) => 1 ;Fixnum division truncates.
(// 3 -2) => -1
(// -3 2) => -1
(// -3 -2) => 1
(// 3 2.0) => 1.5
(// 3 2.0s0) => 1.5s0
(// 4 2) => 2
(// 12. 2. 3.) => 2
(// 4.0) => .25
Returns the first argument divided by all of the rest of its arguments.
When there are two or more arguments, quotient
is equivalent to
//
.
This is the Common Lisp division function. It is like //
except
that it uses exact rational division when the arguments are integers.
//
will someday be changed to divide integers exactly. Then there
will no longer be a distinct function cli://
; that name will become
equivalent to //
.
Note that in Common Lisp syntax you would write just /
rather than
cli://
.
There are four functions for “integer division”, the sort which produces a quotient and a remainder. They differ in how they round the quotient to an integer, and therefore also in the sign of the remainder. The arguments must be real, since ordering is needed to compute the value. The quotient is always an integer, but the arguments and remainder need not be.
1
) ¶floor
’s first value is the largest integer less than or equal to the
quotient of x divided by y.
The second value is the remainder, x minus y times the first value. This has the same sign as y (or may be zero), regardless of the sign of x.
With one argument, floor
’s first value is the largest integer less than
or equal to the argument.
1
) ¶ceiling
’s first value is the smallest integer greater than or equal
to the quotient of x divided by y.
The second value is the remainder, x minus y times the first value. This has the opposite sign from y (or may be zero), regardless of the sign of x.
With one argument, ceiling
’s first value is the smallest integer greater than
or equal to the argument.
1
) ¶truncate
is the same as floor
if the arguments have the same
sign, ceiling
if they have opposite signs. truncate
is the
function that the divide instruction on most computers implements.
truncate
’s first value is the nearest integer, in the direction of
zero, to the quotient of x divided by y.
The second value is the remainder, x minus y times the first value. This has the same sign as x (or may be zero).
1
) ¶round
’s first value is the nearest integer
to the quotient of x divided by y. If the quotient is midway
between two integers, the even integer of the two is used.
The second value is the remainder, x minus y times the first value. The sign of this remainder cannot be predicted from the signs of the arguments alone.
With one argument, round
’s first value is the integer nearest to the
argument.
Here is a table which clarifies the meaning of floor
, ceiling
,
truncate
and round
with one argument:
floor ceiling truncate round 2.6 2 3 2 3 2.5 2 3 2 2 2.4 2 3 2 2 0.7 0 1 0 1 0.3 0 1 0 0 -0.3 -1 0 0 0 -0.7 -1 0 0 -1 -2.4 -3 -2 -2 -2 -2.5 -3 -2 -2 -2 -2.5 -3 -2 -2 -2 -2.6 -3 -2 -2 -3
There are two kinds of remainder function, which differ in the treatment of negative numbers. The remainder can also be obtained as the second value of one of the integer division functions above, but if only the remaineder is desired it is simpler to use these functions.
Returns the remainder of x divided by y.
x and y must be integers (fixnums or bignums).
This is the same as the second value of (truncate x y)
.
Only the absolute value of the divisor is relevant.
(\ 3 2) => 1 (\ -3 2) => -1 (\ 3 -2) => 1 (\ -3 -2) => -1
Common Lisp gives this function the name rem
, but since rem
in
traditional Zetalisp is a function to remove elements from lists (see
rem-fun), the name rem
is defined to mean remainder only in Common
Lisp programs. Note that the name \
would have to be written as
\\
in Common Lisp syntax; but the function \
is not standard
Common Lisp.
Returns the root of number modulo divisor. This is a number
between 0 and divisor, or possibly 0, whose difference from
number is a multiple of divisor. It is the same as the second
value of (floor number divisor)
. Examples:
(mod 2 5) => 2 (mod -2 5) => 3 (mod -2 -5) => -2 (mod 2 -5) => -3
There are four “floating point integer division” functions. These produce a result which is a floating point number whose value is exactly integral.
1
) ¶1
) ¶1
) ¶1
) ¶Like floor
, ceiling
, truncate
and round
except
that the first value is converted from an integer to a float.
If x is a float, then the result is the same type of float as x.
sys:divide-by-zero
: (sys:arithmetic-error
error
) ¶Dividing by zero, using any of the above division functions, signals this
condition. The :function
operation on the condition instance
returns the name of the division function. The :dividend
operation
may be available to return the number that was divided.
(1+ x)
is the same as (+ x 1)
. The other two names
are for Maclisp compatibility.
(1- x)
is the same as (- x 1)
. Note that the
short name may be confusing: (1- x)
does not mean 1-x;
rather, it means x-1. The names sub1
and 1-$
are
for Maclisp compatibility.
Returns the greatest common divisor of all its arguments, which must be integers. With one argument, the value is that argument. With no arguments, the value is zero.
In Common Lisp syntax \\
would be written as \\\\
,
but only the name gcd
is valid in strict Common Lisp.
Returns the least common multiple of the specified integers.
Returns x raised to the y’th power. The result is rational (and
possibly an integer) if x is rational and y an integer. If the exponent is
an integer a repeated-squaring algorithm is used; otherwise the result
is (exp (* y (log x)))
.
If y is zero, the result is (+ 1 (* x y))
;
this is equal to one, but its type depends on those of x and y.
sys:zero-to-negative-power
: (sys:arithmetic-error
error
) ¶This condition is signaled when expt
’s first argument is zero
and the second argument is negative.
Returns the square root of x. A mathematically unavoidable
discontinuity occurs for negative real arguments, for which the value
returned is a positive real times i
.
(sqrt 4) => 2 (sqrt -4) => 0+2i (sqrt -4+.0001i) => .00005+2i (approximately) (sqrt -4-.0001i) => .00005-2i (approximately)
Integer square-root. x must be an integer; the result is the greatest integer less than or equal to the exact square root of x.
These are the internal microcoded arithmetic functions. There is no
reason why anyone should need to write code with these explicitly, since the
compiler knows how to generate the appropriate code for plus
,
+
, etc. These names are only here for Maclisp compatibility.
The internal division function used by cli://
,
it was available before cli://
was and may therefore
be used in some programs. It takes exactly two arguments.
Uses of %div
should be changed to use cli://
.
See also the predicates realp
and complexp
(complexp-fun).
Returns the complex number whose real part is x and whose imaginary part is y.
If x is rational and y is zero or omitted, the value is x, and not a complex number at all. If x is a float and y is zero or omitted, of if y is a floating zero, the result is a complexnum whose imaginary part is zero.
Returns the real part of the number z. If z is real, this is the same as z.
Returns the imaginary part of the number z. If z is real, this is zero.
Returns the complex conjugate of the number z. If z is real, this is the same as z.
Returns the phase angle of the complex number z in its polar form.
This is the angle from the positive x axis to the ray from the
origin through z. The value is always in the interval (-pi, pi]
.
(phase -4) => pi
(phase -4-.0001i) is just over -pi
.
(phase 0) => 0 (an arbitrary choice)
Returns the complex number of unit magnitude whose phase is angle.
This is equal to (complex (cos angle) (sin angle))
.
angle must be real.
Returns a number with unit magnitude and the same type and phase as z. If z is zero, the value is zero.
If z is real, the value is =
to 1
or -1
;
it may be a float, however.
These functions are only for floating-point arguments; if given an integer they convert it to a float. If given a short float, they return a short float.
The value of pi
, as a full-size float.
Returns e raised to the x’th power, where e is the base of natural logarithms.
Returns the logarithm of x to base base. base
defaults to e. When base is e, the imaginary
part of the value is in the interval (-pi, pi]
; for
negative real x, the value has imaginary part pi
.
If base is specified, the result is
(// (log x) (log base))
sys:zero-log
: (sys:arithmetic-error
error
) ¶This is signaled when the argument to log
is zero.
Return, respectively, the sine, cosine and tangent of x, where x is expressed in radians. x may be complex.
Return, respectively, the sine, cosine and tangent of x, where x is expressed in degrees.
Returns the angle (in radians) whose sine (respectively, cosine)
is x. The real part of the result of asin
is
between -pi/2
and pi/2
; acos
and asin
of any given argument always add up to pi/2
.
If only y is given, the value is the angle, in radians, whose
tangent is y. The real part of the result is between zero and -pi
.
If x is also given, both arguments must be real, and the value is
an angle, in radians, whose tangent is y/x. However, the signs
of the two arguments are used to choose between two angles which
differ by pi
and have the same tangent. The one chosen is the
angle from the x-axis counterclockwise to the line from the origin
to the point (x, y).
atan
always returns a non-negative number between zero and
2pi
.
Like atan
but always returns a value whose real part is between
-pi/2
and pi/2
. The value is either the same as
the value of atan
or differs from it by pi
.
atan2
is the traditional name of this function.
In Common Lisp it is called atan
; it is documented as
cli:atan
since the name atan
has a different meaning
in traditional syntax.
These functions are provided to allow specific conversions of data types to be forced, when desired.
Converts number to a floating point number and returns it.
If float is specified, the result is of the same floating point format as float. If number is a float of a different format then it is converted.
If float is omitted, then number is converted to a single-float unless it is already a floating point number.
A complex number is converted to one whose real and imaginary parts are full-size floats unless they are already both floats.
Converts any kind of real number to a short-float. A complex number is converted to one whose real and imaginary parts are short floats. The two names are synonymous.
Returns the numerator of the rational number x. If x is an integer, the value equals x. If x is not an integer or ratio, an error is signaled.
Returns the denominator of the rational number x. If x is an
integer, the value is 1
. If x is not an integer or
ratio, an error is signaled.
Converts x to a rational number. If x is an integer or a ratio, it is returned unchanged. If it is a floating point number, it is regarded as an exact fraction whose numerator is the mantissa and whose denominator is a power of two. For any other argument, an error is signaled.
Returns a rational approximation to x.
If there is only one argument, and it is an integer or a ratio, it is returned unchanged. If the argument is a floating point number, a rational number is returned which, if converted to a floating point number, would produce the original argument. Of all such rational numbers, the one chosen has the smallest numerator and denominator.
If there are two arguments, the second one specifies how much precision of the first argument should be considered significant. precision can be a positive integer (the number of bits to use), a negative integer (the number of bits to drop at the end), or a floating point number (minus its exponent is the number of bits to use).
If there are two arguments and the first is rational, the value is a “simpler” rational which approximates it.
Converts x from a float or ratio to an integer, truncating towards negative infinity. The result is a fixnum or a bignum as appropriate. If x is already a fixnum or a bignum, it is returned unchanged.
fix
is the same as floor
except that floor
returns an
additional value. fix
is semi-obsolete, since the functions floor
,
ceiling
, truncate
and round
provide four different ways of
converting numbers to integers with different kinds of rounding.
fixr
is the same as round
except that round
returns an
additional value. fixr
is considered obsolete.
Returns three values which describe the value of float.
The first value is a positive float of the same format having the same mantissa, but with an exponent chosen to make it between 1/2 and 1, less than 1.
The second value is the exponent of float: the power of 2 by which the first value needs to be scaled in order to get float back.
The third value expresses the sign of float. It is a float of the same format as float, whose value is either 1 or -1. Example:
(decode-float 38.2) => 0.596875 6 1.0
Like decode-float
except that the first value is scaled so as to
make it an integer, and the second value is modified by addition of a
constant to compensate.
(integer-decode-float 38.2) => #o11431463146 -25. 1.0
Multiplies float by 2 raised to the integer power. float can actually be an integer also; it is converted to a float and then scaled.
(scale-float 0.596875 6) => 38.2 (scale-float #o11431463146 -25.) => 38.2
Returns a float whose sign matches that of float1 and whose magnitude and format are those of float2. If float2 is omitted, 1.0 is used as the magnitude and float1’s format is used.
(float-sign -1.0s0 35.3) => -35.3 (float-sign -1.0s0 35.3s0) => -35.3s0
Defined by Common Lisp to return the radix used for the exponent in the
format used for float. On the Lisp Machine, floating point
exponents are always powers of 2, so float-radix
ignores its
argument and always returns 2.
Returns the number of bits of mantissa in the floating point format which float is an example of. It is 17 for short floats and 31 for full size ones.
Returns the number of significant figures present in in the mantissa of float.
This is always the same as (float-digits float)
for normalized numbers,
and on the Lisp Machine all floats are normalized, so the two functions are the same.
Except for lsh
and rot
, these functions operate on both
fixnums and bignums. lsh
and rot
have an inherent word-length
limitation and hence only operate on 25-bit fixnums. Negative numbers
are operated on in their 2’s-complement representation.
Returns the bit-wise logical inclusive or of its arguments. With no arguments, the value is zero, which is the identity for this operation.
Example (in octal):
(logior #o4002 #o67) => #o4067
Returns the bit-wise logical and of its arguments. With no arguments, the value is -1, which is the identity for this operation.
Examples (in octal):
(logand #o3456 #o707) => #o406 (logand #o3456 #o-100) => #o3400
Returns the bit-wise logical exclusive or of its arguments. With no arguments, the value is zero, which is the identity for this operation.
Example (in octal):
(logxor #o2531 #o7777) => #o5246
Combines the integers together bitwise using the equivalence operation, which, for two arguments, is defined to result in 1 if the two argument bits are equal. This operation is asociative. With no args, the value is -1, which is an identity for the equivalence operation.
Example (in octal):
(logeqv #o2531 #o7707) => #o-5237 = ...77772541
Non-associative bitwise operations take only two arguments:
Returns the bitwise-nand of the two arguments. A bit of the result is 1 if at least one of the corresponding argument bits is 0.
Returns the bitwise-nor of the two arguments. A bit of the result is 1 if both of the corresponding argument bits are 0.
Returns the bitwise-or of integer2 with the complement of integer1.
Returns the bitwise-or of integer1 with the complement of integer2.
Returns the bitwise-and of integer2 with the complement of integer1.
Returns the bitwise-and of integer1 with the complement of integer2.
Returns the logical complement of number. This is the same as
logxor
’ing number with -1.
Example:
(lognot #o3456) => #o-3457
boole
is the generalization of logand
, logior
, and logxor
.
fn should be a fixnum between 0 and 17 octal inclusive;
it controls the function which is computed. If the binary representation
of fn is abcd (a is the most significant bit, d the least)
then the truth table for the Boolean operation is as follows:
y | 0 1 --------- 0| a c x | 1| b d
If boole
has more than three arguments, it is associated left
to right; thus,
(boole fn x y z) = (boole fn (boole fn x y) z)
With two arguments, the result of boole
is simply its second argument.
At least two arguments are required.
Examples:
(boole 1 x y) = (logand x y) (boole 6 x y) = (logxor x y) (boole 2 x y) = (logand (lognot x) y)
logand
, logior
, and so on are usually preferred over the equivalent
forms of boole
. boole
is useful when the operation to be performed
is not constant.
The boole
opcodes that correspond to the functions logior
, logand
, etc.
The boole
opcodes for the four trivial operations. Respectively, they
are those which always return zero, always return one, always return the
first argument, and always return the second argument.
bit-test
is a predicate which returns t
if any of
the bits designated by the 1’s in x are 1’s in y.
bit-test
is implemented as a macro which expands as follows:
(bit-test x y) ==> (not (zerop (logand x y)))
logtest
is the Common Lisp name for this function.
Returns x shifted left y bits if y is positive or zero,
or x shifted right |y|
bits if y is negative.
Zero bits are shifted in (at either end) to fill unused positions.
x and y must be fixnums. (In some applications you may
find ash
useful for shifting bignums; see below.)
Examples:
(lsh 4 1) => #o10 (lsh #o14 -2) => 3 (lsh -1 1) => -2
Shifts x arithmetically left y bits if y is positive,
or right -y bits if y is negative.
Unused positions are filled by zeroes from the right, and
by copies of the sign bit from the left. Thus, unlike lsh
,
the sign of the result is always the same as the sign of x.
If x is a fixnum or a bignum, this is a shifting operation.
If x is a float, this does scaling (multiplication by a power of two),
rather than actually shifting any bits.
Returns x rotated left y bits if y is positive or zero,
or x rotated right |y|
bits if y is negative.
The rotation considers x as a 25-bit number (unlike Maclisp,
which considers x to be a 36-bit number in both the pdp-10
and Multics implementations).
x and y must be fixnums. (There is no function for
rotating bignums.)
Examples:
(rot 1 2) => 4 (rot 1 -2) => #o20000000 (rot -1 7) => -1 (rot #o15 25.) => #o15
Returns the number of 1 bits in integer, if it is positive. Returns the number of 0 bits in integer, if it is negative. (There are infinitely many 1 bits in a negative integer.)
(logcount #o15) => 3 (logcount #o-15) => 2
The minimum number of bits (aside from sign) needed to represent
integer in two’s complement. This is the same as haulong
for positive numbers.
(integer-length 0) => 0 (integer-length 7) => 3 (integer-length 8) => 4 (integer-length -7) => 3 (integer-length -8) => 3 (integer-length -9) => 4
The same as integer-length
of the absolute value of integer
.
This name exists for Maclisp compatibility only.
Returns the high n bits of the binary representation of |x|
,
or the low -n
bits if n is negative.
x may be a fixnum or a bignum; its sign is ignored.
haipart
could have been defined by:
(defun haipart (x n) (setq x (abs x)) (if (minusp n) (logand x (1- (ash 1 (- n)))) (ash x (min (- n (haulong x)) 0))))
Several functions are provided for dealing with an arbitrary-width field of contiguous bits appearing anywhere in an integer (a fixnum or a bignum). Such a contiguous set of bits is called a byte. Note that we are not using the term byte to mean eight bits, but rather any number of bits within a number. These functions use numbers called byte specifiers to designate a specific byte position within any word. A byte specifier contains two pieces of information: the size of the byte, and the position of the byte. The position is expressed as the number of least significant bits which are not included in the byte. A position of zero means that the byte is at the right (least significant) end of the number.
The maximum value of the size is 24, since a byte must fit in a fixnum although bytes can be loaded from and deposited into bignums. (Bytes are always positive numbers.)
Byte specifiers are represented as fixnums whose two lowest octal digits represent the size of the byte, and whose higher (usually two, but sometimes more) octal digits represent the position of the byte within a number. For example, the byte-specifier #o0010 (i.e 10 octal) refers to the lowest eight bits of a word, and the byte-specifier #o1010 refers to the next eight bits. The format of byte-specifiers is taken from the pdp-10 byte instructions.
Much old code contains byte specifiers written explicitly as octal numbers.
It is cleaner to construct byte specifiers using byte
instead.
Decomposition of byte specifiers should always be done with
byte-position
and byte-size
, as at some time in the future
other kinds of byte specifiers may be created to refer to fields
whose size is greater than #o77.
Returns a byte specifier for the byte of size bits, positioned to
exclude the position least significant bits. This byte specifier
can be passed as the first argument to ldb
, dpb
, %logldb
,
%logdpb
, mask-field
, %p-ldb
, %p-ldb-offset
, and so on.
Return, respectively, the size and the position of byte-spec. It is always true that
(byte (byte-size byte-spec) (byte-position byte-spec))
equals byte-spec.
Extracts a byte from integer according to byte-soec. The
contents of this byte are returned right-justified in a fixnum. The
name of the function, ldb
, means ‘load byte’. integer may be a
fixnum or a bignum. The returned value is always a fixnum.
Example:
(ldb (byte 6 3) #o4567) => #o56
This is like ldb
except that instead of using a byte specifier,
the position and size are passed as separate arguments.
The argument order is not analogous to that of ldb
so that
load-byte
can be compatible with Maclisp.
ldb-test
is a predicate which returns t
if any of
the bits designated by the byte specifier byte-spec are 1’s in integer.
That is, it returns t
if the designated field is non-zero.
ldb-test
is implemented as a macro which expands as follows:
(ldb-test byte-spec integer) ==> (not (zerop (ldb byte-spec integer)))
t
if the bit index up from the least significant in integer is a 1.
This is equivalent to (ldb-test (byte index 1) integer)
.
This is similar to ldb
; however, the specified byte of fixnum is
positioned in the same byte of the returned value. The returned value
is zero outside of that byte. fixnum must be a fixnum.
Example:
(mask-field (byte 6 3) #o4567) => #o560
Returns a number which is the same as integer except in the bits
specified by byte-spec. The low bits of byte, appropriately
many, are placed in those bits. byte is interpreted as being
right-justified, as if it were the result of ldb
. integer may
be a fixnum or a bignum. The name means ‘deposit byte’.
Example:
(dpb #o23 (byte 6 3) #o4567) => #o4237
This is like dpb
except that instead of using a byte specifier,
the position and size are passed as separate arguments.
The argument order is not analogous to that of dpb
so that
deposit-byte
can be compatible with Maclisp.
This is like dpb
, except that byte is not taken to
be left-justified; the byte-spec bits of byte are used
for the byte-spec bits of the result, with the rest of the
bits taken from fixnum. fixnum must be a fixnum.
Example:
(deposit-field #o230 (byte 6 3) #o4567) => #o4237
The behavior of the following two functions depends on the size of
fixnums, and so functions using them may not work the same way
on future implementations of Zetalisp. Their names start
with %
because they are more like machine-level subprimitives
than the previous functions.
%logldb
is like ldb
except that it only loads out of fixnums and
allows a byte size of 25, i.e all 25 bits of the fixnum
including the sign bit.
%logdpb
is like dpb
except that it only deposits into fixnums.
Using this to change the sign-bit leaves the result as a fixnum,
while dpb
would produce a bignum result for arithmetic correctness.
%logdpb
is good for manipulating fixnum bit-masks such as are used
in some internal system tables and data-structures.
The functions in this section provide a pseudo-random number generator
facility. The basic function you use is random
, which returns a new
pseudo-random number each time it is called.
Returns a randomly generated number. If number is specified, the random number is of the same type as number (floating if number is floating, etc), nonnegative, and less than number.
If number is omitted, the result is a randomly chosen fixnum, with all fixnums being equally likely.
If random-state is present, it is used and updated in generating
the random number. Otherwise, the default random-state (the value of
*random-state*
) is used (and is created if it doesn’t already
exist). The algorithm is executed inside a without-interrupts
(see without-interrupts-fun) so two processes can use the same
random-state without colliding.
Returns a random float in the interval [low, high). The default random-state is used.
A random-state is a named structure of type random-state
whose
contents control the future actions of the random number generator.
Each time you call the function random
, it uses (and updates) one
random-state. One random-state exists standardly and is used by
default. To have several different controllable, resettable sources of
random numbers, you can create your own random-states. Random-states
print as
#s(random-state ...more data...)
so that they can be read back in.
t
if object is a random-state.
This random-state is used by default when random
is called
and the random-state is not explicitly specified.
Creates and returns a new random-state object.
If random-state is nil
, the new random-state is a copy of *random-state*
.
If random-state is a random-state, the new one is a copy of that one.
If random-state is t
, the new random-state is initialized truly randomly
(based on the value of (time)
).
A random-state actually consists of an array of numbers and two pointers into the array. The pointers circulate around the array; each time a random number is requested, both pointers are advanced by one, wrapping around at the end of the array. Thus, the distance forward from the first pointer to the second pointer stays the same, allowing for wraparound. Let the length of the array be length and the distance between the pointers be offset. To generate a new random number, each pointer is set to its old value plus one, modulo length. Then the two elements of the array addressed by the pointers are added together; the sum is stored back into the array at the location where the second pointer points, and is returned as the random number after being normalized into the right range.
This algorithm produces well-distributed random numbers if length
and offset are chosen carefully, so that the polynomial
x ^
length + x ^
offset + 1 is irreducible over the mod-2 integers. The
system uses 71 and 35.
The contents of the array of numbers should be initialized to anything moderately random, to make the algorithm work. The contents get initialized by a simple random number generator, based on a number called the seed. The initial value of the seed is set when the random-state is created, and it can be changed.
nil
) ¶Creates and returns a new random-state according to precise
specifications. length is the length of the array. offset is
the distance between the pointers and should be an integer less than
length. seed is the initial value of the seed, and should be a
fixnum. This calls si:random-initialize
on the random state before
returning it.
random-state must be a random-state, such as is created by
si:random-create-array
. If new-seed is provided, it should be a
fixnum, and the seed is set to it. si:random-initialize
reinitializes the
contents of the array from the seed (calling random
changes the
contents of the array and the pointers, but not the seed).
Common Lisp defines some constants whose values give information in a standard way about the ranges of numbers representable in the individual Lisp implementation.
Any integer smaller than this must be a bignum.
Any integer larger than this must be a bignum.
No short float can be greater than this number.
No positive short float can be closer to zero than this number.
No negative short float can be closer to zero than this number.
No short float can be less than this (negative) number.
Similar to the above, but for full-size floats rather than for short floats.
These are defined by Common Lisp to be similar to the above,
but for double-floats and long-floats. On the Lisp Machine,
there are no distinct double and long floating formats; they are
synonyms for single-floats. So these constants exist but their values
are the same as those of most-positive-single-float
and so on.
Smallest positive short float which can be added to 1.0s0 and make a difference.
That is, for any short float x less than this, (+ 1.0s0 x)
equals 1.0s0.
Smallest positive float which can be added to 1.0 and make a difference. The three names are synonyms on the Lisp Machine, for reasons explained above.
Smallest positive short float which can be subtracted from 1.0s0 and make a difference.
Sometimes it is desirable to have a form of arithmetic which has no overflow checking (that would produce bignums), and truncates results to the word size of the machine.
Returns a fixnum which is pointer-1 plus pointer-2, modulo what could be stored in the size of the pointer field (currently 25 bits). Arguments other than fixnums are rarely useful, but no type checks are made.
Returns a fixnum which is pointer-1 minus pointer-2. If the arguments are fixnums, rather than true pointers, this provides subtraction modulo what can be stored in the pointer field.
Returns a fixnum which is pointer-1 times pointer-2. Arguments other than fixnums are rarely useful, but no type checks are made. The two pointer fields are regarded as signed numbers.
Sometimes it is useful to have a form of truncating arithmetic with a strictly specified field width which is independent of the range of fixnums permissible on a particular machine. In Zetalisp, this is provided by the following set of functions. Their answers are correct only modulo 2^24.
These functions should not be used for efficiency; they are probably less efficient than the functions which do check for overflow. They are intended for algorithms which require this sort of arithmetic, such as hash functions and pseudo-random number generation.
Returns the sum of x and y modulo 2^24. Both arguments must be fixnums.
Returns the difference of x and y modulo 2^24. Both arguments must be fixnums.
Returns the product of x and y modulo 2^24. Both arguments must be fixnums.
These peculiar functions are useful in programs that don’t want to use bignums for one reason or another. They should usually be avoided, as they are difficult to use and understand, and they depend on special numbers of bits and on the use of twos-complement notation.
A double-precision number has 50 bits, of which one is the sign bit. It
is represented as two fixnums. The less signficant fixnum conveys 25
signficant bits and is regarded as unsigned (that is, what is normally
the sign bit is treated as an ordinary data bit); the more significant
fixnum has the same sign as the double-precision number. Only
%float-double
handles negative double-precision numbers; for the
other functions, the more signficant fixnum is always positive and
contains only 24 bits of actual data.
Returns bits 25 through 48 (the most significant half) of the product of
num1 and num2, regarded as unsigned integers. If you call this
and %pointer-times
on the same arguments num1 and num2, you
can combine the results into a double-precision product. If num1
and num2 are regarded as two’s-complement fractions, -1
num
< 1, %multiply-fractions
returns 1/2 of their correct
product as a fraction.
[The name of this function isn’t too great.]
Divides the double-precision number given by the first two arguments by the third argument, and returns the single-precision quotient. Causes an error if divisor is zero or if the quotient won’t fit in single precision.
There are only 24 bits in each half of the number, as neither sign bit is used to convey information.
Divides the double-precision number given by the first two arguments by the third argument, and returns the remainder. Causes an error if divisor is zero.
high25 and low25, which must be fixnums, are concatenated
to produce a 50-bit unsigned positive integer. A full-size float containing the
same value is constructed and returned. Note that only the 31 most significant
bits are retained (after removal of leading zeroes.) This function is
mainly for the benefit of read
.
An array is a Lisp object that consists of a group of cells,
each of which may contain an object. The individual cells are
selected by numerical subscripts. The type predicate arrayp
(arrayp-fun) can be used to test whether an object is an array.
The rank of an array (the number of dimensions which the
array has) is the number of subscripts used to refer to one of the
elements of the array. The rank may be any integer from zero to seven,
inclusively. An array of rank zero has a single element which is
addressed using no subscripts. An array of rank one is called a
vector; the predicate vectorp
(see vectorp-fun) tests whether an
object is a vector. A series of functions called the generic sequence
functions accept either a vector or a list as argument indiscriminantly
(see generic-sequence-functions).
A constant giving the upper limit on the rank of an array. It is 8, indicating that 7 is the highest possible rank.
The lowest value for any subscript is zero; the highest value is a property of the array. Each dimension has a size, which is the lowest number which is too great to be used as a subscript. For example, in a one-dimensional array of five elements, the size of the one and only dimension is five, and the acceptable values of the subscript are zero, one, two, three, and four.
Any one dimension of an array must be smaller than this constant.
The total size of an array is the number of elements in it. It is the product of the sizes of the dimensions of the array.
The total number of elements of any array must be smaller than this constant.
A vector can have a fill pointer which is a number saying how many elements of the vector are active. For many purposes, only that many elements (starting with element zero) are used.
The most basic primitive functions for handling arrays are:
make-array
, which is used for the creation of arrays, aref
,
which is used for examining the
contents of arrays, and aset
, which
is used for storing into arrays.
An array is a regular Lisp object, and it is common for an array to be the binding of a symbol, or the car or cdr of a cons, or, in fact, an element of an array. There are many functions, described in this chapter, which take arrays as arguments and perform useful operations on them.
Another way of handling arrays, inherited from Maclisp, is to treat them
as functions. In this case each array has a name, which is a symbol
whose function definition is the array. Zetalisp supports this
style by allowing an array to be applied to arguments, as if it were
a function. The arguments are treated as subscripts and the array is
referenced appropriately. The store
special form (see store-fun)
is also supported. This kind of array referencing is considered to be
obsolete and is slower than the usual kind. It should not be used in
new programs.
There are several types of arrays, which differ primarily in
which kinds of elements they are allowed to hold. Some types of arrays
can hold Lisp objects of any type; such arrays are called general
arrays. The other types of array restrict the possible elements to a
certain type, usually a numeric type. Arrays of these types are called
specialized arrays, or numeric arrays if the elements must be
numbers. For example, one array type permits only complex numbers with
floating components to be stored in the array. Another permits only the
numbers zero and one; Common Lisp calls these bit arrays. The
contents of a black-and-white screen are stored in a bit array. Several
predicates exist for finding out which of these classifications an array
belongs to: simple-vector-p
(simple-vector-p-fun),
bit-vector-p
, simple-bit-vector-p
, stringp
(stringp-fun),
and simple-string-p
.
The array types are known by a set of symbols whose names
begin with art-
(for ‘ARray Type’).
The most commonly used type is called art-q
. An art-q
array simply holds Lisp objects of any type.
Similar to the art-q
type is the art-q-list
. Like the
art-q
, its elements may be any Lisp object. The difference is that
the art-q-list
array doubles as a list; the function g-l-p
takes an art-q-list
array and returns a list whose elements are
those of the array, and whose actual substance is that of the array. If
you rplaca
elements of the list, the corresponding element of the
array is changed, and if you store into the array, the corresponding
element of the list changes the same way. An attempt to rplacd
the list causes a sys:rplacd-wrong-representation-type
error,
since arrays cannot implement that operation.
The most important type of specialized array is the string, which is
a vector of character objects. Character strings are implemented by the
art-string
array type. Many important system functions, including
read
, print
, and eval
, treat art-string
arrays very
differently from the other kinds of arrays. There are also many
functions specifically for operating on strings, described in chapter
string-chapter.
As viewed by Common Lisp programs, the elements of a string are character objects. As viewed by traditional programs, the elements are integers in the range 0 to 255. While most code still accesses strings in the traditional manner and gets integers out, the Common Lisp viewpoint is considered the correct one. See string-element-type for a discussion of this conflict of conventions and its effect on programs.
An art-fat-string
array is a character string with wider
characters, containing 16 bits rather than 8 bits. The extra bits are
ignored by many string operations, such as comparison, on these strings;
typically they are used to hold font information.
There is a set of types called art-1b, art-2b, art-4b, art-8b
,
and art-16b
;
these names are short for ‘1 bit’, ‘2 bits’, and so on. Each element
of an art-nb
array is a non-negative fixnum, and only the
least significant n bits are remembered in the array; all of the others are discarded. Thus art-1b
arrays store only 0 and 1, and
if you store a 5 into an art-2b
array and look at it
later, you will find a 1 rather than a 5.
These arrays are used when it is known beforehand that the
fixnums which will be stored are non-negative and limited in size to a
certain number of bits. Their advantage over the art-q
array is
that they occupy less storage, because more than one element of the
array is kept in a single machine word. (For example, 32 elements
of an art-1b
array or 2 elements of an art-16b
array
fit into one word).
There are also art-32b
arrays which have 32 bits per element.
Since fixnums only have 24 bits anyway, these are the same as art-q
arrays except that they only hold fixnums. They are not compatible
with the other “bit” array types and generally should not be used.
An art-half-fix
array contains half-size fixnums. Each element
of the array is a signed 16-bit integer; the range is from -32768 to 32767
inclusive.
The art-float
array type is a special-purpose type whose
elements are floats. When storing into such an array the value (any
kind of number) is converted to a float, using the float
function (see float-fun). The advantage of
storing floats in an art-float
array rather than an art-q
array is that the numbers in an art-float
array are not true Lisp
objects. Instead the array remembers the numerical value, and when it
is aref
’ed creates a Lisp object (a float) to hold the value.
Because the system does special storage management for bignums and
floats that are intermediate results, the use of art-float
arrays
can save a lot of work for the garbage collector and hence greatly
increase performance. An intermediate result is a Lisp object passed
as an argument, stored in a local variable, or returned as the value of
a function, but not stored into a special variable, a non-art-float
array, or list structure. art-float
arrays also provide a locality
of reference advantage over art-q
arrays containing floats, since
the floats are contained in the array rather than being separate objects
probably on different pages of memory.
The art-fps-float
array type is another special-purpose type
whose elements are floats. The internal format of this array is compatible
with the PDP-11/VAX single-precision floating-point format. The primary purpose
of this array type is to interface with the FPS array processor, which can
transfer data directly in and out of such an array.
Any type of number may be stored into an art-fps-float
array, but it is, in effect, converted to a float, and then rounded
off to the 24-bit precision of the PDP-11. If the magnitude of the
number is too large, the largest valid floating-point number is
stored. If the magnitude is too small, zero is stored.
When an element of an art-fps-float
array is read, a new
float is created containing the value, just as with an art-float
array.
The art-complex
array type is a special purpose type whose
elements are arbitrary numbers, which may be complex numbers. (Most of
the numeric array types can only hold real numbers.) As compared with
an ordinary art-q
array, art-complex
provides an advantage in
garbage collection similar to what art-float
provides for floating
point numbers.
The art-complex-float
array type is a special purpose type whose
elements are numbers (real or complex) whose real and imaginary parts
are both floating point numbers. (If you store a non-floating-point
number into the array, its real and imaginary parts are converted to
floating point.) This provides maximum advantage in garbage collection
if all the elements you wish to store in the array are numbers with
floating point real and imaginary parts.
The art-complex-fps-float
array type is similar to
art-complex-float
but each real or imaginary part is stored in the
form used by the FPS array processor. Each element occupies two words,
the first being the real part and the second being the imaginary part.
There are three types of arrays which exist only for the
implementation of stack groups; these types are called
art-stack-group-head, art-special-pdl
, and art-reg-pdl
. Their elements
may be any Lisp object; their use is explained in the section on
stack groups (see stack-group).
The value of array-types
is a list of all of the array type symbols
such as art-q
, art-4b
, art-string
and so on. The values
of these symbols are internal array type code numbers for the corresponding
type.
Given an internal numeric array-type code, returns the symbolic name of that type.
array-elements-per-q
is an association list (see alist) which
associates each array type symbol with the number of array elements
stored in one word, for an array of that type. If the value is negative,
it is instead the number of words per array element, for arrays whose
elements are more than one word long.
Given the internal array-type code number, returns the number of array elements stored in one word, for an array of that type. If the value is negative, it is instead the number of words per array element, for arrays whose elements are more than one word long.
The value of array-bits-per-element
is an association list (see alist)
which associates each array type symbol with the number of
bits of unsigned number it can hold, or nil
if it can
hold Lisp objects. This can be used to tell whether an array
can hold Lisp objects or not.
Given the internal array-type code numbers, returns the number of bits
per cell for unsigned numeric arrays, or nil
for a type of array
that can contain Lisp objects.
Given an array, returns the number of bits that fit in an element of that array. For arrays that can hold general Lisp objects, the result is 25, based on the assumption that you will be storing fixnums in the array.
Any array may have an array leader. An array leader is
like a one-dimensional art-q
array which is attached to the main
array. So an array which has a leader acts like two arrays joined
together. The leader can be stored into and examined by a special set
of functions, different from those used for the main array:
array-leader
and store-array-leader
. The leader is always
one-dimensional, and always can hold any kind of Lisp object,
regardless of the type or rank of the main part of the array.
Very often the main part of an array is used as a homogeneous set of objects,
while the leader is used to remember a few associated non-homogeneous pieces of data.
In this case the leader is not used like an array; each slot is used
differently from the others. Explicit numeric subscripts should not be
used for the leader elements of such an array; instead the leader should be described
by a defstruct
(see defstruct-fun).
By convention, element 0 of the array leader of an array is used
to hold the number of elements in the array that are “active”. When the
zeroth element is used this way, it is called a fill pointer.
Many array-processing functions recognize the fill pointer.
For instance, if a string (an array of type art-string
) has
seven elements, but its fill pointer contains the value five, then only elements
zero through four of the string are considered to be active; the string’s
printed representation is five characters long, string-searching
functions stop after the fifth element, etc. Fill pointers are
a Common Lisp standard, but the array leader which is the Lisp Machine’s
way of implementing them is not standard.
Returns the fill pointer of array, or nil
if it does
not have one. This function can be used with setf
to set the
array’s fill pointer.
The system does not provide a way to turn off the fill-pointer convention; any array that has a leader must reserve element 0 for the fill pointer or avoid using many of the array functions.
Leader element 1 is used in conjunction with the “named structure” feature to associate a user-defined data type with the array; see named-structure. Element 1 is treated specially only if the array is flagged as a named structure.
The following explanation of displaced arrays is probably not of interest to a beginner; the section may be passed over without losing the continuity of the manual.
Normally, an array is represented as a small amount of header information, followed by the contents of the array. However, sometimes it is desirable to have the header information removed from the actual contents. One such occasion is when the contents of the array must be located in a special part of the Lisp Machine’s address space, such as the area used for the control of input/output devices, or the bitmap memory which generates the TV image. Displaced arrays are also used to reference certain special system tables, which are at fixed addresses so the microcode can access them easily.
If you give make-array
a fixnum or a locative
as the value of the :displaced-to
option,
it creates a displaced array referring to that location of virtual memory
and its successors.
References to elements of the displaced array will access that part
of storage, and return the contents; the regular aref
and
aset
functions are used. If the array is one whose elements
are Lisp objects, caution should be used: if the region of address
space does not contain typed Lisp objects, the integrity of the storage
system and the garbage collector could be damaged. If the array is one
whose elements are bytes (such as an art-4b
type), then there
is no problem. It is important to know, in this case, that the elements
of such arrays are allocated from the right to the left within the 32-bit
words.
It is also possible to have an array whose contents, instead
of being located at a fixed place in virtual memory, are defined
to be those of another array. Such an array is called an indirect array,
and is created by giving make-array
an array as
the value of the :displaced-to
option.
The effects of this are simple if both arrays have the same type; the two
arrays share all elements. An object stored in a certain element
of one can be retrieved from the corresponding element of the other.
This, by itself, is not very useful. However, if the arrays have
different rank, the manner of accessing the elements differs.
Thus, creating a one-dimensional array of nine elements,
indirected to a second, two-dimensional array of three elements by three,
allows access to the elements in either a one-dimensional or
a two-dimensional manner. Weird effects can be produced if
the new array is of a different type than the old array; this is not
generally recommended. Indirecting an art-mb
array to
an art-nb
array does the obvious thing. For instance,
if m is 4 and n is 1, each element of the first array
contains four bits from the second array, in right-to-left order.
It is also possible to create an indirect array in such a way
that when an attempt is made to reference it or store into it, a
constant number is added to the subscript given. This number is called
the index-offset. It is specified at the time the indirect array
is created, by giving a fixnum to make-array
as the value of the :displaced-index-offset
option.
The length of the indirect array need not be the full length of
the array it indirects to; it can be smaller. Thus the indirect array can
cover just a subrange of the original array.
The nsubstring
function (see nsubstring-fun) creates such
arrays. When using index offsets with multi-dimensional arrays, there
is only one index offset; it is added in to the linearized subscript
which is the result of multiplying each subscript by an appropriate
coefficient and adding them together.
Constructs and returns a vector (one-dimensional array) whose elements are the arguments given.
This is the primitive function for making arrays. dimensions should be a list of fixnums which are the dimensions of the array; the length of the list is the rank of the array. For convenience you can specify a single fixnum rather than a list of one fixnum, when making a one-dimensional array.
options are alternating keywords and values. The keywords may be any of the following:
:area
The value specifies in which area (see area) the array should be created.
It should be either an area number (a fixnum), or nil
to mean the
default area.
:type
The value should be a symbolic name of an array type; the most
common of these is art-q
, which is the default. The elements of the array are
initialized according to the type: if the array is of a type whose
elements may only be fixnums or floats, then every element of the array is
initially 0 or 0.0; otherwise, every element is initially
nil
. See the description of array types on array-type.
The value of the option may also be the value of a symbol which is an array type name
(that is, an internal numeric array type code).
:element-type
element-type is the Common Lisp way to control the type of array made.
Its value is a Common Lisp type specifier (see type-specifiers).
The array type used is the most specialized which can allow as an element
anything which fits the type specifier. For example,
if element-type is (mod 4)
, you get an art-2b
array.
If element-type is (mod 3)
, you still get an art-2b
array,
that being the most restrictive which can store the numbers 0, 1 and 2.
If element-type
is string-char
, you get a string.
:initial-value
:initial-element make-array
Specifies the value to be stored in each element of the new
array. If it is not specified, it is nil
for arrays that can
hold arbitrary objects, or 0 or 0.0 for numeric arrays.
:initial-value
is obsolete.
:initial-contents
Specifies the entire contents for the new array, as a sequence of
sequences of sequences... Array element 1 3 4 of a three-dimensional
array would be (elt (elt (elt initial-contents 1) 3) 4)
. Recall
that a sequence is either a list or a vector, and vectors include
strings.
:displaced-to
If this is not nil
, a displaced array is constructed.
If the value is a fixnum or a locative, make-array
creates a
regular displaced array which refers to the specified section of virtual
address space.
If the value is an array, make-array
creates
an indirect array (see indirect-array).
:leader-length
The value should be a fixnum. The array is made with a leader
containing that many elements. The elements of the leader are
initialized to nil
unless the :leader-list
option is given (see
below).
:leader-list
The value should be a list. Call the number of elements in the list n.
The first n elements of the leader are initialized from successive
elements of this list. If the :leader-length
option is not specified,
then the length of the leader is n. If the :leader-length
option is given, and its value is greater than n, then the nth
and following leader elements are initialized to nil
. If its value
is less than n, an error is signaled. The leader elements are
filled in forward order; that is, the car of the list is stored
in leader element 0, the cadr in element 1, and so on.
:fill-pointer
The value should be a fixnum. The array is made with a leader containing at least one element, and this fixnum is used to initialize that first element.
Using the :fill-pointer
option is equivalent to using
:leader-list
with a list one element long. It avoids consing the list,
and is also compatible with Common Lisp.
:displaced-index-offset
If this is present, the value of the :displaced-to
option should be an
array, and the value should be a non-negative fixnum; it is made to be the
index-offset of the created indirect array. (See index-offset.)
:named-structure-symbol
If this is not nil
, it is a symbol to
be stored in the named-structure cell of the array. The array
made is tagged as a named structure (see named-structure.) If
the array has a leader, then this symbol is stored in leader element
1 regardless of the value of the :leader-list
option. If the array
does not have a leader, then this symbol is stored in array element zero.
Array leader slot 1, or array element 0, cannot be used for anything
else in a named structure.
:adjustable-p
In strict Common Lisp, a non-nil
value for this keyword makes the
array adjustable, which means that it is permissible to change the
array’s size with adjust-array
(adjust-array-fun). This is
because other Lisp systems have multiple representations for arrays, one
which is simple and fast to access, and another which can be adjusted.
The Lisp Machine does not require two representations: any array’s size
may be changed, and this keyword is ignored.
Examples:
;; Create a one-dimensional array of five elements.
(make-array 5)
;; Create a two-dimensional array,
;; three by four, with four-bit elements.
(make-array '(3 4) :type 'art-4b)
;; Create an array with a three-element leader.
(make-array 5 :leader-length 3)
;; Create an array containing 5 t
’s,
;; and a fill pointer saying the array is full.
(make-array 5 :initial-value t :fill-pointer 5)
;; Create a named-structure with five leader
;; elements, initializing some of them.
(setq b (make-array 20 :leader-length 5
:leader-list '(0 nil foo)
:named-structure-symbol 'bar))
(array-leader b 0) => 0
(array-leader b 1) => bar
(array-leader b 2) => foo
(array-leader b 3) => nil
(array-leader b 4) => nil
make-array
returns the newly-created array, and also
returns, as a second value, the number of words allocated in the process
of creating the array, i.e the %structure-total-size
of the array.
When make-array
was originally implemented, it took its arguments
in the following fixed pattern:
(make-array area type dimensions &optional displaced-to leader displaced-index-offset named-structure-symbol)
leader was a combination of the :leader-length
and :leader-list
options, and the list was in reverse order.
This obsolete form is still supported so that old programs will continue
to work, but the new keyword-argument form is preferred.
Returns the element of array selected by the subscripts. The subscripts must be fixnums and their number must match the rank of array.
The Common Lisp version of aref
differs from the traditional one in
that it returns a character object rather than an integer when array
is a string. See chapter string-chapter for a discussion of the data
type of string elements.
Stores x into the element of array selected by the subscripts. The subscripts must be fixnums and their number must match the rank of array. The returned value is x.
aset
is equivalent to
(setf (aref array subscripts...) x)
Returns a locative pointer to the element-cell of array selected by the subscripts. The subscripts must be fixnums and their number must match the rank of array. The array must not be a numeric array, since locatives to the middle of a numeric array are not allowed. See the explanation of locatives in locative.
It is equivalent, and preferable, to write
(locf (aref array subscripts...))
These functions access an array with a single subscript regardless of
how many dimensions the array has. They may be useful for manipulating
arrays of varying rank, as an alternative to maintaining and updating
lists of subscripts or to creating one-dimensional indirect arrays.
ar-1-force
refers to an element,
as-1-force
sets an element, and ap-1-force
returns a locative
to the element’s cell.
In using these functions, you must pay attention to the order in which the array elements are actually stored. See array-element-order-section.
Calculates the cumulative index in array of the element at indices indices.
(ar-1-force array (array-row-major-index array indices...))
is equivalent to (aref array indices...)
.
array should be an array with a leader, and i should be a
fixnum. This returns the ith element of array’s leader.
This is analogous to aref
.
array should be an array with a leader, and i should be a
fixnum. x may be any object. x is stored in the ith element
of array’s leader. store-array-leader
returns x.
This is analogous to aset
.
It is equivalent, and preferable, to write
(setf (array-leader array i) x)
Is equivalent to
(locf (array-leader array i))
The following array accessing functions generally need not be used by users.
These are obsolete versions of aref
, aset
and aloc
that
only work for one-, two-, or three-dimensional arrays, respectively.
The compiler turns aref
into ar-1
, ar-2
, etc according to
the number of subscripts specified, turns aset
into as-1
,
as-2
, etc., and turns aloc
into ap-1
, ap-2
, etc. For
arrays with more than three dimensions the compiler uses the slightly
less efficient form since the special routines only exist for one, two
and three dimensions. There is no reason for any program to call
ar-1
, as-1
, ar-2
, etc explicitly; they are documented
because there used to be such a reason, and many old programs use these
functions. New programs should use aref
, aset
, and aloc
.
A related function, provided only for Maclisp compatibility, is
arraycall
(arraycall-fun).
A special accessing function defined by Common Lisp to work only on
simple general vectors: vectors with no fill pointer, not displaced, and
not adjustable (see adjustable-array). Some other Lisp systems open
code svref
so that it is faster than aref
, but on the Lisp
Machine svref
is a synonym for cli:aref
.
Special accessing functions defined to work only on bit vectors, only on
simple bit vectors, only on strings, and only on simple strings, respectively.
On the Lisp Machine they are all synonyms for cli:aref
.
Here are the conditions signaled for various errors in accessing arrays.
sys:array-has-no-leader
: (sys:bad-array-mixin
error
) ¶This is signaled on a reference to the leader of an array that doesn’t
have one. The condition instance supports the :array
operation,
which returns the array that was used.
The :new-array
proceed-type is provided.
: sys:bad-array-mixin ¶This mixin is used in the conditions signaled by several kinds of
problems pertaining to arrays. It defines prompting for the
:new-array
proceed type.
sys:array-wrong-number-of-dimensions
: (sys:bad-array-mixin
error
) ¶This is signaled when an array is referenced (either reading or writing)
with the wrong number of subscripts; for example, (aref "foo" 1 2)
.
The :array
operation on the condition instance returns the array
that was used. The :subscripts-used
operation returns the
list of subscripts used.
The :new-array
proceed type is provided. It expects one argument,
an array to use instead of the original one.
sys:subscript-out-of-bounds
: (error
) ¶This is signaled when there are the right number of subscripts but their
values specify an element that falls outside the bounds of the array.
The same condition is used by sys:%instance-ref
, etc., when the
index is out of bounds in the instance.
The condition instance supports the operations :object
and
:subscripts-used
, which return the array or instance and the list of
subscripts.
The :new-subscript
proceed type is provided. It takes an
appropriate number of subscripts as arguments. You should provide as
many subscripts as there originally were.
sys:number-array-not-allowed
: (sys:bad-array-mixin
error
) ¶This is signaled by an attempt to use aloc
on a numeric array
such as an art-1b
array or a string.
The :array
operation and the :new-array
proceed type are available.
Returns the symbolic type of array.
Example:
(setq a (make-array '(3 5))) (array-type a) => art-q
Returns a type specifier which describes what elements could be stored in
array (see type-specifiers for more about type specifiers). Thus, if
array is a string, the value is string-char
. If array is an
art-1b
array, the value is bit
. If array is an art-2b
array, the value is (mod 4)
. If array is an art-q
array,
the value is t
(the type which all objects belong to).
array may be any array. This returns the total number
of elements in array. For a one-dimensional array,
this is one greater than the maximum allowable subscript.
(But if fill pointers are being used, you may want to use
array-active-length
.)
Example:
(array-length (make-array 3)) => 3 (array-length (make-array '(3 5))) => 15
array-total-size
is the Common Lisp name of this function.
If array does not have a fill pointer, then this returns whatever
(array-length array)
would have. If array does have a
fill pointer, array-active-length
returns it. See the general
explanation of the use of fill pointers on fill-pointer.
Returns the number of dimensions of array.
Example:
(array-rank (make-array '(3 5))) => 2
Returns the length of dimension n of array. Examples:
(setq a (make-array '(2 3))) (array-dimension a 0) => 2 (array-dimension a 1) => 3
array may be any kind of array, and n should be a fixnum.
If n is between 1 and the rank of array,
this returns the nth dimension of array. If n is 0,
this returns the length of the leader of array; if array has no
leader it returns nil
. If n is any other value, this
returns nil
.
This function is obsolete; use array-dimension-n
,
whose calling sequence is cleaner.
Examples:
(setq a (make-array '(3 5) :leader-length 7)) (array-dimension-n 1 a) => 3 (array-dimension-n 2 a) => 5 (array-dimension-n 3 a) => nil (array-dimension-n 0 a) => 7
Returns a list whose elements are the dimensions of array.
Example:
(setq a (make-array '(3 5))) (array-dimensions a) => (3 5)
Note: the list returned by (array-dimensions x)
is
equal to the cdr of the list returned by (arraydims x)
.
Returns a list whose first element is the symbolic name of the type of array, and whose remaining elements are its dimensions. array may be any array; it also may be a symbol whose function cell contains an array, for Maclisp compatibility (see maclisp-array).
Example:
(setq a (make-array '(3 5))) (arraydims a) => (art-q 3 5)
arraydims
is for Maclisp compatibility only.
t
if subscripts is a legal
set of subscripts for array, otherwise nil
.
t
if array is any kind of displaced array
(including an indirect array), otherwise nil
.
array may be any kind of array.
t
if array is an indirect array, otherwise nil
.
array may be any kind of array.
t
if array is an indirect array with an index-offset,
otherwise nil
.
array may be any kind of array.
Returns the index offset of array if it is an indirect
array which has an index offset. Otherwise it returns nil
.
array may be any kind of array.
t
if array has a fill pointer. It must have a leader and leader
element 0 must be an integer. While array leaders are not standard
Common Lisp, fill pointers are, and so is this function.
t
if array has a leader, otherwise nil
.
Returns the length of array’s leader if it has one, or nil
if it
does not.
According to Common Lisp, returns t
if array’s size may be
adjusted with adjust-array
(see below). On the Lisp Machine,
this function always returns t
.
Modifies various aspects of an array. array is modified in place if that is possible;
otherwise, a new array is created and array is forwarded to it. In either case,
array is returned. The arguments have the same names as arguments
to make-array
, and signify approximately the same thing. However:
element-type is just an error check. adjust-array
cannot change
the array type. If the array type of array is not what
element-type would imply, you get an error.
If displaced-to is specified, the new array is displaced as specified by displaced-to and displaced-index-offset. If array itself was already displaced, it is modified in place provided that either array used to have an index offset and is supposed to continue to have one, or array had no index offset and is not supposed to have one.
Otherwise, if initial-contents was specified, it is used to set all the contents of the array. The old contents of array are irrelevant.
Otherwise, each element of array is copied forward into the new array
to the slot with the same indices, if there is one. Any new slots whose
indices were out of range in array are initialized to
initial-element, or to nil
or 0 if initial-element was not
specified.
fill-pointer, if specified, is used to set the fill pointer of the array. Aside from this, the result has a leader with the same contents as the original array.
adjust-array
is the only function in this section which is standard
Common Lisp. According to Common Lisp, an array’s dimensions can be
adjusted only if the :adjustable
option was specified to
make-array
with a non-nil
value when the array was created
(see adjustable-array). The Lisp Machine does not distinguish
adjustable and nonadjustable arrays; any array may be adjusted.
If array is a one-dimensional array, its size is
changed to be new-size. If array has more than one
dimension, its size (array-length
) is changed to new-size
by changing only the last dimension.
If array is made smaller, the extra elements are lost; if array
is made bigger, the new elements are initialized in the same fashion as
make-array
(see make-array-fun) would initialize them: either to nil
or 0,
depending on the type of array.
Example:
(setq a (make-array 5))
(aset 'foo a 4)
(aref a 4) => foo
(adjust-array-size a 2)
(aref a 4) => an error occurs
If the size of the array is being increased,
adjust-array-size
may have to allocate a new array somewhere. In
that case, it alters array so that references to it will be made to
the new array instead, by means of invisible pointers (see
structure-forward
, structure-forward-fun).
adjust-array-size
returns the new array if it creates one, and
otherwise it returns array. Be careful to be consistent about
using the returned result of adjust-array-size
, because you may end
up holding two arrays which are not the same (i.e not eq
), but
which share the same contents.
Equivalent to (adjust-array array dimensions)
.
This name is obsolete.
Changes an indirect array array’s type, size, or target pointed at. type specifies the new array type, dimlist its new dimensions, displaced-p the target it should point to (an array, locative or fixnum), and index-offset the new offset in the new target.
array is returned.
These functions manipulate art-q-list
arrays, which were
introduced on art-q-list-var.
array should be an art-q-list
array. This returns
a list which shares the storage of array.
Example:
(setq a (make-array 4 :type 'art-q-list)) (aref a 0) => nil (setq b (g-l-p a)) => (nil nil nil nil) (rplaca b t) b => (t nil nil nil) (aref a 0) => t (aset 30 a 2) b => (t nil 30 nil)
g-l-p
stands for ‘get list pointer’.
The following two functions work strangely, in the same way that store
does, and should not be used in new programs.
The argument array-ref is ignored, but should be a reference
to an art-q-list
array by applying the array to subscripts (rather
than by aref
). This returns a list object which
is a portion of the “list” of the array, beginning with the last
element of the last array which has been called as a function.
get-locative-pointer-into-array
is
similar to get-list-pointer-into-array
, except that it returns a
locative, and doesn’t require the array to be art-q-list
.
Use locf
of aref
in new programs.
array must be a one-dimensional array which has a fill pointer and x may
be any object. vector-push
attempts to store x in the element
of the array designated by the fill pointer, and increase the fill pointer
by one. If the fill pointer does not designate an element of the array (specifically,
when it gets too big), it is unaffected and vector-push
returns nil
;
otherwise, the two actions (storing and incrementing) happen uninterruptibly,
and vector-push
returns the former value of the fill pointer,
i.e the array index in which it stored x. If the array is of type
art-q-list
, an operation similar to nconc
has taken place,
in that the element has been added to the list by changing the cdr of
the formerly last element. The cdr-coding is updated to ensure this.
array-push
is an old name for this function. vector-push
is
preferable because it takes arguments in an order like push
.
vector-push-extend
is just like vector-push
except
that if the fill pointer gets too large, the array grows
to fit the new element; it never “fails” the way vector-push
does,
and so never returns nil
. extension is the number of
elements to be added to the array if it needs to grow. It defaults
to something reasonable, based on the size of the array.
array-push-extend
differs only in the order of arguments,
array must be a one-dimensional array which has a fill pointer.
The fill pointer is decreased by one and the array element
designated by the new value of the fill pointer is returned.
If the new value does not designate any element of the array
(specifically, if it had already reached zero), an error is caused.
The two operations (decrementing and array referencing) happen
uninterruptibly. If the array is of type art-q-list
, an operation
similar to nbutlast
has taken place. The cdr-coding is
updated to ensure this.
The two names are synonymous.
sys:fill-pointer-not-fixnum
: (sys:bad-array-mixin
error
) ¶This is signaled when one of the functions in this section is used with an array whose leader element zero is not a fixnum. Most other array accessing operations simply assume that the array has no fill pointer in such a case, but these cannot be performed without a fill pointer.
The :array
operation on the condition instance returns the array
that was used. The :new-array
proceed type is supported, with one
argument, an array.
The new functions replace
(replace-fun)
and fill
(fill-fun) are useful ways to
copy parts of arrays.
Stores value into all or part of array. start and end are optional indices which delimit the part of array to be initialized. They default to the beginning and end of the array.
This function is by far the fastest way to do the job.
array may be any type of array, or, for Maclisp
compatibility, a symbol whose function cell contains an array. It can
also be nil
, in which case an array of type art-q
is created.
There are two forms of this function, depending on the type of x.
If x is a list, then fillarray
fills up array with
the elements of list. If x is too short to fill up all of
array, then the last element of x is used to fill the
remaining elements of array. If x is too long, the extra
elements are ignored. If x is nil
(the empty list), array
is filled with the default initial value for its array type (nil
or 0).
If x is an array (or, for Maclisp compatibility, a symbol
whose function cell contains an array), then the elements of array are
filled up from the elements of x. If x is too small, then
the extra elements of array are not affected.
If array is multi-dimensional, the elements are accessed
in row-major order: the last subscript varies the most quickly.
The same is true of x if it is an array.
fillarray
returns array; or, if array was
nil
, the newly created array.
array may be any type of array, or, for Maclisp
compatibility, a symbol whose function cell contains an array.
listarray
creates and returns a list whose elements are those of
array. If limit is present, it should be a fixnum, and only
the first limit (if there are more than that many) elements of
array are used, and so the maximum length of the returned list is
limit.
If array is multi-dimensional, the elements are accessed
in row-major order: the last subscript varies the most quickly.
array may be any type of array, or, for Maclisp
compatibility, a symbol whose function cell contains an array.
list-array-leader
creates and returns a list whose elements are those of
array’s leader. If limit is present, it should be a fixnum, and only
the first limit (if there are more than that many) elements of
array’s leader are used, and so the maximum length of the returned list is
limit. If array has no leader, nil
is returned.
from and to must be arrays. The contents of from
is copied into the contents of to, element by element.
If to is shorter than from,
the rest of from is ignored. If from is shorter than
to, the rest of to is filled with nil
, 0 or 0.0
according to the type of array.
This function always returns t
.
The entire length of from or to is used, ignoring the fill pointers if any. The leader itself is not copied.
copy-array-contents
works on multi-dimensional arrays. from and
to are linearized subscripts, and elements are taken in row-major
order.
Like copy-array-contents
, but also copies the leader of from
(if any) into to.
The portion of the array from-array with indices greater than or
equal to from-start and less than from-end is copied into
the portion of the array to-array with indices greater than or
equal to to-start and less than to-end, element by element.
If there are more elements in the selected portion of to-array
than in the selected portion of from-array, the extra elements
are filled with the default value as by copy-array-contents
.
If there are more elements in the selected portion of from-array,
the extra ones are ignored. Multi-dimensional arrays are treated
the same way as copy-array-contents
treats them.
This function always returns t
.
%blt
and %blt-typed
(%blt-fun) are often useful for copying
parts of arrays. They can be used to shift a part of an array either up
or down.
These functions perform bitwise boolean operations on the elements of arrays.
Perform boolean operations element by element on bit arrays. The
arguments must match in their size and shape, and all of their elements
must be integers. Corresponding elements of bit-array-1 and
bit-array-2 are taken and passed to one of logand
, logior
,
etc to get an element of the result array.
If the third argument is non-nil
, the result bits are stored into it,
modifying it destructively. If it is t
, the results are stored in
bit-array-1. Otherwise a new array of the same type as
bit-array-1 is created and used for the result. In any case, the
value returned is the array where the results are stored.
These functions were introduced for the sake of Common Lisp, which
defines them only when all arguments are specialized arrays that hold
only zero or one. In the Lisp machine, they accept not only such arrays
(art-1b
arrays) but any arrays whose elements are integers.
Performs lognot
on each element of bit-array to get an element of
the result. If result-bit-array is non-nil
, the result elements
are stored in that; it must match bit-array in size and shape.
Otherwise, a new array of the same type as bit-array is created and
used to hold the result. The value of bit-not
is the array where the
results are stored.
from-array and to-array must be two-dimensional arrays
of bits or bytes (art-1b
, art-2b
, art-4b
, art-8b
,
art-16b
, or art-32b
). bitblt
copies a rectangular portion of from-array
into a rectangular portion of to-array. The value stored
can be a Boolean function of the new value and the value already there,
under the control of alu (see below). This function is most commonly used
in connection with raster images for TV displays.
The top-left corner of the source rectangle is (ar-2-reverse
from-array from-x from-y)
. The top-left corner of the
destination rectangle is (ar-2-reverse to-array to-x
to-y)
. width and height are the dimensions of both
rectangles. If width or height is zero, bitblt
does
nothing. The x coordinates and width are used as the second
dimension of the array, since the horizontal index is the one which
varies fastest in the screen buffer memory and the array’s last index
varies fastest in row-major order.
from-array and to-array are allowed to be the same array.
bitblt
normally traverses the arrays in increasing order of x
and y subscripts. If width is negative, then (abs width)
is used as the width, but the processing of the x direction is done
backwards, starting with the highest value of x and working down.
If height is negative it is treated analogously. When
bitblt
’ing an array to itself, when the two rectangles overlap, it
may be necessary to work backwards to achieve effects such
as shifting the entire array downwards by a certain number of rows. Note
that negativity of width or height does not affect the
(x, y) coordinates specified by the arguments, which are still the
top-left corner even if bitblt
starts at some other corner.
If the two arrays are of different types, bitblt
works bit-wise
and not element-wise. That is, if you bitblt
from an art-2b
array into an art-4b
array, then two elements of the from-array
correspond to one element of the to-array.
If bitblt
goes outside the bounds of the source array, it wraps
around. This allows such operations as the replication of a small
stipple pattern through a large array. If bitblt
goes outside
the bounds of the destination array, it signals an error.
If src is an element of the source rectangle, and dst
is the corresponding element of the destination rectangle, then
bitblt
changes the value of dst to
(boole alu src dst)
. See the boole
function (boole-fun). There are symbolic names for some of the
most useful alu functions; they are tv:alu-seta
(plain
copy), tv:alu-ior
(inclusive or), tv:alu-xor
(exclusive
or), and tv:alu-andca
(and with complement of source).
bitblt
is written in highly-optimized microcode and goes very much
faster than the same thing written with ordinary aref
and aset
operations would. Unfortunately this causes bitblt
to have a couple
of strange restrictions. Wrap-around does not work correctly if
from-array is an indirect array with an index-offset. bitblt
signals an error if the second dimensions of from-array
and to-array are not both integral multiples of the machine word
length. For art-1b
arrays, the second dimension must be a multiple
of 32., for art-2b
arrays it must be a multiple of 16, etc.
Currently, multi-dimensional arrays are stored in row-major order, as in Maclisp., and as specified by Common Lisp. This means that successive memory locations differ in the last subscript. In older versions of the system, arrays were stored in column-major order.
Most user code has no need to know about which order array elements are
stored in. There are three known reasons to care: use of
multidimensional indirect arrays; paging efficiency
(if you want to reference every element in a
multi-dimensional array and move linearly through memory to improve
locality of reference, you must vary the last subscript fastest
in row-major order);
and access to the TV screen or to arrays of pixels copied to or from the
screen with bitblt
. The latter is the most important one.
The bits on the screen are actually stored in rows, which means that the dimension that varies fastest has to be the horizontal position. As a result, if arrays are stored in row-major order, the horizontal position must be the second subscript, but if arrays are stored in column-major order, the horizontal position must be the first subscript. To ease the conversion of code that uses arrays of pixels, several bridging functions are provided:
This is like make-array
except that the dimensions of the array are
width and height, in whichever order is correct. width is
used as the dimension in the subscript that varies fastest in memory,
and height as the other dimension. options are passed along to
make-array
to specify everything but the size of the array.
Returns the extent of array, a two-dimensional array, in the dimension that varies faster through memory. For a screen array, this is always the width.
Returns the extent of array, a two-dimensional array, in the dimension that varies slower through memory. For a screen array, this is always the height.
Returns the element of array at horizontal-index and vertical-index. horizontal-index is used as the subscript in whichever dimension varies faster through memory.
Stores newvalue into the element of array at horizontal-index and vertical-index. horizontal-index is used as the subscript in whichever dimension varies faster through memory.
Code that was written before the change in order of array indices can be
converted by replacing calls to make-array
, array-dimension
,
aref
and aset
with these functions. It can then work either in
old systems or in new ones. In more complicated circumstances, you can
facilitate conversion by writing code which tests this variable.
This is t
in more recent system versions which store arrays in
row-major order (last subscript varies fastest). It is nil
in older
system versions which store arrays in column-major order.
The functions in this section perform some useful matrix operations.
The matrices are represented as two-dimensional Lisp arrays. These
functions are part of the mathematics package rather than the kernel
array system, hence the ‘math:
’ in the names.
Multiplies matrix-1 by matrix-2. If matrix-3 is supplied,
multiply-matrices
stores the results into matrix-3 and returns
matrix-3, which should be of exactly the right dimensions for
containing the result of the multiplication; otherwise it creates an
array to contain the answer and returns that. All matrices must be
either one- or two-dimensional arrays, and the first dimension of
matrix-2 must equal the second dimension of matrix-1.
Computes the inverse of matrix. If into-matrix is supplied,
stores the result into it and returns it; otherwise it creates an array
to hold the result and returns that. matrix must be two-dimensional
and square. The Gauss-Jordan algorithm with partial pivoting is used.
Note: if you want to solve a set of simultaneous equations, you should
not use this function; use math:decompose
and math:solve
(see
below).
Transposes matrix. If into-matrix is supplied, stores the result into it and returns it; otherwise it creates an array to hold the result and returns that. matrix must be a two-dimensional array. into-matrix, if provided, must be two-dimensional and have exactly the right dimensions to hold the transpose of matrix.
Returns the determinant of matrix. matrix must be a two-dimensional square matrix.
The next two functions are used to solve sets of simultaneous linear
equations. math:decompose
takes a matrix holding the coefficients of the
equations and produces the LU decomposition; this decomposition can then
be passed to math:solve
along with a vector of right-hand sides
to get the values of the variables. If you want to solve the same
equations for many different sets of right-hand side values, you only need to call
math:decompose
once. In terms of the argument names used below, these
two functions exist to solve the vector equation A x = b
for x. A is a matrix. b and x are vectors.
Computes the LU decomposition of matrix a. If lu is non-nil
,
stores the result into it and returns it; otherwise it creates an array
to hold the result, and returns that. The lower triangle of lu, with
ones added along the diagonal, is L, and the upper triangle of lu is
U, such that the product of L and U is a. Gaussian elimination with
partial pivoting is used. The lu array is permuted by rows according
to the permutation array ps, which is also produced by this function;
if the argument ps is supplied, the permutation array is stored into it;
otherwise, an array is created to hold it. This function returns two values,
the LU decomposition and the permutation array.
This function takes the LU decomposition and associated permutation
array produced by math:decompose
and solves the set of simultaneous
equations defined by the original matrix a given to math:decompose
and the right-hand sides in the vector b. If x is supplied, the solutions
are stored into it and it is returned; otherwise an array is
created to hold the solutions and that is returned. b must
be a one-dimensional array.
Returns a list of lists containing the values in array, which must be a two-dimensional array. There is one element for each row; each element is a list of the values in that row.
This is the opposite of math:list-2d-array
. list should be a
list of lists, with each element being a list corresponding to a row.
array’s elements are stored from the list. Unlike fillarray
(see fillarray-fun), if list is not long enough,
math:fill-2d-array
“wraps around”, starting over at the beginning.
The lists which are elements of list also work this way.
math:singular-matrix
: (sys:arithmetic-error
error
) ¶This is signaled when any of the matrix manipulation functions in this
section has trouble because of a singular matrix. (In some functions,
such as math:determinant
, a singular matrix is not a problem.)
The :matrix
operation on the condition instance returns the matrix
which is singular.
A plane is effectively an array whose bounds, in each dimension, are plus-infinity and minus-infinity; all integers are legal as indices. Planes may be of any rank. When you create a plane, you do not need to specify any size, just the rank. You also specify a default value. At that moment, every component of the plane has that value. As you can’t ever change more than a finite number of components, only a finite region of the plane need actually be stored. When you refer to an element for which space has not actually been allocated, you just get the default value.
The regular array accessing functions don’t work on planes.
You can use make-plane
to create a plane,
plane-aref
or plane-ref
to get the value of a component, and
plane-aset
or plane-store
to store into a component.
array-rank
works on planes.
A plane is actually stored as an array with a leader.
The array corresponds to a rectangular, aligned region of the plane,
containing all the components in which a plane-store
has been done
(and, usually, others which have never been altered).
The lowest-coordinate corner of that rectangular region is
given by the plane-origin
in the array leader.
The highest-coordinate corner can be found by adding the plane-origin
to the array-dimensions
of the array.
The plane-default
is the contents of all the
elements of the plane that are not actually stored in the array.
The plane-extension
is the amount to extend a plane by in any direction
when the plane needs to be extended. The default is 32.
If you never use any negative indices, then the plane-origin
remains
all zeroes and you can use regular array functions, such as aref
and aset
,
to access the portion of the plane that is actually stored. This can be
useful to speed up certain algorithms. In this case you can even use the
bitblt
function on a two-dimensional plane of bits or bytes,
provided you don’t change the plane-extension
to a number that is not
a multiple of 32.
Creates and returns a plane. rank is the number of dimensions. The keyword arguments are
The array type symbol (e.g art-1b
) specifying the type of the array
out of which the plane is made.
The default component value as explained above.
The amount by which to extend the plane, as explained above.
nil
or a list of integers whose length is rank. If not nil
,
each element corresponds to one dimension, specifying the width to
allocate the array initially in that dimension.
nil
or a list of integers whose length is rank. If not nil
,
each element corresponds to one dimension, specifying the smallest index
in that dimension for which storage should initially be allocated.
Example:
(make-plane 2 :type 'art-4b :default-value 3)
creates a two-dimensional plane of type art-4b
, with default value 3
.
A list of numbers, giving the lowest coordinate values actually stored.
This is the contents of the infinite number of plane elements that are not actually stored.
The amount to extend the plane by, in any direction, when plane-store
is done
outside of the currently-stored portion.
These two functions return the contents of a specified element of a plane.
They differ only in the way they take their arguments; plane-aref
wants
the subscripts as arguments, while plane-ref
wants a list of subscripts.
These two functions store datum into the specified element of a plane,
extending it if necessary, and return datum.
They differ only in the way they take their arguments; plane-aset
wants
the subscripts as arguments, while plane-store
wants a list of subscripts.
The functions in this section are provided only for Maclisp compatibility and should not be used in new programs.
Fixnum arrays do not exist (however, see Zetalisp’s
small-positive-integer arrays). Float arrays exist but you do not use
them in the same way; no declarations are required or allowed.
Un-garbage-collected arrays do not exist.
Readtables and obarrays are represented as arrays, but Zetalisp does not
use special array types for them. See the descriptions of read
(read-fun) and intern
(intern-fun) for information about
readtables and obarrays (packages). There are no ‘dead” arrays, nor are
Multics “external” arrays provided.
The arraycall
function exists for compatibility
but should not be used (see aref
, aref-fun.)
Subscripts are always checked for validity, regardless of the value
of *rset
and whether the code is compiled or not.
However, in a multi-dimensional array, an error is caused only
if the subscripts would have resulted in a reference to storage
outside of the array. For example, if you have a 2 by 7 array and refer
to an element with subscripts 3 and 1, no error occurs
despite the fact that the reference is invalid;
but if you refer to element 1 by 100, an error occurs.
In other words, subscript errors are caught if and only if
they refer to storage outside the array; some errors are undetected,
but they can only clobber (alter randomly) some other element of the same array,
not something completely unpredictable.
loadarrays
and dumparrays
are not provided. However,
arrays can be put into QFASL files; see fasdump.
The *rearray
function is not provided, since not all
of its functionality is available in Zetalisp.
Its most common uses are implemented by adjust-array-size
.
In Maclisp, arrays are usually kept on the array
property
of symbols, and the symbols are used instead of the arrays. In order
to provide some degree of compatibility for this manner of using
arrays, the array
, *array
, and store
functions are
provided, and when arrays are applied to arguments, the arguments are
treated as subscripts and apply
returns the corresponding element
of the array.
Creates an art-q
type array in default-array-area
with the given dimensions. (That is, dims is given
to make-array
as its first argument.) type is ignored.
If symbol is nil
, the array is returned; otherwise,
the array is put in the function cell of symbol, and symbol
is returned.
Is like array
, except that all of the arguments
are evaluated.
Stores x into the
specified array element. array-ref should be a form which
references an array by calling it as a function (aref
forms are not
acceptable). First x is evaluated, then array-ref is
evaluated, and then the value of x is stored into the array cell
last referenced by a function call, presumably the one in array-ref.
This is just like store
, but it is not
a special form; this is because the arguments are in the other
order. This function only exists for the compiler to compile the
store
special form into, and should never be used by programs.
(arraycall t array sub1 sub2...)
is the same
as (aref array sub1 sub2...)
. It exists for
Maclisp compatibility.
The type specifier sequence
is defined to include lists and vectors
(arrays of rank one).
Lists and vectors are similar in that both can
be regarded as sequences of elements: there is a first element, a second
element, and so on. Element n of a list is (nth n
list)
, and element n of a vector is (aref vector
n)
. Many useful operations which apply in principle to a sequence
of objects can work equally well on lists and vectors. These are the
generic sequence functions.
All the generic sequence functions accept nil
as a sequence of length zero.
Creates a sequence of type type, size elements long.
size must be an integer and type must be either list
or some kind of array type. type could be just array
or vector
to make
a general vector, it could be (vector (byte 8))
to make an art-8b
vector, and so on.
If initial-element is specified, each element of the new sequence
contains initial-element. Otherwise, the new sequence is initialized
to contain nil
if that is possible, zero otherwise (for numeric array types).
(make-sequence 'list 3) => (nil nil nil) (make-sequence 'array 5 :initial-element t) => #(t t t t t) (make-sequence '(vector bit) 5) => #*00000
Returns the element at index index in sequence.
If sequence is a list, this is (nth index sequence)
.
If sequence is a vector, this is (aref index sequence)
.
Being microcoded, elt
is as fast as either nth
or aref
.
(setf (elt sequence index) value)
is the way to set
an element of a sequence.
Returns the length of sequence, as an integer. For a vector with a fill
pointer, this is the fill pointer value. For a list, it is the traditional
Lisp function; note that lists ending with atoms other than nil
are
accepted, so that the length of (a b . c)
is 2.
Returns a new sequence of the same type, length and contents as sequence.
Returns a new sequence, of type result-type, whose contents
are made from the contents of all the sequences.
result-type can be list
or any array type,
just as in make-sequence
above. Examples:
(concatenate 'list '(1 2) '#(A 3)) => (1 2 A 3) (concatenate 'vector '(1 2) '#(A 3) => #(1 2 A 3)
Returns a new sequence whose elements are a subsequence of sequence. The new sequence is of the same type as sequence.
start is the index of the first element of sequence to take.
end is the index of where to stop–the first element not to take.
end can also be nil
, meaning take everything from start up
to the end of sequence.
Examples:
(subseq "Foobar" 3 5) => "ba" (subseq '(a b c) 1) => (b c)
It is also possible to setf
a call to subseq
. This means
to store into part of the sequence passed to subseq
. Thus,
(setf (subseq "Foobar" 3 5) "le")
modifies the string "Foobar"
so that it contains "Fooler"
instead.
0
) end1 (start2 0
) end2 ¶Copies part of from-sequence-2 into part of to-sequence-1. start2 and end2 are the indices of the part of from-sequence-2 to copy from, and start1 and end1 are the indices of the part of to-sequence-1 to copy into.
If the number of elements to copy out of from-sequence-2 is less than the number of elements of to-sequence-1 to be copied into, the extra elements of to-sequence-1 are not changed. If the number of elements to copy out is more than there is room for, the last extra elements are ignored.
If the two sequence arguments are the same sequence, then the elements to be copied are copied first into a temporary sequence (if necessary) to make sure that no element is overwritten before it is copied. Example:
(setq str "Elbow") (replace str str :start1 2 :end1 5 :start2 1 :end2 4)
modifies str
to contain "Ellbo"
.
into-sequence-1 is returned as the value of replace
.
0
) end ¶Modifies the contents of sequence by setting all the
elements to item. start and end may be specified
to limit the operation to some contiguous portion of sequence;
then the elements before start or after end are unchanged.
If end is nil
, the filling goes to the end of sequence.
The value returned by fill
is sequence. Example:
(setq l '(a b c d e)) (fill l 'lose :start 2) l => (a b lose lose lose)
Returns a new sequence containing the same elements as sequence but
in reverse order. The new sequence is of the same type and length as
sequence.
reverse
does not modify its argument, unlike nreverse
which is faster
but does modify its argument. The list created by reverse
is not cdr-coded.
(reverse "foo") => "oof" (reverse '(a b (c d) e)) => (e (c d) b a)
Modifies sequence destructively to have its elements in reverse
order, and returns sequence as modified. For a vector, this is done
by copying the elements to different positions. For a list, this is
done by modifying cdr pointers. This has two important consequences: it
is most efficient when the list is not cdr-coded, and the rearranged
list starts with the cell that used to be at the end. Although the
altered list as a whole contains the same cells as the original, the
actual value of the altered list is not eq
to the original list.
For this reason, one must always store the value of nreverse
into
the place where the list will be used. Do not just use nreverse
for effect
on a list.
(setq a '#(1 2 3 4 5)) (nreverse a) (concatenate 'list a) => (5 4 3 2 1) (setq b '(1 2 3 4 5) c b d (last b)) (setq b (nreverse b)) b => (5 4 3 2 1) c => (1) (eq b d) => t
nreverse
is most frequently used after a loop which computes
elements for a new list one by one. These elements can be put on the
new list with push
, but this produces a list which has the elements
in reverse order (first one generated at the end of the list).
(let (accumulate) (dolist (x input) (push (car x) accumulate) (push (cdr x) accumulate)) (nreverse accumulate))
Currently, nreverse
is inefficient with cdr-coded lists (see
cdr-code), because it just uses rplacd
in the
straightforward way. This may be fixed someday. In the meantime
reverse
might be preferable in some cases.
The Common Lisp map
function
maps function over successive elements of each sequence,
constructing and returning a sequence of the results that function returns.
The constructed sequence is of type result-type (see make-sequence
,
make-sequence-fun).
function is called first on the first elements of all the sequences, then on the second elements of all, and so on until some argument sequence is exhausted.
(map 'list 'list '(1 2 3) '#(A B C D)) => ((1 A) (2 B) (3 C)) (setq vect (map '(vector (mod 16.)) '+ '(3 4 5 6 7) (circular-list 1))) (concatenate 'list vect) => (2 3 4 5 6) (array-element-type vect) => (mod 16.)
result-type can also be nil
. Then the values returned by function
are thrown away, no sequence is constructed, and map
returns nil
.
This function is available under the name map
in Common Lisp programs.
In traditional Zetalisp programs, map
is another function which
does something related but different; see map-fun.
Traditional programs can call this function as cli:map
.
Applies predicate to successive elements of each sequence.
If predicate ever returns a non-nil
value, cli:some
immediately
returns the same value. If one of the argument sequences is exhausted,
cli:some
returns nil
.
Each time predicate is called, it receives one argument from each sequence. The first time, it gets the first element of each sequence, then the second element of each, and so on until a sequence is exhausted. Examples:
(cli:some 'plusp '(-4 0 5 6)) => 5 (cli:some '> '(-4 0 5 6) '(0 12 12 12)) => nil (cli:some '> '(-4 0 5 6) '(3 3 3 3)) => 5 (cli:some '> '(-4 0 5 6) '(3 3)) => nil
This function is available under the name some
in Common Lisp programs.
In traditional Zetalisp programs, some
is another function which
does something related but different; see some-fun.
Traditional programs can call this function as cli:some
.
Applies predicate to successive elements of each sequence.
If predicate ever returns nil
, cli:every
immediately
returns nil
. If one of the argument sequences is exhausted,
cli:every
returns t
.
Each time predicate is called, it receives one argument from each sequence. The first time, it gets the first element of each sequence, then the second element of each, and so on until a sequence is exhausted. Examples:
(cli:every 'plusp '(-4 0 5 6)) => nil (cli:every 'plusp '(5 6)) => t
This function is available under the name every
in Common Lisp programs.
In traditional Zetalisp programs, every
is another function which
does something related but different; see every-fun.
Traditional programs can call this function as cli:every
.
These are the opposites of cli:some
and cli:every
.
(notany ...)
is equivalent to (not (cli:some ...))
.
(notevery ...)
is equivalent to (not (cli:every ...))
.
0
) end initial-value ¶Combines the elements of sequence using function, a function of two args. function is applied to the first two elements; then to that result and the third element; then to that result and the fourth element; and so on.
start and end are indices that restrict the action to a part of sequence,
as if the rest of sequence were not there. They default to 0 and nil
(nil
for end means go all the way to the end of sequence).
If from-end is non-nil
, processing starts with the last of the
elements. function is first applied to the last two elements; then
to the previous element and that result; then to the previous element
and that result; and so on until element number start has been used.
If initial-value is specified, it acts like an extra element of
sequence, used in addition to the actual elements of the specified part
of sequence. It comes, in effect, at the beginning if from-end is
nil
, but at the end if from-end is non-nil
, so that in any
case it is the first element to be processed.
If there is only one element to be processed, that element is returned and function is not called.
If there are no elements (sequence is of length zero and no initial-value), function is called with no arguments and its value is returned.
Examples:
(reduce '+ '(1 2 3)) => 6
(reduce '- '(1 2 3)) => -4
(reduce '- '(1 2 3) :from-end t) => 2 ;; 1 -
(2 -
3)
(reduce 'cons '(1 2 3) :from-end t) => (1 2 . 3)
(reduce 'cons '(1 2 3)) => ((1 . 2) . 3)
The generic sequence functions for searching, substituting and removing elements from sequences take similar arguments whose meanings are standard. This is because they all look at each element of the sequence to decide whether it should be processed.
Functions which conceptually modify the sequence come in pairs. One
function in the pair copies the sequence if necessary and never modifies
the argument. The copy is a list if the original sequence is a list;
otherwise, the copy is an art-q
array. If the sequence is a list,
it may be copied only partially, sharing any unchanged tail with the
original argument. If no elements match, the result sequence may be
eq
to the argument sequence.
The other function in the pair may alter the original sequence and return it, or may make a copy and return that.
There are two ways the function can decide which elements to operate on.
The functions whose names end in -if
or -if-not
have an
argument named predicate which should be a function of one argument.
This function is applied to each element and the value determines
whether the element is processed.
The other functions have an argument named item or something similar
which is an object to compare each element with. The elements that
match item are processed. By default, the comparison is done with
eql
. You can specify any function of two arguments to be used
instead, as the test keyword argument. item is always the first
argument, and an element of the sequence is the second argument. The
element matches item if test returns non-nil
.
Alternatively, you can specify the test-not keyword argument; then
the element matches if test-not returns nil
.
The elements may be tested in any order, and may be tested more than once. For predictable results, your predicate, test and test-not functions should be side-effect free.
The five keyword arguments start, end, key, count and from-end have the same meanings for all of the functions, except that count is not relevant for some kinds of operations. Here is what they do:
start and end are indices in the sequence; they restrict the processing to the portion between those indices. Only elements in this portion are tested, replaced or removed. For the search functions, only this portion is searched. For element removal functions, elements outside the portion are unchanged.
start is the index of the first element to be processed, and end
is the index of the element after the last element to be processed.
end can also be nil
, meaning that processing should continue to
the end of the sequence.
start always defaults to 0, and end always defaults to nil
.
key, if not nil
, is a function of one argument which is applied
to each element of the sequence to get a value which is passed to the
test, test-not or predicate function in place of the
element. For example, if key is car
, the car of each element is
compared or tested. The default for key is nil
, which means to
compare or test the element itself.
If from-end is non-nil
, elements are (conceptually) processed in
the reverse of the sequence order, from the later elements to the
earlier ones. In some functions this argument makes no difference,
or matters only when count is non-nil
.
Note: the actual testing of elements may happen in any order.
count, if not nil
, should be an integer specifying the number of
matching elements to be processed. For example, if count is 2,
only the first two elements that match are removed, replaced, etc.
If from-end is non-nil
, the last two matching elements
are the ones removed or replaced.
The default for count is nil
, which means all elements are tested
and all matching ones are processed.
These functions remove certain elements of a sequence. The remove
series functions copy the argument; the delete
series functions
can modify it destructively (currently they always copy anyway if the
argument is a vector).
0
) end count key from-end ¶0
) end count key from-end ¶Returns a sequence like sequence but missing any elements that
satisfy predicate. predicate is a function of one argument
which is applied to one element at a time; if predicate returns
non-nil
, that element is removed. remove-if
copies structure as
necessary to avoid modifying sequence, while delete-if
can
either modify the original sequence and return it or make a copy and
return that. (Currently, a list is always modified, and a vector is
always copied, but don’t depend on this.)
The start, end, key count and from-end arguments are handled in the standard way.
(remove-if 'plusp '(1 -1 2 -2 3 -3)) => (-1 -2 -3) (remove-if 'plusp '(1 -1 2 -2 3 -3) :count 2) => (-1 -2 3 -3) (remove-if 'plusp '(1 -1 2 -2 3 -3) :count 2 :from-end t) => (1 -1 -2 -3) (remove-if 'plusp '(1 -1 2 -2 3 -3) :start 4) => (1 -1 2 -2 -3) (remove-if 'zerop '(1 -1 2 -2 3 -3) :key '1-) => (-1 2 -2 3 -3)
0
) end count key from-end ¶0
) end count key from-end ¶Like remove-if
and delete-if
except that the elements removed
are those for which predicate returns nil
.
'eql
) test-not (start 0
) end count key from-end ¶'eql
) test-not (start 0
) end count key from-end ¶The Common Lisp functions for eliminating elements from a sequence
test the elements of sequence one by one by comparison with item,
using the test or test-not function, and eliminate the elements
that match. cli:remove
copies structure as necessary to avoid modifying
sequence, while cli:delete
can either modify the original sequence
and return it or make a copy and return that. (Currently, a list is always
modified, and a vector is always copied.)
The start, end, key count and from-end arguments are handled in the standard way.
(cli:remove 'x '(x (a) (x) (a x))) => ((a) (x) (a x)) (cli:remove 'x '((a) (x) (a x)) :test 'memq) => ((a)) (cli:remove 'x '((a) (x) (a x)) :test-not 'memq) => ((x) (a x)) (cli:remove 'x '((a) (x) (a x)) :test 'memq :count 1) => ((a) (a x)) (cli:remove 'x '((a) (x) (a x)) :key 'car) => ((a) (a x))
These functions are available under the names remove
and delete
in Common Lisp programs. Traditional Zetalisp provides functions
remove
and delete
which serve similar functions, on lists only,
and with different calling sequences; see remove-fun and
delete-fun. Traditional programs can call these functions as
cli:remove
and cli:delete
.
'eql
) test-not (start 0
) end key from-end ¶'eql
) test-not (start 0
) end key from-end ¶remove-duplicates
returns a new sequence like sequence except
that all but one of any set of matching elements have been removed.
delete-duplicates
is the same except that it may destructively modify
and then return sequence itself.
Elements are compared using test, a function of two arguments.
Two elements match if test returns non-nil
. Each element
is compared with all the following elements and slated for removal if
it matches any of them.
If test-not is specified, it is used instead of test, but then
elements match if test-not returns nil
. If neither test nor test-not
is specified, eql
is used for test.
If key is non-nil
, it should be a function of one argument. key is
applied to each element, and the value key returns is passed to test
or test-not.
If from-end is non-nil
, then elements are processed
(conceptually) from the end of sequence forward. Each element is
compared with all the preceding ones and slated for removal if it
matches any of them. For a well-behaved comparison function, the only
difference from-end makes is which elements of a matching set
are removed. Normally the last one is kept; with from-end, it is
the first one that is kept.
If start or end is used to restrict processing to a portion of sequence, both removal and comparison are restricted. An element is removed only if it is itself within the specified portion, and matches another element within the specified portion.
The functions in this section substitute a new value for certain of the
elements in a sequence–those that match a specified object or satisfy a
predicate. For example, you could replace every t
in the sequence with
nil
, leaving all elements other than t
unchanged. The substitute
series functions make a copy and return it, leaving the original
sequence unmodified. The nsubstitute
series functions always alter
the original sequence destructively and return it. They do not use up
any storage.
Note the difference between these functions and the function
cli:subst
. subst
operates only on lists, and it searches all
levels of list structure in both car and cdr positions.
substitute
, when given a list, considers for replacement only the
elements of the list.
substitute-if
returns a new sequence like sequence but with
newitem substituted for each element of sequence that satisfies
predicate. sequence itself is unchanged. If it is a list, only
enough of it is copied to avoid changing sequence.
nsubstitute-if
replaces elements in sequence itself, modifying it
destructively, and returns sequence.
start, end, key, count and from-end are handled in the standard fashion as described above.
(substitute-if 0 'plusp '(1 -1 2 -2 3) :from-end t :count 2) => (1 -1 0 -2 0)
Like substitute-if
and nsubstitute-if
except that the elements
replaced are those for which predicate returns nil
.
'eql
) test-not start end count key from-end ¶'eql
) test-not start end count key from-end ¶Like substitute-if
and nsubstitute-if
except that elements are
tested by comparison with olditem, using test or test-not as
a comparison function.
start, end, key, count and from-end are handled in the standard fashion as described above.
(substitute 'a 'b '(a b (a b))) => (a a (a b))
The functions in this section find an element or elements of a sequence
which satisfy a predicate or match a specified object. The position
series functions find one element and return the index of the element
found in the specified sequence. The find
series functions return
the element itself. The count
series functions find all the
elements that match and returns the number of them that were found.
All of the functions accept the keyword arguments start, end, count and from-end, and handle them in the standard way described in generic-sequence-arguments.
0
) end key from-end ¶0
) end key from-end ¶Find the first element of sequence (last element, if from-end is
non-nil
) which satisfies predicate. position-if
returns the
index in sequence of the element found; find-if
returns the element
itself. If no element is found, the value is nil
for either
function.
See generic-sequence-arguments for a description of the standard arguments start, end and key. If start or end is used to restrict operation to a portion of sequence, elements outside the portion are not tested, but the index returned is still the index in the entire sequence.
(position-if 'plusp '(-3 -2 -1 0 1 2 3)) => 4 (find-if 'plusp '(-3 -2 -1 0 1 2 3)) => 1 (position-if 'plusp '(-3 -2 -1 0 1 2 3) :start 5) => 5 (position-if 'plusp '(-3 -2 -1 0 1 2 3) :from-end t) => 6 (find-if 'plusp '(-3 -2 -1 0 1 2 3) :from-end t) => 3
0
) end key from-end ¶0
) end key from-end ¶Like position-if
and find-if
but search for an element for which predicate
returns nil
.
0
) end key from-end ¶0
) end key from-end ¶Like position-if
and find-if
but search for an element which matches item,
using test or test-not for comparison.
(position #\A "BabA" :test 'char-equal) => 1 (position #/A "BabA" :test 'equalp) => 1 (position #\A "BabA" :test 'char=) => 3 (position #/A "BabA" :test 'eq) => 3
find-position-in-list
is equivalent to position
with
eq
as the value of test.
Tests each element of sequence with predicate and counts how many
times predicate returns non-nil
. This number is returned.
start, end and key are used in the standard way, as described in generic-sequence-arguments. The from-end keyword argument is accepted without error, but it has no effect.
(count-if 'symbolp #(a b "foo" 3)) => 2
Like count-if
but returns the number of elements for which
predicate returns nil
.
Like count
but returns the number of elements which match item.
test or test-not is the function used for the comparison.
(count 4 '(1 2 3 4 5) :test '>) => 3
'eql
) test-not (start1 0
) end1 (start2 0
) end2 key from-end ¶Compares successive elements of sequence1 with successive elements
of sequence2, returning nil
if they all match, or else the index
in sequence1 of the first mismatch. If the sequences differ in length
but match as far as they go, the value is the index in sequence1 of
the place where one sequence ran out. If sequence1 is the one which
ran out, this value equals the length of sequence1, so it isn’t the
index of an actual element, but it still describes the place where
comparison stopped.
Elements are compared using the function test, which should accept two arguments.
If it returns non-nil
, the elements are considered to match.
If you specify test-not instead of test, it is used similarly as a function, but the elements match if test-not returns nil
.
If key is non-nil
, it should be a function of one argument. It is applied
to each element to get an object to pass to test or test-not in place of
the element. Thus, if car
is supplied as key, the cars of the elements
are compared using test or test-not.
start1 and end1 can be used to specify a portion of
sequence1 to use in the comparison, and start2 and end2 can
be used to specify a portion of sequence2. The comparison uses
the first element of each sequence portion, then the second element of
each sequence portion, and so on. If the two specified portions differ
in length, comparison stops where the first one runs out. In any case,
the index returned by mismatch
is still relative to the
whole of sequence1.
If from-end is non-nil
, the comparison proceeds conceptually
from the end of each sequence or portion. The first comparison uses
the last element of each sequence portion, the second comparison
uses the next-to-the-last element of each sequence portion, and so on.
When a mismatch is encountered, the value returned is one greater
than the index of the first mismatch encountered in order of
processing (closest to the ends of the sequences).
(mismatch "Foo" "Fox") => 2 (mismatch "Foo" "FOO" :test 'char-equal) => nil (mismatch "Foo" "FOO" :key 'char-upcase) => nil (mismatch '(a b) #(a b c)) => 2 (mismatch "Win" "The Winner" :start2 4 :end2 7) => nil (mismatch "Foo" "Boo" :from-end t) => 1
0
) end1 (start2 0
) end2 ¶Searches in-sequence-2 (or portion of it) for a subsequence that
matches for-sequence-1 (or portion of it) element by element, and
returns the index in in-sequence-2 of the beginning of the matching subsequence.
If no matching subsequence is found, the value is nil
,
The comparison of each subsequence of in-sequence-2 is done with
mismatch
, and the test, test-not and key arguments
are used only to pass along to mismatch
.
Normally, subsequences are considered starting with the beginning of
the specified portion of in-sequence-2 and proceeding toward the end.
The value is therefore the index of the earliest subsequence that matches.
If from-end is non-nil
, the subsequences are tried in the reverse
order, and the value identifies the latest subsequence that matches.
In either case, the value identifies the beginning of the subsequence found.
(search '(#\A #\B) "cabbage" :test 'char-equal) => 1
Several functions are provided for sorting vectors and lists. These functions use algorithms which always terminate no matter what sorting predicate is used, provided only that the predicate always terminates. The main sorting functions are not stable; that is, equal items may not stay in their original order. If you want a stable sort, use the stable versions. But if you don’t care about stability, don’t use them since stable algorithms are significantly slower.
After sorting, the argument (be it list or vector) has been rearranged
internally so as to be completely ordered. In the case of a vector
argument, this is accomplished by permuting the elements of the vector,
while in the list case, the list is reordered by rplacd
’s in the
same manner as nreverse
. Thus if the argument should not be
clobbered, the user must sort a copy of the argument, obtainable by
fillarray
or copylist
, as appropriate. Furthermore, sort
of a list is like delq
in that it should not be used for effect;
the result is conceptually the same as the argument but in fact is a
different Lisp object.
Should the comparison predicate cause an error, such as a wrong type argument error, the state of the list or vector being sorted is undefined. However, if the error is corrected the sort proceeds correctly.
The sorting package is smart about compact lists; it sorts compact sublists as if they were vectors. See cdr-code for an explanation of compact lists, and MIT A I Lab Memo 587 by Guy L Steele Jr. for an explanation of the sorting algorithm.
The first argument to sort
is a vector or a list whose elements are
to be sorted. The second is a predicate, which must be applicable to
all the objects in the sequence. The predicate should take two
arguments, and return non-nil
if and only if the first argument is
strictly less than the second (in some appropriate sense).
The sort
function proceeds to reorder the elements of the sequence
according to the predicate, and returns a modified sequence. Note that
since sorting requires many comparisons, and thus many calls to the
predicate, sorting is much faster if the predicate is a compiled
function rather than interpreted.
Example: Sort a list alphabetically by the first symbol found at any level
in each element.
(defun mostcar (x) (cond ((symbolp x) x) ((mostcar (car x))))) (sort 'fooarray #'(lambda (x y) (string-lessp (mostcar x) (mostcar y))))
If fooarray
contained these items before the sort:
(Tokens (The alien lurks tonight)) (Carpenters (Close to you)) ((Rolling Stones) (Brown sugar)) ((Beach Boys) (I get around)) (Beatles (I want to hold you up))
then after the sort fooarray
would contain:
((Beach Boys) (I get around)) (Beatles (I want to hold you up)) (Carpenters (Close to you)) ((Rolling Stones) (Brown sugar)) (Tokens (The alien lurks tonight))
When sort
is given a list, it may change the order of the conses of
the list (using rplacd
), and so it cannot be used merely for
side-effect; only the returned value of sort
is the sorted
list. The original list may have some of its elements missing when
sort
returns. If you need both the original list and the sorted
list, you must copy the original and sort the copy (see copylist
,
copylist-fun).
Sorting a vector just moves the elements of the vector into different places, and so sorting a vector for side-effect only is all right.
If the argument to sort
is a vector with a fill pointer, note that,
like most functions, sort
considers the active length of the vector
to be the length, and so only the active part of the vector is
sorted (see array-active-length
, array-active-length-fun).
sortcar
is the same as sort
except that the predicate is applied
to the cars of the elements of sequence, instead of directly to the
elements of sequence. Example:
(sortcar '((3 . dog) (1 . cat) (2 . bird)) #'<) => ((1 . cat) (2 . bird) (3 . dog))
Remember that sortcar
, when given a list, may change the order of the
conses of the list (using rplacd
), and so it cannot be used merely
for side-effect; only the returned value of sortcar
is the
sorted list. The original list is destroyed by sorting.
stable-sort
is like sort
, but if two elements of sequence are equal,
i.e predicate returns nil
when applied to them in either order,
then they remain in their original order.