Lisp Machine Manual

Lisp Machine Manual

Table of Contents

1 Introduction

1.1 General Information

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.

1.2 Structure of the Manual

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.

1.3 Notational Conventions and Helpful Notes

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:

Function: function-name arg1 arg2 &optional arg3 (arg4 arg2)

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:

Special Form: do-three-times form

This evaluates form three times and returns the result of the third evaluation.

Macro: with-foo-bound-to-nil form...

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:

Special Form: twiddle-frob [(frob option...)] {parameter value}...

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:

Method on Operation: 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:

Variable: typical-variable

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.



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).

1.4 Common Lisp Support

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.

Function: common-lisp flag

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.

2 Primitive Object Types

2.1 Data Types

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).

2.2 Data Type Predicates

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.

Function: symbolp object

t if object is a symbol, otherwise nil.

Function: nsymbolp object

nil if object is a symbol, otherwise t.

Function: listp object

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.]

Function: cli:listp object

The Common Lisp version of listp returns t if object is nil or a cons.

Function: nlistp object

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.]

Function: atom object

t if object is not a cons, otherwise nil. This is the same as (not (consp object)).

Function: 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.

Function: numberp object

t if object is any kind of number, otherwise nil.

Function: integerp object
Function: fixp object

Return t if object is a representation of an integer, i.e. a fixnum or a bignum, otherwise nil.

Function: floatp object

t if object is a floating-point number, i.e. a full-size or short float, otherwise nil.

Function: fixnump object

t if object is a fixnum, otherwise nil.

Function: bigp object

t if object is a bignum, otherwise nil.

Function: flonump object

t if object is a full-size float, otherwise nil.

Function: small-floatp object

t if object is a short float, otherwise nil.

Function: rationalp object

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.

Function: complexp object

t if object is a complexnum, a number explicitly represented as complex. Otherwise nil.

Function: realp object

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.

Function: characterp object

t if object is a character object, otherwise nil.

Function: stringp object

t if object is a string, otherwise nil.

Function: arrayp object

t if object is an array, otherwise nil. Note that strings are arrays.

Function: vectorp object

t if object is an array of rank 1.

Function: bit-vector-p object

t if object is an array of rank 1 that allows only 0 and 1 as elements.

Function: simple-vector-p object

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.

Function: simple-bit-vector-p object

t if object is an array of rank 1, with no fill pointer and not displaced, that allows only 0 and 1 as elements.

Function: simple-string-p object

t if object is a string with no fill pointer and not displaced.

Function: functionp object &optional allow-special-forms

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.

Function: compiled-function-p object
Function: subrp object

t if object is any compiled code object, otherwise nil. The name subrp is for Maclisp compatibility.

Function: special-form-p symbol

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.

Function: closurep object

t if object is a closure, otherwise nil.

Function: entityp object

t if object is an entity, otherwise nil. See (entity) for information about entities.

Function: locativep object

t if object is a locative, otherwise nil.

Function: commonp object

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)).

2.3 Type Specifiers

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).

2.3.1 Standard Type Specifiers

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.

2.3.2 User-Defined Type Specifiers

Macro: deftype type-name lambda-list body...

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

2.3.3 Testing Types with Type Specifiers

Function: type-of object

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).

Function: typep object type-spec

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.

Macro: typecase key-form clauses...

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)))
Macro: etypecase key-form clauses...

Like typecase except that an uncorrectable error is signaled if every clause fails. t or otherwise clauses are not allowed.

Macro: ctypecase place clauses...

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.

2.3.4 Coercion with Type Specifiers

Function: coerce object type-spec

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.

2.3.5 Comparing Type Specifiers

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?

Function: subtypep type1 type2

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.

3 Evaluation

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.

3.1 Variables

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.

3.1.1 Variables and Bindings

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)         ;prints 5
  (let ((a "foo"))
    (print a)       ;prints "foo"
    (setq a "bar")
    (print a))      ;prints "bar"
  (print a))        ;prints 5

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.

3.1.2 Setting Variables

Here are the constructs used for setting variables.

Special Form: setq {variable value}...

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.

Macro: psetq {variable value}...

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
Special Form: variable-location symbol

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).

Special Form: variable-boundp symbol

t if variable symbol is not void. It is equivalent to

(location-boundp (variable-location symbol))

symbol is not evaluated.

Special Form: variable-makunbound symbol

Makes symbol’s current binding void. It is equivalent to

(location-makunbound (variable-location symbol))

symbol is not evaluated.

3.1.3 Variable Binding Constructs

Here are the constructs used for binding variables.

Special Form: let ((var value)...) body...

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.

Special Form: let* ((var value)...) body...

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.

Special Form: let-if condition ((var value)...) body...

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.

Macro: let-globally ((var value)...) body...
Macro: let-globally-if condition ((var value)...) body...

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.

Special Form: progv symbol-list value-list body...

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.

Special Form: progw vars-and-vals-form body...

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.

3.1.4 Defining Global Variables

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.

Macro: defvar variable [initial-value] [documentation]

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.

Macro: defconst variable initial-value [documentation]
Macro: defparameter variable initial-value [documentation]

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.

Macro: defconstant symbol value [documentation]

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.

3.1.5 The Global Binding

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.

Macro: setq-globally {symbol value}...

Sets each symbol’s global binding to the value that follows. The value’s are evaluated but the symbol’s are not.

Function: set-globally symbol value

Sets the global binding of symbol to value.

Function: makunbound-globally symbol

Makes the global binding of symbol be void.

Function: boundp-globally symbol

Returns t if the global binding of symbol is not void.

Function: symeval-globally symbol
Function: symbol-value-globally symbol

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.

3.2 Generalized Variables

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.

3.2.1 setf

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.

Macro: setf {place value}...

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.

Condition: sys:unknown-setf-reference (error)
Condition: 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.

Macro: psetf {place value}...

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.

Macro: shiftf place...

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.

Macro: rotatef place...

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.

Macro: swapf place1 place2

Exchanges the contents of place1 and place2. This is a special case of rotatef.

Macro: incf place [amount]

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).

Macro: decf place [amount]

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)).

3.2.2 locf

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.

Macro: locf place

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.

3.3 Functions

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:

Required positional 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”).

Optional positional parameters:

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.

After the positional parameters:

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.

Rest parameter:

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.

Keyword parameters:

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.

Constant: lambda-parameters-limit

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.

3.3.1 Lambda-List Keywords

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.

Constant: lambda-list-keywords

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.

&quote

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 &quote 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).

3.3.2 Local Functions

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.

Special Form: flet local-functions body...

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).

Special Form: labels local-functions body...

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)).

3.4 Some Functions and Special Forms

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.

Function: eval form &optional nohook

(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)).

Function: si:eval1 form &optional nohook

Within the definition of a special form, evaluates form in the current lexical environment.

Function: funcall f &rest args

(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.

Function: apply f &rest args
Function: lexpr-funcall f &rest args

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.

Constant: call-arguments-limit

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.

Function: call function &rest argument-specifications

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.

Special Form: quote object

(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)))
Special Form: function f

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.

Function: false

Takes no arguments and returns nil.

Function: true

Takes no arguments and returns t.

Function: ignore &rest ignore

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.

Special Form: comment

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.

3.5 Declarations

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.

Special Form: local-declare (declaration...) 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.

Special Form: declare declaration...

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 defuns 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 defuns, 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 (defsubsts) 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 defdecls.

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.

Macro: locally &body body

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.

Function: proclaim &rest declarations

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)).

Special Form: special variables...

Equivalent to (proclaim (special variables...)), this declares each of the variables to be globally special. This function is obsolete.

Special Form: unspecial variables...

Removes any global special declarations of the variables. This function is obsolete.

Macro: the type-specifier value-form

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)).

3.6 Tail Recursion

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.

Variable: tail-recursion-flag

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.

3.7 Multiple Values

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.

Function: values &rest args

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.

Function: values-list list

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.

Special Form: multiple-value (variable...) form
Special Form: multiple-value-setq (variable...) form

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.

Special Form: multiple-value-bind (variable...) form body...

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)
Special Form: multiple-value-call function argforms...

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)
Special Form: multiple-value-prog1 form forms...

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
Special Form: multiple-value-list form

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.

Special Form: nth-value n form

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.

Constant: multiple-values-limit

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.

3.8 Evaluation and Function Calling Errors

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.

Condition: 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.

Condition: 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.

Condition: 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.

Condition: 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.

Condition: 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.

Condition Flavor: 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.

Condition: sys:unbound-variable (sys:cell-contents-error error)

This condition name categorizes all errors of variables whose values are void.

Condition: sys:unbound-special-variable
Condition: sys:unbound-closure-variable
Condition: 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.

Condition: sys:undefined-function (sys:cell-contents-error error)

This condition name categorizes errors of function specs that are undefined.

Condition: 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.

4 Flow of Control

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).

4.1 Compound Statements

Special Form: progn body...

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.

Special Form: prog1 first-form body...

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.

Special Form: prog2 first-form second-form body...

prog2 is similar to progn and prog1, but it returns its second form. It is included largely for compatibility with old programs.

4.2 Conditionals

Special Form: if

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.

Macro: when condition body...

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.

Macro: unless condition body...

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.

Special Form: cond

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 
                    ; just z.  If z is non-nil, it is returned.
      (t            ;A condition of t
       105)         ; is always satisfied.
   )                ;This is the end of the cond.
Macro: cond-every

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.

Special Form: and form...

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.

Special Form: or form...

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.

Macro: selectq
Macro: case
Macro: caseq

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:

1) A symbol

If the key is eql to the symbol, it matches.

2) A number

If the key is eql to the number, it matches. key must have the same type and the same value as the number.

3) A list

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.

4) 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.

Macro: ecase key-form clauses...

Like case except that an uncorrectable error is signaled if every clause fails. t or otherwise clauses are not allowed.

Macro: ccase place clauses...

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.

Macro: select

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)))
Macro: selector

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))))
Macro: select-match

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.

Macro: dispatch

(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.

Macro: selectq-every

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)))

4.2.1 Comparison Predicates

Function: eq x y

(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).

Function: neq x y

(neq x y) = (not (eq x y)). This is provided simply as an abbreviation for typing convenience.

Function: eql x y

eql is the same as eq except that if x and y are numbers of the same type they are eql if they are =.

Function: equal x y

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
Function: equalp x y

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
Function: not x
Function: null x

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.

4.3 Iteration

Special Form: do

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, i.e. 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, i.e. 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-style do.
  (aset 0 foo-array i))	; Note how the setq is avoided.

(do ((z list (cdr z)) ; z starts as list and is cdr'd each time.
     (y other-list)   ; y starts as other-list, and is unchanged by the do.
     (x)	      ; x starts as nil and is not changed by the do.
     w) 	      ; w starts as nil and is not changed by the do.
    (nil)	      ; The end-test is nil, so this is an infinite loop.
  body)    ; Presumably the body uses return 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 of nreverse.
    )                          ;no do-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, i.e. 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.

Special Form: do*

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.

Special Form: do-named

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.

Special Form: do*-named

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.

Macro: dotimes (index count [value-expression]) body...

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.

Macro: dolist (item list [value-expression]) body...

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.

Macro: do-forever body...

Executes the forms in the body over and over, or until a non-local exit (such as return).

4.4 Static Non-Local Exits

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.

Special Form: block name body...

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
Special Form: return-from name values

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.

Special Form: return values

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.

Special Form: return-list list

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.

4.5 Tags and Gotos

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-protects 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.

Special Form: tagbody statements-and-tags...

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.

Special Form: go tag

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.

Special Form: prog

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...))))
Special Form: prog*

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.

4.6 Dynamic Non-Local Exits

Special Form: catch tag body...

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.

Special Form: catch-continuation tag throw-cont non-throw-cont body...
Special Form: catch-continuation-if cond-form tag throw-cont non-throw-cont body...

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.

Special Form: throw tag values-form

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.

Macro: *catch form tag
Macro: *throw form tag

Old, obsolete names for catch and throw.

Condition: 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.

Function: *unwind-stack tag value active-frame-count action

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.

Special Form: unwind-protect protected-form cleanup-form...

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.

Macro: catch-all body...

(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.

4.7 Mapping

Function: map fcn &rest lists
Function: mapl fcn &rest lists
Function: mapc fcn &rest lists
Function: maplist fcn &rest lists
Function: mapcar fcn &rest lists
Function: mapcon fcn &rest lists
Function: mapcan fcn &rest lists

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).

5 Manipulating List Structure

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).

5.1 Conses

Function: car x

Returns the car of x.

Example:
(car '(a b c)) => a
Function: cdr x

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.

Function: c...r x

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.

Function: cons x y

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)
Function: ncons x

(ncons x) is the same as (cons x nil). The name of the function is from “nil-cons”.

Function: xcons x y

xcons (“exchanged cons”) is like cons except that the order of the arguments is reversed.

Example:
(xcons 'a 'b) => (b . a)
Function: cons-in-area x y area-number

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)
Function: ncons-in-area x area-number

(ncons-in-area x area-number) = (cons-in-area x nil area-number)

Function: xcons-in-area x y area-number

(xcons-in-area x y area-number) = (cons-in-area y x area-number)

Macro: push item place

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.

Macro: pop place

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).

Function: car-location cons

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.

Function: rplaca x y

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)
Function: rplacd x y

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.

5.2 Lists

Function: list &rest args

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)))))
Function: list* &rest args

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
Function: length list-or-array

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))))
Function: list-length list

Returns the length of list, or nil if list is circular. (The function length would loop forever if given a circular list.)

Function: first list
Function: second list
Function: third list
Function: fourth list
Function: fifth list
Function: sixth list
Function: seventh 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.

Function: rest list
Function: rest1 list
Function: rest2 list
Function: rest3 list
Function: rest4 list

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.

Function: endp list

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.

Function: nth n list

(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))))
Function: nthcdr n list

(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)))
Function: last 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)))))
Macro: list-match-p object pattern

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.

Function: list-in-area area-number &rest args

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.

Function: list*-in-area area-number &rest args

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.

Function: make-list length &key area initial-element

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.

Function: circular-list &rest args

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)
Function: copylist list &optional area
Function: copy-list list &optional area

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.

Function: copylist* list &optional area

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.

Function: copyalist list &optional area
Function: copy-alist list &optional area

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.

Function: append &rest lists

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.

Function: nconc &rest lists

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) ;hook y onto x
	     x)))		 ;and return the modified x.
Function: revappend x y

(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)))))
Function: nreconc 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.

Function: butlast list &optional (n 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”.

Function: nbutlast list &optional (n 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)
Function: firstn n list

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)
Function: nleft n list &optional tail

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)
Function: ldiff list tail

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.
Function: car-safe object
Function: cdr-safe object
Function: caar-safe object
Function: cadr-safe object
Function: cdar-safe object
Function: cddr-safe object
Function: caddr-safe object
Function: cdddr-safe object
Function: cadddr-safe object
Function: cddddr-safe object
Function: nth-safe n object
Function: nthcdr-safe n object

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

5.3 Cons Cells as Trees

Function: copytree tree &optional area
Function: copy-tree tree &optional area

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.

Function: tree-equal x y &key test test-not

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.

Function: subst new old tree

(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.

Function: cli:subst new old tree &key test test-not key

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.

Function: nsubst new old tree &key test test-not key

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)))
Function: subst-if new predicate tree &key key

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.

Function: subst-if-not new predicate tree &key key

Similar, but replaces tree nodes which do not satisfy predicate.

Function: nsubst-if new predicate tree &key key
Function: nsubst-if-not new predicate tree &key key

Like subst-if and subst-if-not except that they destructively modify tree itself and return it, creating no new list structure.

Function: sublis alist tree &key test test-not key

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)))))))
Function: nsublis alist tree &key test test-not key

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))))

5.4 Cdr-Coding

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)).

5.5 Tables

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.

5.6 Lists as Tables

Function: memq item list

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 for x in the list z.
  (if (not (null sublist))      ;If it is found,
      (rplaca sublist y)))	;Replace it with y.
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.

Function: member item list

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)))))
Function: cli:member item list &key test test-not key

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)
Function: member-if predicate list &key key

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.

Function: member-if-not predicate list &key key

Searches for an element which does not satisfy predicate. Otherwise like member-if.

Function: mem predicate item list

Is equivalent to

(cli:member item list :test predicate)

The function mem antedates cli:member.

Function: find-position-in-list item list

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)).

Function: find-position-in-list-equal item list

Is like find-position-in-list, except that the comparison is done with equal instead of eq.

Function: tailp sublist list

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))))
Function: delq item list &optional n

(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.

Function: delete item list &optional n

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.

Function: del predicate item list &optional n

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)
Function: remq item list &optional n

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)
Function: remove item list &optional n

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.

Function: rem predicate item list &optional n

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).

Function: subset predicate list
Function: rem-if-not predicate list

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)
Function: subset-not predicate list
Function: rem-if predicate list

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.

Function: del-if predicate list

del-if is just like rem-if except that it modifies list rather than creating a new list.

Function: del-if-not predicate 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)).

Function: every list predicate &optional step-function

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).

Function: some list predicate &optional step-function

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).

5.7 Lists as Sets

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)).

Function: subsetp list1 list2 &key test test-not key

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.

Function: adjoin item list &key test test-not key

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.

Macro: pushnew item list-place &key test test-not key

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).

Function: union list &rest more-lists

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.

Function: intersection list &rest more-lists

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.

Function: nunion list &rest more-lists

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.

Function: nintersection list &rest more-lists

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.

Function: cli:union list1 list2 &key test test-not key
Function: cli:intersection list1 list2 &key test test-not key
Function: cli:nunion list1 list2 &key test test-not key
Function: cli:nintersection list1 list2 &key test test-not key

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.

Function: set-difference list1 list2 &key test test-not key

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.

Function: set-exclusive-or list1 list2 &key test test-not key

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.

Function: nset-difference list1 list2 &key test test-not key

Like set-difference but destructively modifies list1 to produce the value. See the caveat in nintersection, above.

Function: nset-exclusive-or list1 list2 &key test test-not key

Like set-exclusive-or but may destructively modify both list1 and list2 to produce the value. See the caveat in nintersection, above.

5.8 Association Lists

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.

Function: pairlis cars cdrs &optional tail

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))
Function: acons acar acdr tail

Returns (cons (cons acar acdr) tail). This adds one additional mapping from acar to acdr onto the alist tail.

Function: assq item alist

(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))) ))
Function: assoc item alist

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))) ))
Function: cli:assoc item alist &key test test-not

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.

Function: ass predicate item alist

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)
Function: assoc-if predicate alist

Returns the first element of alist which is a cons whose car satisfies predicate, or nil if there is no such element.

Function: assoc-if-not predicate alist

Returns the first element of alist which is a cons whose car does not satisfy predicate, or nil if there is no such element.

Function: memass predicate item alist

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).

Function: rassq item alist
Function: rassoc item alist
Function: rass predicate item alist
Function: cli:rassoc item alist &key test test-not
Function: rassoc-if predicate alist
Function: rassoc-if-not predicate alist

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)))))
Function: sassq item alist fcn

(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.

Function: sassoc item alist fcn

(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)))

5.9 Stack Lists

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.

Special Form: with-stack-list (variable element...) body...
Special Form: with-stack-list* (variable element... tail) body...

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.

Condition: 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).

5.10 Property Lists

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.

Function: get plist property-name &optional default-value

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
Function: getl plist property-name-list

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).

Function: putprop plist x property-name

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.

Special Form: defprop symbol x property-name

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)
Function: remprop plist property-name

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.

Macro: getf place property &optional default

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.

Macro: remf place property

Equivalent to (remprop (locf place) property), except that remf is defined in Common Lisp.

Macro: get-properties place list-of-properties

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:

propname

the property name found

value

the value of that property

cell

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.

5.11 Hash Tables

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.

5.11.1 Hash Table Functions

Function: make-hash-table &rest options
Function: make-equal-hash-table &rest options

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.

Function: hash-table-p object

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.

Function: gethash key hash-table &optional default-value

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.

Function: puthash key value hash-table &rest extra-values

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.

Function: remhash key hash-table

Removes any entry for key in hash-table. Returns t if there was an entry or nil if there was not.

Function: swaphash key value hash-table &rest extra-values

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.

Function: maphash function hash-table &rest extra-args

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.

Function: maphash-return function hash-table

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.

Function: clrhash hash-table

Removes all the entries from hash-table. Returns the hash table itself.

Function: hash-table-count hash-table

Returns the number of filled entries in hash-table.

5.11.2 Hash Table Operations

Hash tables are instances, and support the following operations:

Method on Operation: 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.

Method on Operation: hash-table :filled-entries

Returns the number of entries that are currently occupied.

Method on Operation: hash-table :get-hash key
Method on Operation: hash-table :put-hash key &rest values
Method on Operation: hash-table :swap-hash key &rest values
Method on Operation: hash-table :rem-hash key
Method on Operation: hash-table :map-hash function &rest extra-args
Method on Operation: hash-table :map-hash-return function
Method on Operation: hash-table :clear-hash
Method on Operation: 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.

Method on Operation: 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.

5.11.3 Hash Tables and the Garbage Collector

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.

5.11.4 Hash Primitive

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.

Function: sxhash tree &optional ok-to-use-address

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.

5.12 Resources

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.

5.12.1 Defining Resources

Macro: defresource

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)))

5.12.2 Allocating Resource Objects

Function: allocate-resource resource-name &rest parameters

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.

Function: deallocate-resource resource-name resource-object

Frees the object resource-object, returning it to the free-object list of the resource specified by resource-name.

Macro: using-resource (variable resource parameters...) body...

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.
Function: deallocate-whole-resource resource-name

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.

Function: map-resource function resource-name &rest extra-args

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.

Function: clear-resource resource-name

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.

5.12.3 Accessing the Resource Data Structure

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:

Function: si:resource-object resource-structure index

Returns the index’th object remembered by the resource. Both free and allocated objects are remembered.

Function: si:resource-in-use-p resource-structure index

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.

Function: si:resource-parameters resource-structure index

Returns the list of parameters from which the index’th object was originally created.

Function: si:resource-n-objects resource-structure

Returns the number of objects currently remembered by the resource. This will include all objects ever constructed, unless clear-resource has been used.

Function: si:resource-parametizer resource-structure

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.

5.12.4 Fast Pseudo-Resources

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.

6 Symbols

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).

6.1 The Value Cell

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.

Function: symeval symbol
Function: symbol-value symbol

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.

Function: set symbol value

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.

Function: boundp symbol

t if symbol’s value cell is not void.

Function: makunbound symbol

Makes symbol’s value cell void.

Example:
(setq a 1)
a => 1
(makunbound 'a)
a => causes an error.

makunbound returns its argument.

Function: value-cell-location symbol

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.

6.2 The Function Cell

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.

Function: fsymeval symbol
Function: symbol-function symbol

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.

Function: fset symbol definition

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.

Function: fboundp symbol

nil if symbol’s function cell is void, i.e. if symbol is undefined. Otherwise it returns t.

Function: fmakunbound symbol

Causes symbol to be undefined, i.e. its function cell to be void. It returns symbol.

Function: function-cell-location 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.

6.3 The Property List

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.

Function: plist symbol
Function: symbol-plist

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.

Function: setplist symbol list

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)
Function: property-cell-location symbol

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.

6.4 The Print Name

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)).

Function: symbol-name symbol
Function: get-pname symbol

Returns the print-name of the symbol symbol.

Example:
(symbol-name 'xyz) => "XYZ"

get-pname is an older name for this function.

6.5 The Package Cell

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).

6.6 Creating Symbols

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.

Function: make-symbol pname &optional permanent-p

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.

Function: copysymbol symbol copy-props
Function: copy-symbol symbol copy-props

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.

Function: gensym &optional x

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”.

Function: gentemp &optional (prefix "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.

7 Numbers

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:

fixnum

Fixnums are 25-bit twos-complement binary integers. These are the preferred, most efficient type of number.

bignum

Bignums are arbitrary-precision binary integers.

ratio

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.

single-float or full-size float

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-float

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.

complexnum

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.

Variable: zunderflow

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.

Condition: sys:floating-exponent-overflow (sys:arithmetic-error error)
Condition: 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.

7.1 Numeric Predicates

Function: zerop x

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.

Function: plusp x

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.

Function: minusp x

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.

Function: oddp number

Returns t if number is odd, otherwise nil. If number is not a fixnum or a bignum, oddp causes an error.

Function: evenp number

Returns t if number is even, otherwise nil. If number is not a fixnum or a bignum, evenp causes an error.

Special Form: signp test x

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  0

e

x = 0

n

x  0

ge

x  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)).

7.2 Numeric Comparisons

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.

Function: = &rest 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.

Function: > &rest numbers
Function: greaterp &rest 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.

Function: >= &rest numbers
Function:  &rest numbers

 compares each pair of successive arguments. If any argument is less than the next,  returns nil. But if the arguments are monotonically decreasing or equal, the result is t.

>= is the Common Lisp name for this function.

Function: < &rest numbers
Function: lessp &rest numbers

< 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.

Function: <= &rest numbers
Function:  &rest numbers

 compares its arguments from left to right. If any argument is greater than the next,  returns nil. But if the arguments are monotonically increasing or equal, the result is t.

<= is the Common Lisp name for this function.

Function:  &rest numbers
Function: //= &rest numbers

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 /=.

Function: max &rest one-or-more-args

Returns the largest of its arguments, which must not be complex.

Example:
(max 1 3 2) => 3

max requires at least one argument.

Function: min &rest one-or-more-args

Returns the smallest of its arguments, which must not be complex.

Example:
(min 1 3 2) => 1

min requires at least one argument.

7.3 Arithmetic

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).

Function: + &rest args
Function: plus &rest args
Function: +$ &rest args

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.

Function: - arg &rest args
Function: -$ arg &rest args

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.

Function: minus x

Returns the negative of x, just like - with one argument.

Function: difference arg &rest args

Returns its first argument minus all of the rest of its arguments. If there are at least two arguments, difference is equivalent to -.

Function: abs x

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))
Function: * &rest args
Function: times &rest args
Function: *$ &rest args

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.

Function: // arg &rest args
Function: //$ arg &rest args

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
Function: quotient arg &rest args

Returns the first argument divided by all of the rest of its arguments. When there are two or more arguments, quotient is equivalent to //.

Function: cli:// number &rest numbers

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.

Function: floor x &optional (y 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.

Function: ceiling x &optional (y 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.

Function: truncate x &optional (y 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).

Function: round x &optional (y 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.

Function: \ x y
Function: remainder x y
Function: cli:rem x y

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.

Function: mod number divisor

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.

Function: ffloor x &optional (y 1)
Function: fceiling x &optional (y 1)
Function: ftruncate x &optional (y 1)
Function: fround x &optional (y 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.

Condition: 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.

Function: 1+ x
Function: add1 x
Function: 1+$ x

(1+ x) is the same as (+ x 1). The other two names are for Maclisp compatibility.

Function: 1- x
Function: sub1 x
Function: 1-$ x

(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.

Function: gcd &rest integers
Function: \\ &rest integers

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.

Function: lcm integer &rest more-integers

Returns the least common multiple of the specified integers.

Function: expt x y
Function: ^ x y
Function: ^$ x y

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.

Condition: 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.

Function: sqrt x

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)
Function: isqrt x

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.

Function: *dif x y
Function: *plus x y
Function: *quo x y
Function: *times x y

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.

Function: %div dividend divisor

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://.

7.4 Complex Number Functions

See also the predicates realp and complexp ((complexp-fun)).

Function: complex x &optional y

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.

Function: realpart z

Returns the real part of the number z. If z is real, this is the same as z.

Function: imagpart z

Returns the imaginary part of the number z. If z is real, this is zero.

Function: conjugate z

Returns the complex conjugate of the number z. If z is real, this is the same as z.

Function: phase 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 (-, ].

(phase -4) => 
(phase -4-.0001i) is just over -.
(phase 0) => 0 (an arbitrary choice)
Function: cis angle

Returns the complex number of unit magnitude whose phase is angle. This is equal to (complex (cos angle) (sin angle)). angle must be real.

Function: signum z

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.

7.5 Transcendental Functions

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.

Constant: pi

The value of , as a full-size float.

Function: exp x

Returns e raised to the x’th power, where e is the base of natural logarithms.

Function: log x &optional base

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 (-, ]; for negative real x, the value has imaginary part .

If base is specified, the result is

(// (log x) (log base))
Condition: sys:zero-log (sys:arithmetic-error error)

This is signaled when the argument to log is zero.

Function: sin x
Function: cos x
Function: tan x

Return, respectively, the sine, cosine and tangent of x, where x is expressed in radians. x may be complex.

Function: sind x
Function: cosd x
Function: tand x

Return, respectively, the sine, cosine and tangent of x, where x is expressed in degrees.

Function: asin x
Function: acos x

Returns the angle (in radians) whose sine (respectively, cosine) is x. The real part of the result of asin is between -/2 and /2; acos and asin of any given argument always add up to /2.

Function: atan y &optional x

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 -.

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  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 2.

Function: atan2 y &optional x
Function: cli:atan y &optional x

Like atan but always returns a value whose real part is between -/2 and /2. The value is either the same as the value of atan or differs from it by .

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.

Function: sinh x
Function: cosh x
Function: tanh x
Function: asinh x
Function: acosh x
Function: atanh x

The hyperbolic and inverse hyperbolic functions.

7.6 Numeric Type Conversions

These functions are provided to allow specific conversions of data types to be forced, when desired.

Function: float number &optional float

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.

Function: small-float x
Function: short-float x

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.

Function: numerator x

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.

Function: denominator x

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.

Function: rational x

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.

Function: rationalize x &optional precision

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.

Function: fix x

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.

Function: fixr x

fixr is the same as round except that round returns an additional value. fixr is considered obsolete.

7.7 Floating Point Numbers

Function: decode-float float

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
Function: integer-decode-float float

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
Function: scale-float float integer

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
Function: float-sign float1 &optional float2

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
Function: float-radix float

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.

Function: float-digits float

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.

Function: float-precision float

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.

7.8 Logical Operations on Numbers

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.

Function: logior &rest integers

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
Function: logand &rest integers

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
Function: logxor &rest integers

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
Function: logeqv &rest integers

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:

Function: lognand integer1 integer2

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.

Function: lognor integer1 integer2

Returns the bitwise-nor of the two arguments. A bit of the result is 1 if both of the corresponding argument bits are 0.

Function: logorc1 integer1 integer2

Returns the bitwise-or of integer2 with the complement of integer1.

Function: logorc2 integer1 integer2

Returns the bitwise-or of integer1 with the complement of integer2.

Function: logandc1 integer1 integer2

Returns the bitwise-and of integer2 with the complement of integer1.

Function: logandc2 integer1 integer2

Returns the bitwise-and of integer1 with the complement of integer2.

Function: lognot number

Returns the logical complement of number. This is the same as logxor’ing number with -1.

Example:
(lognot #o3456) => #o-3457
Function: boole fn &rest one-or-more-args

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.

Constant: boole-ior
Constant: boole-and
Constant: boole-xor
Constant: boole-eqv
Constant: boole-nand
Constant: boole-nor
Constant: boole-orc1
Constant: boole-orc2
Constant: boole-andc1
Constant: boole-andc2

The boole opcodes that correspond to the functions logior, logand, etc.

Constant: boole-clr
Constant: boole-set
Constant: boole-1
Constant: boole-2

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.

Function: bit-test x y
Function: logtest x y

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.

Function: lsh x y

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
Function: ash x y

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.

Function: rot x y

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
Function: logcount integer

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
Function: integer-length integer

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
Function: haulong integer

The same as integer-length of the absolute value of integer. This name exists for Maclisp compatibility only.

Function: haipart x n

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))))

7.9 Byte Manipulation Functions

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.

Function: byte size position

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.

Function: byte-position byte-spec
Function: byte-size byte-spec

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.

Function: ldb byte-spec integer

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
Function: load-byte integer position size

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.

Function: ldb-test byte-spec integer

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)))
Function: logbitp index 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).

Function: mask-field byte-spec fixnum

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
Function: dpb byte byte-spec integer

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
Function: deposit-byte integer position size byte

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.

Function: deposit-field byte byte-spec fixnum

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.

Function: %logldb byte-spec fixnum

%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.

Function: %logdpb byte byte-spec fixnum

%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.

7.10 Random Numbers

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.

Function: random &optional number random-state

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.

Function: si:random-in-range low high

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.

Function: random-state-p object

t if object is a random-state.

Variable: *random-state*

This random-state is used by default when random is called and the random-state is not explicitly specified.

Function: make-random-state &optional random-state

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.

Function: si:random-create-array length offset seed &optional (area 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.

Function: si:random-initialize random-state &optional new-seed

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).

7.11 Information on Numeric Precision

Common Lisp defines some constants whose values give information in a standard way about the ranges of numbers representable in the individual Lisp implementation.

Constant: most-negative-fixnum

Any integer smaller than this must be a bignum.

Constant: most-positive-fixnum

Any integer larger than this must be a bignum.

Constant: most-positive-short-float

No short float can be greater than this number.

Constant: least-positive-short-float

No positive short float can be closer to zero than this number.

Constant: least-negative-short-float

No negative short float can be closer to zero than this number.

Constant: most-negative-short-float

No short float can be less than this (negative) number.

Constant: most-positive-single-float
Constant: least-positive-single-float
Constant: least-negative-single-float
Constant: most-negative-single-float

Similar to the above, but for full-size floats rather than for short floats.

Constant: most-positive-double-float
Constant: least-positive-double-float
Constant: least-negative-double-float
Constant: most-negative-double-float
Constant: most-positive-long-float
Constant: least-positive-long-float
Constant: least-negative-long-float
Constant: most-negative-long-float

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.

Constant: short-float-epsilon

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.

Constant: single-float-epsilon
Constant: double-float-epsilon
Constant: long-float-epsilon

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.

Constant: short-float-negative-epsilon

Smallest positive short float which can be subtracted from 1.0s0 and make a difference.

Constant: single-float-negative-epsilon
Constant: double-float-negative-epsilon
Constant: long-float-negative-epsilon

Smallest positive float which can be subtracted from 1.0 and make a difference.

7.12 Arithmetic Ignoring Overflow

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.

Function: %pointer-plus pointer-1 pointer-2

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.

Function: %pointer-difference pointer-1 pointer-2

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.

Function: %pointer-times pointer-1 pointer-2

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.

7.13 24-Bit Arithmetic

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.

Function: %24-bit-plus x y

Returns the sum of x and y modulo 2^24. Both arguments must be fixnums.

Function: %24-bit-difference x y

Returns the difference of x and y modulo 2^24. Both arguments must be fixnums.

Function: %24-bit-times x y

Returns the product of x and y modulo 2^24. Both arguments must be fixnums.

7.14 Double-Precision Arithmetic

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.

Function: %multiply-fractions num1 num2

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.]

Function: %divide-double dividend[25:48] dividend[0:24] divisor

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.

Function: %remainder-double dividend[25:48] dividend[0:24] divisor

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.

Function: %float-double high25 low25

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.

8 Arrays

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)).

Constant: array-rank-limit

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.

Constant: array-dimension-limit

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.

Constant: array-total-size-limit

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.

8.1 Array Types

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)).

Constant: array-types

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.

Function: array-types array-type-code

Given an internal numeric array-type code, returns the symbolic name of that type.

Constant: array-elements-per-q

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.

Function: array-elements-per-q array-type-code

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.

Constant: array-bits-per-element

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.

Function: array-bits-per-element array-type-code

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.

Function: array-element-size array

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.

8.2 Extra Features of Arrays

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.

Function: fill-pointer array

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.

8.2.1 Displaced Arrays

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.

8.3 Constructing Arrays

Function: vector &rest elements

Constructs and returns a vector (one-dimensional array) whose elements are the arguments given.

Function: make-array dimensions &rest options.

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.

8.4 Accessing Array Elements

Function: aref array &rest subscripts

Returns the element of array selected by the subscripts. The subscripts must be fixnums and their number must match the rank of array.

Function: cli:aref array &rest subscripts

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.

Function: aset x array &rest subscripts

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)
Function: aloc array &rest subscripts

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...))
Function: ar-1-force array i
Function: as-1-force value array i
Function: ap-1-force array i

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).

Function: array-row-major-index array &rest indices

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...).

Function: array-leader array i

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.

Function: store-array-leader x array i

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)
Function: ap-leader array i

Is equivalent to

(locf (array-leader array i))

The following array accessing functions generally need not be used by users.

Function: ar-1 array i
Function: ar-2 array i j
Function: ar-3 array i j k
Function: as-1 x array i
Function: as-2 x array i j
Function: as-3 x array i j k
Function: ap-1 array i
Function: ap-2 array i j
Function: ap-3 array i j k

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)).

Function: svref vector index

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.

Function: bit bit-vector index
Function: sbit bit-vector index
Function: char bit-vector index
Function: schar bit-vector index

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.

Condition: 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.

Condition Flavor: 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.

Condition: 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.

Condition: 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.

Condition: 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.

8.5 Getting Information About an Array

Function: array-type array

Returns the symbolic type of array.

Example:
(setq a (make-array '(3 5)))
(array-type a) => art-q
Function: array-element-type array

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).

Function: array-length array
Function: array-total-size array

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.

Function: array-active-length array

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).

Function: array-rank array

Returns the number of dimensions of array.

Example:
(array-rank (make-array '(3 5))) => 2
Function: array-dimension array n

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
Function: array-dimension-n n array

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
Function: array-dimensions array

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).

Function: arraydims array

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.

Function: array-in-bounds-p array &rest subscripts

t if subscripts is a legal set of subscripts for array, otherwise nil.

Function: array-displaced-p array

t if array is any kind of displaced array (including an indirect array), otherwise nil. array may be any kind of array.

Function: array-indirect-p array

t if array is an indirect array, otherwise nil. array may be any kind of array.

Function: array-indexed-p array

t if array is an indirect array with an index-offset, otherwise nil. array may be any kind of array.

Function: array-index-offset 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.

Function: array-has-fill-pointer-p 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.

Function: array-has-leader-p array

t if array has a leader, otherwise nil.

Function: array-leader-length array

Returns the length of array’s leader if it has one, or nil if it does not.

Function: adjustable-array-p array

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.

8.6 Changing the Size of an Array

Function: adjust-array array new-dimensions &key element-type initial-element initial-contents fill-pointer displaced-to displaced-index-offset

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.

Function: adjust-array-size array new-size

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.

Function: array-grow array &rest dimensions

Equivalent to (adjust-array array dimensions). This name is obsolete.

Function: si:change-indirect-array array type dimlist displaced-p index-offset

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.

8.7 Arrays Overlaid With Lists

These functions manipulate art-q-list arrays, which were introduced on (art-q-list-var).

Function: g-l-p array

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.

Function: get-list-pointer-into-array array-ref

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.

Function: get-locative-pointer-into-array array-ref

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.

8.8 Adding to the End of an Array

Function: vector-push x array
Function: array-push array x

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.

Function: vector-push-extend x array &optional extension
Function: array-push-extend array x &optional extension

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,

Function: vector-pop array
Function: array-pop array

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.

Condition: 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.

8.9 Copying an Array

The new functions replace ((replace-fun)) and fill ((fill-fun)) are useful ways to copy parts of arrays.

Function: array-initialize array value &optional start end

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.

Function: fillarray array x

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.

Function: listarray array &optional limit

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.

Function: list-array-leader array &optional limit

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.

Function: copy-array-contents from to

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.

Function: copy-array-contents-and-leader from to

Like copy-array-contents, but also copies the leader of from (if any) into to.

Function: copy-array-portion from-array from-start from-end to-array to-start to-end

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.

8.10 Bit Array Functions

These functions perform bitwise boolean operations on the elements of arrays.

Function: bit-and bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-ior bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-xor bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-eqv bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-nand bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-nor bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-andc1 bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-andc2 bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-orc1 bit-array-1 bit-array-2 &optional result-bit-array
Function: bit-orc2 bit-array-1 bit-array-2 &optional result-bit-array

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.

Function: bit-not bit-array &optional result-bit-array

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.

Function: bitblt alu width height from-array from-x from-y to-array to-x to-y

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.

8.11 Order of Array Elements

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:

Function: make-pixel-array width height &rest options

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.

Function: pixel-array-width 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.

Function: pixel-array-height array

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.

Function: ar-2-reverse array horizontal-index vertical-index

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.

Function: as-2-reverse newvalue array horizontal-index vertical-index

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.

Constant: sys:array-index-order

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.

8.12 Matrices and Systems of Linear Equations

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.

Function: math:multiply-matrices matrix-1 matrix-2 &optional matrix-3

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.

Function: math:invert-matrix matrix &optional into-matrix

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).

Function: math:transpose-matrix matrix &optional into-matrix

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.

Function: math:determinant 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.

Function: math:decompose a &optional lu ps

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.

Function: math:solve lu ps b &optional x

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.

Function: math:list-2d-array 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.

Function: math:fill-2d-array array list

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.

Condition: 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.

8.13 Planes

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.

Function: make-plane rank &key type default-value extension initial-dimensions initial-origins

Creates and returns a plane. rank is the number of dimensions. The keyword arguments are

type

The array type symbol (e.g. art-1b) specifying the type of the array out of which the plane is made.

default-value

The default component value as explained above.

extension

The amount by which to extend the plane, as explained above.

initial-dimensions

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.

initial-origins

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.

Function: plane-origin plane

A list of numbers, giving the lowest coordinate values actually stored.

Function: plane-default plane

This is the contents of the infinite number of plane elements that are not actually stored.

Function: plane-extension plane

The amount to extend the plane by, in any direction, when plane-store is done outside of the currently-stored portion.

Function: plane-aref plane &rest subscripts
Function: plane-ref plane subscripts

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.

Function: plane-aset datum plane &rest subscripts
Function: plane-store datum plane 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.

8.14 Maclisp Array Compatibility

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.

Function: array &quote symbol type &eval &rest dims

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.

Function: *array symbol type &rest dims

Is like array, except that all of the arguments are evaluated.

Special Form: store array-ref x

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.

Function: xstore x 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.

Function: arraycall ignored array &rest subscripts

(arraycall t array sub1 sub2...) is the same as (aref array sub1 sub2...). It exists for Maclisp compatibility.

9 Generic Sequence Functions

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.

9.1 Primitive Sequence Operations

Function: make-sequence type size &key initial-element

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
Function: elt sequence index

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.

Function: length 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.

9.2 Simple Sequence Operations

Function: copy-seq sequence

Returns a new sequence of the same type, length and contents as sequence.

Function: concatenate result-type &rest sequences

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)
Function: subseq sequence start &optional end

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.

Function: replace into-sequence-1 from-sequence-2 &key (start1 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.

Function: fill sequence item &key (start 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)
Function: reverse sequence

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)
Function: nreverse sequence

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.

9.3 Mapping On Sequences

Function: cli:map result-type function &rest sequences

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.

Function: cli:some predicate &rest sequences

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.

Function: cli:every predicate &rest sequences

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.

Function: notany predicate &rest sequences
Function: notevery predicate &rest sequences

These are the opposites of cli:some and cli:every.

(notany ...) is equivalent to (not (cli:some ...)).

(notevery ...) is equivalent to (not (cli:every ...)).

Function: reduce function sequence &key from-end (start 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)

9.4 Operating on Selected Elements

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, end

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

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.

from-end

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

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.

9.4.1 Removing Elements from Sequences

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).

Function: remove-if predicate sequence &key (start 0) end count key from-end
Function: delete-if predicate sequence &key (start 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)
Function: remove-if-not predicate sequence &key (start 0) end count key from-end
Function: delete-if-not predicate sequence &key (start 0) end count key from-end

Like remove-if and delete-if except that the elements removed are those for which predicate returns nil.

Function: cli:remove item sequence &key (test 'eql) test-not (start 0) end count key from-end
Function: cli:delete item sequence &key (test '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.

Function: remove-duplicates sequence &key (test 'eql) test-not (start 0) end key from-end
Function: delete-duplicates sequence &key (test '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.

9.4.2 Substitution Functions

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.

Function: substitute-if newitem predicate sequence &key start end count key from-end
Function: nsubstitute-if newitem predicate sequence &key start end count key from-end

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)
Function: substitute-if-not newitem predicate sequence &key start end count key from-end
Function: nsubstitute-if-not newitem predicate sequence &key start end count key from-end

Like substitute-if and nsubstitute-if except that the elements replaced are those for which predicate returns nil.

Function: substitute newitem olditem sequence &key (test 'eql) test-not start end count key from-end
Function: nsubstitute newitem olditem sequence &key (test '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))

9.4.3 Searching for Elements

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).

Function: position-if predicate sequence &key (start 0) end key from-end
Function: find-if predicate sequence &key (start 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
Function: position-if-not predicate sequence &key (start 0) end key from-end
Function: find-if-not predicate sequence &key (start 0) end key from-end

Like position-if and find-if but search for an element for which predicate returns nil.

Function: position item sequence sequence &key test test-not (start 0) end key from-end
Function: find item sequence sequence &key test test-not (start 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.

Function: count-if predicate sequence &key start end key

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
Function: count-if-not predicate sequence &key start end key

Like count-if but returns the number of elements for which predicate returns nil.

Function: count item sequence &key test test-not start end key

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

9.5 Comparison Functions

Function: mismatch sequence1 sequence2 &key (test '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
Function: search for-sequence-1 in-sequence-2 &key from-end test test-not key (start1 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

9.6 Sorting and Merging

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.

Function: sort sequence predicate

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)).

Function: sortcar sequence predicate

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.

Function: stable-sort sequence predicate

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.

Function: stable-sortcar sequence predicate

stable-sortcar is like sortcar, but if two elements of sequence are equal, i.e. predicate returns nil when applied to their cars in either order, then they remain in their original order.

Function: sort-grouped-array array group-size predicate

sort-grouped-array considers its array argument to be composed of records of group-size elements each. These records are considered as units, and are sorted with respect to one another. The predicate is applied to the first element of each record; so the first elements act as the keys on which the records are sorted.

Function: sort-grouped-array-group-key array group-size predicate

This is like sort-grouped-array except that the predicate is applied to four arguments: an array, an index into that array, a second array, and an index into the second array. predicate should consider each index as the subscript of the first element of a record in the corresponding array, and compare the two records. This is more general than sort-grouped-array since the function can get at all of the elements of the relevant records, instead of only the first element.

Function: merge result-type sequence1 sequence2 predicate &key key

Returns a single sequence containing the elements of sequence1 and sequence2 interleaved in order according to predicate. The length of the result sequence is the sum of the lengths of sequence1 and sequence2. result-type specifies the type of sequence to create, as in make-sequence.

The interleaving is done by taking the next element of sequence1 unless the next element of sequence2 is “less” than it according to predicate. Therefore, if each of the argument sequences is sorted, the result of merge is also sorted.

key, if non-nil, is applied to each element to get the object to pass to predicate, rather than the element itself. Thus, if key is car, the cars of the elements are compared rather than the entire elements.

(merge 'list '(1 2 5 6) '(3 5.0 5.1) '<)
  =>  (1 2 3 5 5.0 5.1 6)

10 Characters and Strings

A string is a one-dimensional array representing a sequence of characters. The printed representation of a string is its characters enclosed in quotation marks, for example "foo bar". Strings are constants, that is, evaluating a string returns that string. Strings are the right data type to use for text-processing.

Individual characters can be represented by character objects or by fixnums. A character object is actually the same as a fixnum except that it has a recognizably different data type and prints differently. Without escaping, a character object is printed by outputting the character it represents. With escaping, a character object prints as #\char in Common Lisp syntax or as #/char in traditional syntax; see (character-set) and (sharp-slash). By contrast, a fixnum would in all cases print as a sequence of digits. Character objects are accepted by most numeric functions in place of fixnums, and may be used as array indices. When evaluated, they are constants.

The character object data type was introduced recently for Common Lisp support. Traditionally characters were always represented as fixnums, and nearly all system and user code still does so. Character objects are interchangeable with fixnums in most contexts, but not in eq, which is often used to compare the result of the stream input operations such as :tyi, since that might be nil. Therefore, the stream input operations still return fixnums that represent characters. Aside from this, Common Lisp functions that return a character return a character object, while traditional functions return a fixnum. The fixnum which is the character code representing char can be written as #/char in traditional syntax. This is equivalent to writing the fixnum using digits, but does not require you to know the character code.

Most strings are arrays of type art-string, where each element is stored in eight bits. Only characters with character code less than 256 can be stored in an ordinary string; these characters form the type string-char. A string can also be an array of type art-fat-string, where each element holds a sixteen-bit unsigned fixnum. The extra bits allow for multiple fonts or an expanded character set.

Since strings are arrays, the usual array-referencing function aref is used to extract characters from strings. For example, (aref "frob" 1) returns the representation of lower case r. The first character is at index zero.

Conceptually, the elements of a string are character objects. This is what Common Lisp programs expect to see when they do aref (or char, which on the Lisp Machine is synonymous with aref) on a string. But nearly all Lisp Machine programs are traditional, and expect elements of strings to be fixnums. Therefore, aref of a string actually returns a fixnum. A distinct version of aref exists for Common Lisp programs. It is cli:aref and it does return character objects if given a string. For all other kinds of arrays, aref and cli:aref are equivalent.

(aref "Foo" 1)  =>  #o157
(cli:aref "Foo" 1)  =>  #/o

It is also legal to store into strings, for example using setf of aref. As with rplaca on lists, this changes the actual object; you must be careful to understand where side-effects will propagate. It makes no difference whether a character object or a fixnum is stored. When you are making strings that you intend to change later, you probably want to create an array with a fill-pointer (see (fill-pointer)) so that you can change the length of the string as well as the contents. The length of a string is always computed using array-active-length, so that if a string has a fill-pointer, its value is used as the length.

The functions described in this section provide a variety of useful operations on strings. In place of a string, most of these functions accept a symbol or a fixnum as an argument, coercing it into a string. Given a symbol, its print name, which is a string, is used. Given a fixnum, a one-character string containing the character designated by that fixnum is used. Several of the functions actually work on any type of one-dimensional array and may be useful for other than string processing; these are the functions such as substring and string-length which do not depend on the elements of the string being characters.

The generic sequence functions in chapter (sequence-chapter) may also be used on strings.

10.1 Characters

The Lisp Machine data type for character objects is a recent addition to the system. Most programs still use fixnums to represent characters.

Common Lisp programs typically work with actual character objects but programs traditionally use fixnums to represent characters. The new Common Lisp functions for operating with characters have been implemented to accept fixnums as well, so that they can be used equally well from traditional programs.

Function: characterp object

t if object is a character object; nil otherwise. In particular, it is nil if object is a fixnum such as traditional programs use to represent characters.

Function: character object

Coerces object to a single character, represented as a fixnum. If object is a number, it is returned. If object is a string or an array, its first element is returned. If object is a symbol, the first character of its pname is returned. Otherwise an error occurs. The way characters are represented as fixnums is explained in (character-set).

Function: cli:character object

Coerces object into a character and returns the character as a character object for Common Lisp programs.

Function: int-char fixnum

Converts fixnum, regarded as representing a character, to a character object. This is a special case of cli:character. (int-char #o101) is the character object for A. If a character object is given as an argument, it is returned unchanged.

Function: char-int char

Converts char, a character object, to the fixnum which represents the same character. This is the inverse of int-char. It may also be given a fixnum as argument, in which case the value is the same fixnum.

10.1.1 Components of a Character

A character object, or a fixnum which is interpreted as a character, contains three separate pieces of information: the character code, the font number, and the modifier bits. Each of these things is an integer from a fixed range. The character code ranges from 0 to 377 (octal), the font number from 0 to 377 (octal), and the modifier bits from 0 to 17 (octal). These numeric constants should not appear in programs; instead, use the constant symbols char-code-limit, and so on, described below.

Ordinary strings can hold only characters whose font number and modifier bits are zero. Fat strings can hold characters with any font number, but the modifier bits must still be zero.

Character codes less than 200 octal are printing graphics; when output to a device they are assumed to print a character and move the cursor one character position to the right. (All software provides for variable-width fonts, so the term “character position” shouldn’t be taken too literally.)

Character codes 200 through 236 octal are used for special characters. Character 200 is a “null character”, which does not correspond to any key on the keyboard. The null character is not used for anything much; fasload uses it internally. Characters 201 through 236 correspond to the special function keys on the keyboard such as Return and Call. The remaining character codes 237 through 377 octal are reserved for future expansion.

Most of the special characters do not normally appear in files (although it is not forbidden for files to contain them). These characters exist mainly to be used as “commands” from the keyboard. A few special characters, however, are “format effectors” which are just as legitimate as printing characters in text files. The names and meanings of these characters are:

Return

The “newline” character, which separates lines of text. We do not use the PDP-10 convention which separates lines by a pair of characters, a “carriage return” and a “linefeed”.

Page

The “page separator” character, which separates pages of text.

Tab

The “tabulation” character, which spaces to the right until the next “tab stop”. Tab stops are normally every 8 character positions.

The space character is considered to be a printing character whose printed image happens to be blank, rather than a format effector.

When a letter is typed with any of the modifier bit keys (Control, Meta, Super, or Hyper), the letter is normally upper-case. If the Shift key is pressed as well, then the letter becomes lower-case. This is exactly the reverse of what the Shift key does to letters without control bits. (The Shift-lock key has no effect on letters with control bits.)

Function: char-code char
Function: char-font char
Function: char-bits char

Return the character code of char, the font number of char, and the modifier bits value of char. char may be a fixnum or a character object; the value is always a fixnum.

These used to be written as

(ldb %%ch-char char)
(ldb %%ch-font char)
(ldb %%ch-control-meta char)

Such use of ldb is frequent but obsolete.

Constant: char-code-limit

A constant whose value is a bound on the maximum code of any character. In the Lisp Machine, currently, it is 400 (octal).

Constant: char-font-limit

A constant whose value is a bound on the maximum font number value of any character. In the Lisp Machine, currently, it is 400 (octal).

Constant: char-bits-limit

A constant whose value is a bound on the maximum modifier bits value of any character. In the Lisp Machine, currently, it is 20 (octal). Thus, there are four modifier bits. These are just the familiar Control, Meta, Super and Hyper bits.

Constant: char-control-bit
Constant: char-meta-bit
Constant: char-super-bit
Constant: char-hyper-bit

Constants with values 1, 2, 4 and 8. These give the meanings of the bits within the bits-field of a character object. Thus, (bit-test char-meta-bit (char-bits char)) would be non-nil if char is a meta-character. (This can also be tested with char-bit.)

Function: char-bit char name

t if char has the modifier bit named by name. name is one of the following four symbols: :control, :meta, :super, and :hyper.

(char-bit #\meta-x :meta) => t.
Function: set-char-bit char name newvalue

Returns a character like char except that the bit specified by name is present if newvalue is non-nil, absent otherwise. Thus,

(set-char-bit #\x :meta t) => #\meta-x.

The value is a fixnum if char is one; a character object if char is one.

Until recently the only way to access the character code, font and modifier bits was with ldb, using the byte field names listed below. Most code still uses that method, but it is obsolete; char-bit should be used instead.

%%kbd-char
%%ch-char

’vindex %%kbd-char ’vindex %%ch-char Specifies the byte containing the character code.

%%ch-font

’vindex %%ch-font Specifies the byte containing the font number.

%%kbd-control

’vindex %%kbd-control Specifies the byte containing the Control bit.

%%kbd-meta

’vindex %%kbd-meta Specifies the byte containing the Meta bit.

%%kbd-super

’vindex %%kbd-super Specifies the byte containing the Super bit.

%%kbd-hyper

’vindex %%kbd-hyper Specifies the byte containing the Hyper bit.

%%kbd-control-meta

’vindex %%kbd-control-meta Specifies the byte containing all the modifier bits.

Characters are sometimes used to represent mouse clicks. The character says which button was pressed and how many times. Refer to the Window System manual for an explanation of how these characters are generated.

Function: tv:kbd-mouse-p char

t if char is a character used to represent a mouse click. Such characters are always distinguishable from characters that represent keyboard input.

Constant: %%kbd-mouse-button

The value of %%kbd-mouse-button is a byte specifier for the field in a mouse signal that says which button was clicked. The byte contains 0, 1, or 2 for the left, middle, or right button, respectively.

Constant: %%kbd-mouse-n-clicks

The value of %%kbd-mouse-n-clicks is a byte specifier for the field in a mouse signal that says how many times the button was clicked. The byte contains one less than the number of times the button was clicked.

10.1.2 Constructing Character Objects

Function: code-char code &optional (bits 0) (font 0)
Function: make-char code &optional (bits 0) (font 0)

Returns a character object made from code, bits and font. Common Lisp says that not all combinations may be valid, and that nil is returned for an invalid combination. On the Lisp Machine, any combination is valid if the arguments are valid individually.

According to Common Lisp, code-char requires a number as a first argument, whereas make-char requires a character object, whose character code is used. On the Lisp Machine, either function may be used in either way.

Function: digit-char weight &optional (radix 10.) (font 0)

Returns a character object which is the digit with the specified weight, and with font as specified. However, if there is no suitable character which has weight weight in the specified radix, the value is nil. If the “digit” is a letter (which happens if weight is greater than 9), it is returned in upper case.

Function: tv:make-mouse-char button n-clicks

Returns the fixnum character code that represents a mouse click in the standard way. tv:mouse-char-p of this value is t. button is 0 for the leftbutton, 1 for the middle button, or 2 for the right button. n-clicks is one less than the number of clicks (1 for a double click, 0 normally).

10.1.3 The Character Set

Here are the numerical values of the characters in the Zetalisp character set. It should never be necessary for a user or a source program to know these values. Indeed, they are likely to be changed in the future. There are symbolic names for all characters; see the section on character names, below.

It is worth pointing out that the Zetalisp character set is different from the ASCII character set. File servers operating on hosts that use ASCII for storing text files automatically perform character set conversion when text files are read or written. The details of the mapping are explained in (character-set-differences).

000 center-dot (@centerDot{})             040 space       100 @@           140 `
001 down arrow (@downArrow{})             041 !           101 A           141 a
002 alpha (@alpha{})                  042 "           102 B           142 b
003 beta (@beta{})                   043 #           103 C           143 c
004 and-sign (@andSign{})               044 $           104 D           144 d
005 not-sign (@notSign{})               045 %           105 E           145 e
006 epsilon (@epsilon{})                046 &           106 F           146 f
007 pi (@pi{})                     047 '           107 G           147 g
010 lambda ((ctl-h))                 050 (           110 H           150 h
011 gamma (@gamma{})                  051 )           111 I           151 i
012 delta (@delta{})                  052 *           112 J           152 j
013 uparrow (@uparrow{})                053 +           113 K           153 k
014 plus-minus (@plusMinus{})             054 ,           114 L           154 l
015 circle-plus ((ctl-m))            055 -           115 M           155 m
016 infinity (@infinity{})               056 .           116 N           156 n
017 partial delta (@partialDelta{})          057 /           117 O           157 o
020 left horseshoe (@leftHorseshoe{})         060 0           120 P           160 p
021 right horseshoe (@delta{})        061 1           121 Q           161 q
022 up horseshoe (@upHorseshoe{})           062 2           122 R           162 r
023 down horseshoe (@downHorseshoe{})         063 3           123 S           163 s
024 universal quantifier (@universalQuantifier{})   064 4           124 T           164 t
025 existential quantifier (@existentialQuantifier{}) 065 5           125 U           165 u
026 circle-X (@circleX{})               066 6           126 V           166 v
027 double-arrow (@doubleArrow{})           067 7           127 W           167 w
030 left arrow (@leftArrow{})             070 8           130 X           170 x
031 right arrow (@rightArrow{})            071 9           131 Y           171 y
032 not-equals (@notEquals{})             072 :           132 Z           172 z
033 diamond (altmode) (@diamond{})      073 ;           133 [           173 @{
034 less-or-equal (@lessOrEqual{})          074 <           134 \           174 |
035 greater-or-equal (@greaterOrEqual{})       075 =           135 ]           175 @}
036 equivalence (@equivalence{})            076 >           136 ^           176 ~
037 or (@or{})                     077 ?           137 _           177 (ctl-qm)
200 Null character     210 Overstrike    220 Stop-output   230 Roman-iv
201 Break              211 Tab           221 Abort         231 Hand-up
202 Clear              212 Line          222 Resume        232 Hand-down
203 Call               213 Delete        223 Status        233 Hand-left
204 Terminal escape    214 Page          224 End           234 Hand-right
205 Macro/backnext     215 Return        225 Roman-i       235 System
206 Help               216 Quote         226 Roman-ii      236 Network
207 Rubout             217 Hold-output   227 Roman-iii
237-377 reserved for the future
The Lisp Machine Character Set
(all numbers in octal)

10.1.4 Classifying Characters

Function: string-char-p char

t if char is a character that can be stored in a string. On the Lisp Machine, this is true if the font and modifier bits of char are zero.

Function: standard-char-p char

t if char is a standard Common Lisp character: any of the 95 ASCII printing characters (including Space), and the Return character. Thus (standard-char-p #\end) is nil.

Function: graphic-char-p char

t if char is a graphic character; one which has a printed shape. A, -, Space and  are all graphic characters; Return, End and Abort are not. A character whose modifier bits are nonzero is never graphic.

Ordinary output to windows prints graphic characters using the current font. Nongraphic characters are printed using lozenges unless they have special formatting meanings (as Return does).

Function: alpha-char-p char

t if char is a letter with zero modifier bits.

Function: digit-char-p char &optional (radix 10.)

If char is a digit available in the specified radix, returns the weight of that digit. Otherwise, it returns nil. If the modifier bits of char are nonzero, the value is always nil. (It would be more useful to ignore the modifier bits, but this decision provides Common Lisp with a foolish consistency.) Examples:

(digit-char-p #\8 8) => nil
(digit-char-p #\8 9) => 8
(digit-char-p #\F 16.) => 15.
(digit-char-p #\c-8 anything) => nil
Function: alphanumericp char

t if char is a letter or a digit 0 through 9, with zero modifier bits.

10.1.5 Comparing Characters

Function: char-equal &rest chars

This is the primitive for comparing characters for equality; many of the string functions call it. The arguments may be fixnums or character objects indiscriminately. The result is t if the characters are equal ignoring case, font and modifier bits, otherwise nil.

Function: char-not-equal &rest chars

t if the arguments are all different as characters, ignoring case, font and modifier bits.

Function: char-lessp &rest chars
Function: char-greaterp &rest chars
Function: char-not-lessp &rest chars
Function: char-not-greaterp &rest chars

Ordered comparison of characters, ignoring case, font and modifier bits. These are the primitives for comparing characters for order; many of the string functions call it. The arguments may be fixnums or character objects. The result is t if the arguments are in strictly increasing (strictly decreasing, nonincreasing, nondecreasing) order. Details of the ordering of characters are in (character-set).

Function: char= char1 &rest chars
Function: char//= char1 &rest chars
Function: char> char1 &rest chars
Function: char< char1 &rest chars
Function: char>= char1 &rest chars
Function: char<= char1 &rest chars

These are the Common Lisp functions for comparing characters and including the case, font and bits in the comparison. On the Lisp Machine they are synonyms for the numeric comparison functions =, >, etc. Note that in Common Lisp syntax you would write char/=, not char//=.

10.1.6 Character Names

Characters can sometimes be referred to by long names; as, for example, in the #\ construct in Lisp programs. Every basic character (zero modifier bits) which is not a graphic character has one or more standard names. Some graphic characters have standard names too. When a non-graphic character is output to a window, it appears as a lozenge containing the character’s standard name.

Function: char-name char

Returns the standard name (or one of the standard names) of char, or nil if there is none. The name is returned as a string. (char-name #\space) is the string "SPACE".

If char has nonzero modifier bits, the value is nil. Compound names such as Control-X are not constructed by this function.

Function: name-char name

Returns (as a character object) the character for which name is a name, or returns nil if name is not a recognized character name. name may be a symbol or a string. Compound names such as Control-X are not recognized.

read uses this function to process the #\ construct when a character name is encountered.

The following are the recognized special character names, in alphabetical order except with synonyms together. Character names are encoded and decoded by the functions char-name and name-char ((char-name-fun)).

First a list of the special function keys.

abort		break		call		clear-input,  clear
delete		end		hand-down	hand-left
hand-right	hand-up		help		hold-output
line,  lf		macro,  back-next	network
overstrike,  backspace,  bs		page,  form,  clear-screen
quote		resume		return, cr		
roman-i		roman-ii		roman-iii		roman-iv
rubout		space,  sp		status		stop-output
system		tab		terminal,  esc

These are printing characters that also have special names because they may be hard to type on the hosts that are used as file servers.

altmode		circle-plus	delta		gamma
integral		lambda		plus-minus	uparrow
center-dot	down-arrow	alpha		beta
and-sign		not-sign		epsilon		pi
lambda		gamma		delta		up-arrow
plus-minus	circle-plus	infinity		partial-delta
left-horseshoe	right-horseshoe	up-horseshoe	down-horseshoe
universal-quantifier			existential-quantifier
circle-x		double-arrow	left-arrow		right-arrow
not-equal		altmode		less-or-equal	greater-or-equal
equivalence	or-sign

The following names are for special characters sometimes used to represent single and double mouse clicks. The buttons can be called either l, m, r or 1, 2, 3 depending on stylistic preference.

mouse-l-1 or mouse-1-1		mouse-l-2 or mouse-1-2
mouse-m-1 or mouse-2-1		mouse-m-2 or mouse-2-2
mouse-r-1 or mouse-3-1		mouse-r-2 or mouse-3-2

10.2 Conversion to Upper or Lower Case

Function: upper-case-p char

t if char is an upper case letter with zero modifier bits.

Function: lower-case-p char

t if char is an lower case letter with zero modifier bits.

Function: both-case-p char

This Common Lisp function is defined to return t if char is a character which has distinct upper and lower case forms. On the Lisp Machine it returns t if char is a letter with zero modifier bits.

Function: char-upcase char

If char, is a lower-case alphabetic character its upper-case form is returned; otherwise, char itself is returned. If font information or modifier bits are present, they are preserved. If char is a fixnum, the value is a fixnum. If char is a character object, the value is a character object.

Function: char-downcase char

Similar, but converts to lower case.

Function: string-upcase string &key (start 0) end

Returns a string like string, with all lower-case alphabetic characters replaced by the corresponding upper-case characters. If start or end is specified, only the specified portion of the string is converted, but in any case the entire string is returned.

The result is a copy of string unless no change is necessary. string itself is never modified.

Function: string-downcase string &key (start 0) end

Similar, but converts to lower case.

Function: string-capitalize string &key (start 0) end

Returns a string like string in which all, or the specified portion, has been processed by capitalizing each word. For this function, a word is any maximal sequence of letters or digits. It is capitalized by putting the first character (if it is a letter) in upper case and any letters in the rest of the word in lower case.

The result is a copy of string unless no change is necessary. string itself is never modified.

Function: nstring-upcase string &key (start 0) end
Function: nstring-downcase string &key (start 0) end
Function: nstring-capitalize string &key (start 0) end

Like the previous functions except that they modify string itself and return it.

Function: string-capitalize-words string &optional (copy-p t) (spaces t)

Puts each word in string into lower-case with an upper case initial, and if spaces is non-nil replaces each hyphen character with a space.

If copy-p is t, the value is a copy of string, and string itself is unchanged. Otherwise, string itself is returned, with its contents changed.

This function is somewhat obsolete. One can use string-capitalize followed optionally by string-subst-char.

See also the format operation ~(...~) on (format-case-convert).

10.3 Basic String Operations

Function: make-string size &key (initial-element 0)

Creates and returns a string of length size, with each element initialized to initial-element, which may be a fixnum or a character.

Function: string x

Coerces x into a string. Most of the string functions apply this to their string arguments. If x is a string (or any array), it is returned. If x is a symbol, its pname is returned. If x is a non-negative fixnum less than 400 octal, a one-character-long string containing it is created and returned. If x is an instance that supports the :string-for-printing operation (such as, a pathname) then the result of that operation is returned. Otherwise, an error is signaled.

If you want to get the printed representation of an object into the form of a string, this function is not what you should use. You can use format, passing a first argument of nil (see (format-fun)). You might also want to use with-output-to-string (see (with-output-to-string-fun)).

Function: string-length string

Returns the number of characters in string. This is 1 if string is a number or character object, the array-active-length (see (array-active-length-fun)) if string is an array, or the array-active-length of the pname if string is a symbol.

Function: string-equal string1 string2 &key (start1 0) (start2 0) end1 end2

Compares two strings, returning t if they are equal and nil if they are not. The comparison ignores the font and case of the characters. equal calls string-equal if applied to two strings.

The keyword arguments start1 and start2 are the starting indices into the strings. end1 and end2 are the final indices; the comparison stops just before the final index. nil for end1 or end2 means stop at the end of the string.

Examples:
(string-equal "Foo" "foo") => t
(string-equal "foo" "bar") => nil
(string-equal "element" "select" 0 1 3 4) => t

An older calling sequence in which the start and end arguments are positional rather than keyword is still supported. The arguments come in the order start1 start2 end1 end2. This calling sequence is obsolete and should be changed whenever found.

Function: string-not-equal string1 string2 &key (start1 0) end1 (start2 0) end2

(not (string-equal ...))

Function: string= string1 string2 &key (start1 0) (start2 0) end1 end2

is like string-equal except that case is significant.

(string= "A" "a") => nil
Function: string string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string//= string1 string2 &key (start1 0) end1 (start2 0) end2

(not (string= ...)). Note that in Common Lisp syntax you would write string/=, not string//=.

Function: string-lessp string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string-greaterp string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string-not-greaterp string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string-not-lessp string1 string2 &key (start1 0) end1 (start2 0) end2

Compare all or the specified portions of string1 and string2 using dictionary order. Characters are compared using char-lessp and char-equal so that font and alphabetic case are ignored.

You can use these functions as predicates, but they do more. If the strings fit the condition (e.g. string1 is strictly less in string-lessp) then the value is a number, the index in string1 of the first point of difference between the strings. This equals the length of string1 if the strings match. If the condition is not met, the value is nil.

(string-lessp "aa" "Ab") => 1
(string-lessp "aa" "Ab" :end1 1 :end2 1) => nil
(string-not-greaterp "Aa" "Ab" :end1 1 :end2 1) => 1
Function: string< string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string> string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string>= string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string<= string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string string1 string2 &key (start1 0) end1 (start2 0) end2
Function: string string1 string2 &key (start1 0) end1 (start2 0) end2

Like string-lessp, etc., but treat case and font as significant when comparing characters.

(string< "AA" "aa") => 0
(string-lessp "AA" "aa") => nil
Function: string-compare string1 string2 &optional (start1 0) (start2 0) end1 end2

Compares two strings using dictionary order (as defined by char-lessp). The arguments are interpreted as in string-equal. The result is 0 if the strings are equal, a negative number if string1 is less than string2, or a positive number if string1 is greater than string2. If the strings are not equal, the absolute value of the number returned is one greater than the index (in string1) where the first difference occurred.

Function: substring string start &optional end area

Extracts a substring of string, starting at the character specified by start and going up to but not including the character specified by end. start and end are 0-origin indices. The length of the returned string is end minus start. If end is not specified it defaults to the length of string. The area in which the result is to be consed may be optionally specified.

Example:
(substring "Nebuchadnezzar" 4 8) => "chad"
Function: nsubstring string start &optional end area

Is like substring except that the substring is not copied; instead an indirect array (see (indirect-array)) is created which shares part of the argument string. Modifying one string will modify the other.

Note that nsubstring does not necessarily use less storage than substring; an nsubstring of any length uses at least as much storage as a substring 12 characters long. So you shouldn’t use this for efficiency; it is intended for uses in which it is important to have a substring which, if modified, will cause the original string to be modified too.

Function: string-append &rest strings

Copies and concatenates any number of strings into a single string. With a single argument, string-append simply copies it. If there are no arguments, the value is an empty string. In fact, vectors of any type may be used as arguments, and the value is a vector capable of holding all the elements of all the arguments. Thus string-append can be used to copy and concatenate any type of vector. If the first argument is not an array (for example, if it is a character), the value is a string.

Example:
(string-append #\! "foo" #\!) => "!foo!"
Function: string-nconc modified-string &rest strings

Is like string-append except that instead of making a new string containing the concatenation of its arguments, string-nconc modifies its first argument. modified-string must have a fill-pointer so that additional characters can be tacked onto it. Compare this with array-push-extend ((array-push-extend-fun)). The value of string-nconc is modified-string or a new, longer copy of it; in the latter case the original copy is forwarded to the new copy (see adjust-array-size, (adjust-array-size-fun)). Unlike nconc, string-nconc with more than two arguments modifies only its first argument, not every argument but the last.

Function: string-trim char-set string

Returns a substring of string, with all characters in char-set stripped off the beginning and end. char-set is a set of characters, which can be represented as a list of characters, a string of characters or a single character.

Example:
(string-trim '(#\sp) "  Dr. No  ") => "Dr. No"
(string-trim "ab" "abbafooabb") => "foo"
Function: string-left-trim char-set string

Returns a substring of string, with all characters in char-set stripped off the beginning. char-set is a set of characters, which can be represented as a list of characters, a string of characters or a single character.

Function: string-right-trim char-set string

Returns a substring of string, with all characters in char-set stripped off the end. char-set is a set of characters, which can be represented as a list of characters, a string of characters or a single character.

Function: string-remove-fonts string

Returns a copy of string with each character truncated to 8 bits; that is, changed to font zero.

If string is an ordinary string of array type art-string, this does not change anything, but it makes a difference if string is an art-fat-string.

Function: string-reverse string
Function: string-nreverse string

Like reverse and nreverse, but on strings only (see (reverse-fun)). There is no longer any reason to use these functions except that they coerce numbers and symbols into strings like the other string functions.

Function: string-pluralize string

Returns a string containing the plural of the word in the argument string. Any added characters go in the same case as the last character of string.

Example:
(string-pluralize "event") => "events"
(string-pluralize "trufan") => "trufen"
(string-pluralize "Can") => "Cans"
(string-pluralize "key") => "keys"
(string-pluralize "TRY") => "TRIES"

For words with multiple plural forms depending on the meaning, string-pluralize cannot always do the right thing.

Function: string-select-a-or-an word

Returns "a" or "an" according to the string word; whichever one appears to be correct to use before word in English.

Function: string-append-a-or-an word

Returns the result of appending "a " or "an ", whichever is appropriate, to the front of word.

Function: %string-equal string1 start1 string2 start2 count

%string-equal is the microcode primitive used by string-equal. It returns t if the count characters of string1 starting at start1 are char-equal to the count characters of string2 starting at start2, or nil if the characters are not equal or if count runs off the length of either array.

Instead of a fixnum, count may also be nil. In this case, %string-equal compares the substring from start1 to (string-length string1) against the substring from start2 to (string-length string2). If the lengths of these substrings differ, then they are not equal and nil is returned.

Note that string1 and string2 must really be strings; the usual coercion of symbols and fixnums to strings is not performed. This function is documented because certain programs which require high efficiency and are willing to pay the price of less generality may want to use %string-equal in place of string-equal.

Examples:
To compare the two strings foo and bar:
(%string-equal foo 0 bar 0 nil)
To see if the string foo starts with the characters "bar":
(%string-equal foo 0 "bar" 0 3)
Variable: alphabetic-case-affects-string-comparison

If this variable is t, the functions %string-equal and %string-search consider case (and font) significant in comparing characters. Normally this variable is nil and those primitives ignore differences of case.

This variable may be bound by user programs around calls to %string-equal and %string-search-char, but do not set it globally, for that may cause system malfunctions.

10.4 String Searching

Function: string-search-char char string &optional (from 0) to consider-case

Searches through string starting at the index from, which defaults to the beginning, and returns the index of the first character that is char-equal to char, or nil if none is found. If to is non-nil, it is used in place of (string-length string) to limit the extent of the search.

Example:
(string-search-char #\a "banana") => 1

Case (and font) is significant in comparison of characters if consider-case is non-nil. In other words, characters are compared using char= rather than char-equal.

(string-search-char #\a "BAnana" 0 nil t) => 3
Function: %string-search-char char string from to

%string-search-char is the microcode primitive called by string-search-char and other functions. string must be an array and char, from, and to must be fixnums. The arguments are all required. Case-sensitivity is controlled by the value of the variable alphabetic-case-affects-string-comparison rather than by an argument. Except for these these differences, %string-search-char is the same as string-search-char. This function is documented for the benefit of those who require the maximum possible efficiency in string searching.

Function: string-search-not-char char string &optional (from 0) to consider-case

Like string-search-char but searches string for a character different from char.

Example:
(string-search-not-char #\B "banana") => 1
(string-search-not-char #\B "banana" 0 nil t) => 0
Function: string-search key string &optional (from 0) to (key-from 0) key-to consider-case

Searches for the string key in the string string. The search begins at from, which defaults to the beginning of string. The value returned is the index of the first character of the first instance of key, or nil if none is found. If to is non-nil, it is used in place of (string-length string) to limit the extent of the search.

The arguments key-from and key-to can be used to specify the portion of key to be searched for, rather than all of key.

Case and font are significant in character comparison if consider-case is non-nil.

Example:
(string-search "an" "banana") => 1
(string-search "an" "banana" 2) => 3
(string-search "tank" "banana" 2 nil 1 3) => 3
(string-search "an" "BAnaNA" 0 nil 0 nil t) => nil
Function: string-search-set char-set string &optional (from 0) to consider-case

Searches through string looking for a character that is in char-set. char-set is a set of characters, which can be represented as a sequence of characters or a single character.

The search begins at the index from, which defaults to the beginning. It returns the index of the first character that is char-equal to some element of char-set, or nil if none is found. If to is non-nil, it is used in place of (string-length string) to limit the extent of the search.

Case and font are significant in character comparison if consider-case is non-nil.

Example:
(string-search-set '(#\n #\o) "banana") => 2
(string-search-set "no" "banana") => 2
Function: string-search-not-set char-set string &optional (from 0) to consider-case

Like string-search-set but searches for a character that is not in char-set.

Example:
(string-search-not-set '(#\a #\b) "banana") => 2
Function: string-reverse-search-char char string &optional from (to 0) consider-case

Searches through string in reverse order, starting from the index one less than from (nil for from starts at the end of string), and returns the index of the first character which is char-equal to char, or nil if none is found. Note that the index returned is from the beginning of the string, although the search starts from the end. The last (leftmost) character of string examined is the one at index to.

Case and font are significant in character comparison if consider-case is non-nil. In this case, char= is used for the comparison rather than char-equal.

Example:
(string-reverse-search-char #\n "banana") => 4
Function: string-reverse-search-not-char char string &optional from (to 0) consider-case

Like string-reverse-search-char but searches for a character in string that is different from char.

Example:
(string-reverse-search-not-char #\a "banana") => 4
;4 is the index of the second "n"
Function: string-reverse-search key string &optional from (to 0) (key-from 0) key-to consider-case

Searches for the string key in the string string. The search proceeds in reverse order, starting from the index one less than from, and returns the index of the first (leftmost) character of the first instance found, or nil if none is found. Note that the index returned is from the beginning of the string, although the search starts from the end. The from condition, restated, is that the instance of key found is the rightmost one whose rightmost character is before the from’th character of string. nil for from means the search starts at the end of string. The last (leftmost) character of string examined is the one at index to.

Example:
(string-reverse-search "na" "banana") => 4

The arguments key-from and key-to can be used to specify the portion of key to be searched for, rather than all of key. Case and font are significant in character comparison if consider-case is non-nil.

Function: string-reverse-search-set char-set string &optional from (to 0) consider-case

Searches through string in reverse order for a character which is char-equal to some element of char-set. char-set is a set of characters, which can be represented as a list of characters, a string of characters or a single character.

The search starts from an index one less than from, and returns the index of the first suitable character found, or nil if none is found. nil for from means the search starts at the end of string. Note that the index returned is from the beginning of the string, although the search starts from the end. The last (leftmost) character of string examined is the one at index to.

Case and font are significant in character comparison if consider-case is non-nil. In this case, char= is used for the comparison rather than char-equal.

(string-reverse-search-set "ab" "banana") => 5
Function: string-reverse-search-not-set char-set string &optional from (to 0) consider-case

Like string-reverse-search-set but searches for a character which is not in char-set.

(string-reverse-search-not-set '(#\a #\n) "banana") => 0
Function: string-subst-char new-char old-char string (copy-p t) (retain-font-p t)

Returns a copy of string in which all occurrences of old-char have been replaced by new-char.

Case and font are ignored in comparing old-char against characters of string. Normally the font information of the character replaced is preserved, so that an old-char in font 3 is replaced by a new-char in font 3. If retain-font-p is nil, the font specified in new-char is stored whenever a character is replaced.

If copy-p is nil, string is modified destructively and returned. No copy is made.

Function: substring-after-char char string &optional start end area

Returns a copy of the portion of string that follows the next occurrence of char after index start. The portion copied ends at index end. If char is not found before end, a null string is returned.

The value is consed in area area, or in default-cons-area, unless it is a null string. start defaults to zero, and end to the length of string.

See also make-symbol ((make-symbol-fun)), which given a string makes a new uninterned symbol with that print name, and intern ((intern-fun)), which given a string returns the one and only symbol (in the current package) with that print name.

10.5 Maclisp-Compatible Functions

The following functions are provided primarily for Maclisp compatibility.

Function: alphalessp string1 string2

(alphalessp string1 string2) is equivalent to (string-lessp string1 string2).

Function: samepnamep sym1 sym2

This predicate is equivalent to string=.

Function: getchar string index

Returns the index’th character of string as a symbol. Note that 1-origin indexing is used. This function is mainly for Maclisp compatibility; aref should be used to index into strings (but aref does not coerce symbols or numbers into strings).

Function: getcharn string index

Returns the index’th character of string as a fixnum. Note that 1-origin indexing is used. This function is mainly for Maclisp compatibility; aref should be used to index into strings (but aref does not coerce symbols or numbers into strings).

Function: ascii x

Like character, but returns a symbol whose printname is the character instead of returning a fixnum.

Examples:
(ascii #o101) => A
(ascii #o56) => /.

The symbol returned is interned in the current package (see (package)).

Function: maknam char-list

Returns an uninterned symbol whose print-name is a string made up of the characters in char-list.

Example:
(maknam '(a b #\0 d)) => ab0d
Function: implode char-list

implode is like maknam except that the returned symbol is interned in the current package.

11 Functions

Functions are the basic building blocks of Lisp programs. This chapter describes the functions in Zetalisp that are used to manipulate functions. It also explains how to manipulate special forms and macros.

This chapter contains internal details intended for those writing programs to manipulate programs as well as material suitable for the beginner. Feel free to skip sections that look complicated or uninteresting when reading this for the first time.

11.1 What Is a Function?

There are many different kinds of functions in Zetalisp. Here are the printed representations of examples of some of them:

foo
(lambda (x) (car (last x)))
(named-lambda foo (x) (car (last (x))))
(subst (x) (car (last x)))
#<dtp-fef-pointer append 1424771>
#<dtp-u-entry last 270>
#<dtp-closure 1477464>

We will examine these and other types of functions in detail later in this chapter. There is one thing they all have in common: a function is a Lisp object that can be applied to arguments. All of the above objects may be applied to some arguments and will return a value. Functions are Lisp objects and so can be manipulated in all the usual ways; you can pass them as arguments, return them as values, and make other Lisp objects refer to them.

11.2 Function Specs

The name of a function does not have to be a symbol. Various kinds of lists describe other places where a function can be found. A Lisp object that describes a place to find a function is called a function spec. (‘Spec’ is short for ‘specification’.) Here are the printed representations of some typical function specs:

foo
(:property foo bar)
(:method tv:graphics-mixin :draw-line)
(:internal foo 1)
(:within foo bar)
(:location #<dtp-locative 7435216>)

Function specs have two purposes: they specify a place to remember a function, and they serve to name functions. The most common kind of function spec is a symbol, which specifies that the function cell of the symbol is the place to remember the function. We will see all the different types of function spec, and what they mean, shortly. Function specs are not the same thing as functions. You cannot, in general, apply a function spec to arguments. The time to use a function spec is when you want to do something to the function, such as define it, look at its definition, or compile it.

Some kinds of functions remember their own names, and some don’t. The “name” remembered by a function can be any kind of function spec, although it is usually a symbol. In the examples of functions in the previous section, the one starting with the symbol named-lambda, the one whose printed representation included dtp-fef-pointer, and the dtp-u-entry remembered names (the function specs foo, append, and last respectively). The others didn’t remember their names.

To define a function spec means to make that function spec remember a given function. Programs do this by calling fdefine; you give fdefine a function spec and a function, and fdefine remembers the function in the place specified by the function spec. The function associated with a function spec is called the definition of the function spec. A single function can be the definition of more than one function spec at the same time, or of no function specs.

The definition of a function spec can be obtained with fdefinition. (function function-spec) does so too, but here function-spec is not evaluated. For example, (function foo) evaluates to the function definition of foo. fdefinition is used by programs whose purpose is to examine function definitions, whereas function is used in this way by programs of all sorts to obtain a specific definition and use it. See (function-fun).

To define a function means to create a new function and define a given function spec as that new function. This is what the defun special form does. Several other special forms, such as defmethod ((defmethod-fun)) and defselect ((defselect-fun)), do this too.

These special forms that define functions usually take a function spec, create a function whose name is that function spec, and then define that function spec to be the newly-created function. Most function definitions are done this way, and so usually if you go to a function spec and see what function is there, the function’s name is the same as the function spec. However, if you define a function named foo with defun, and then define the symbol bar to be this same function, the name of the function is unaffected; both foo and bar are defined to be the same function, and the name of that function is foo, not bar.

A function spec’s definition in general consists of a basic definition surrounded by encapsulations. Both the basic definition and the encapsulations are functions, but of recognizably different kinds. What defun creates is a basic definition, and usually that is all there is. Encapsulations are made by function-altering functions such as trace, breakon and advise. When the function is called, the entire definition, which includes the tracing and advice, is used. If the function is redefined with defun, only the basic definition is changed; the encapsulations are left in place. See the section on encapsulations, (encapsulate).

A function spec is a Lisp object of one of the following types:

a symbol

The function is remembered in the function cell of the symbol. See (fsymeval-fun) for an explanation of function cells and the primitive functions to manipulate them.

(:property symbol property)

The function is remembered on the property list of the symbol; doing (get symbol property) returns the function. Storing functions on property lists is a frequently-used technique for dispatching (that is, deciding at run-time which function to call, on the basis of input data).

(:method flavor-name operation)
(:method flavor-name method-type operation)
(:method flavor-name method-type operation suboperation)

The function is remembered inside internal data structures of the flavor system and is called automatically as part of handling the operation operation on instances of flavor-name. See the chapter on flavors ((flavor)) for details.

(:handler flavor-name operation)

This is a name for the function actually called when an operation message is sent to an instance of the flavor flavor-name. The difference between :handler and :method is that the handler may be a method inherited from some other flavor or a combined method automatically written by the flavor system. Methods are what you define in source files; handlers are not. Note that redefining or encapsulating a handler affects only the named flavor, not any other flavors built out of it. Thus :handler function specs are often used with trace (see (trace-fun)), breakon ((breakon-fun)), and advise ((advise-fun)).

(:select-method function-spec operation)

This function spec assumes that the definition of function-spec is a select-method object (see (select-method)) containing an alist of operation names and functions to handle them, and refers to one particular element of that alist: the one for operation operation.

The function is remembered in that alist element and is called when function-spec’s definition is called with first argument operation.

:select-method function specs are most often used implicitly through defselect. One of the things done by

(defselect foo
  (:win (x) (cons 'win x))
  ...)

is to define the function spec (:select-method foo :win).

:select-method function specs are explicitly given function definitions when you use defselect-incremental instead of defselect, as in

(defselect-incremental foo)
(defun (:select-method foo :win) (ignore x)
  (cons 'win x))
(:lambda-macro name)

This is a name for the function that expands the lambda macro name.

(:location pointer)

The function is stored in the cdr of pointer, which may be a locative or a list. This is for pointing at an arbitrary place that there is no other way to describe. This form of function spec isn’t useful in defun (and related special forms) because the reader has no printed representation for locative pointers and always creates new lists; these function specs are intended for programs that manipulate functions (see (programs-that-manipulate-functions)).

(:within within-function function-to-affect)

This refers to the meaning of the symbol function-to-affect, but only where it occurs in the text of the definition of within-function. If you define this function spec as anything but the symbol function-to-affect itself, then that symbol is replaced throughout the definition of within-function by a new symbol, which is then defined as you specify. See the section on si:rename-within encapsulations ((rename-within-section)) for more information.

It is rarely useful to define a :within function spec by hand, but often useful to trace or advise one. For example,

(breakon '(:within myfunction eval))

allows you to break when eval is called from myfunction. Simply doing (breakon 'eval) will probably blow away your machine.

(:internal function-spec number)

Some Lisp functions contain internal functions, created by (function (lambda ...)) forms. These internal functions need names when compiled, but they do not have symbols as names; instead they are named by :internal function-specs. function-spec is the name of the containing function. number is a sequence number; the first internal function the compiler comes across in a given function is numbered 0, the next 1, etc. Internal functions are remembered inside the compiled function object of their containing function.

(:internal function-spec symbol)

If a Lisp function uses flet to name an internal function, you can use the local name defined with flet in the :internal function spec instead of a number. Here is an example of such a function:

(defun foo (a)
  (flet ((square (x) (* x x)))
    (+ a (square a))))

After compiling foo, you could use the function spec (:internal foo square) to refer to the internal function locally named square. You could also use (:internal foo 0). If there are multiple flet’s defining local functions with the same name, only the first can be referred to by name this way.

Here is an example defining a function whose name is not a symbol:

(defun (:property foo bar-maker) (thing &optional kind)
  (set-the 'bar thing (make-bar 'foo thing kind)))

This puts a function on foo’s bar-maker property. Now you can say

(funcall (get 'foo 'bar-maker) 'baz)
or
(funcall #'(:property foo bar-maker) 'bax)

Unlike the other kinds of function spec, a symbol can be used as a function. If you apply a symbol to arguments, the symbol’s function definition is used instead. If the definition of the first symbol is another symbol, the definition of the second symbol is used, and so on, any number of times. But this is an exception; in general, you can’t apply function specs to arguments.

A keyword symbol that identifies function specs (i.e., that may appear in the car of a list which is a function spec) is identified by a sys:function-spec-handler property whose value is a function that implements the various manipulations on function specs of that type. The interface to this function is internal and not documented in this manual.

For compatibility with Maclisp, the function-defining special forms defun, macro, and defselect (and other defining forms built out of them, such as defmacro) also accept a list

(symbol property)

as a function name. This is translated into

(:property symbol property)

symbol must not be one of the keyword symbols that identify a function spec, since that would be ambiguous.

11.3 Simple Function Definitions

Special Form: defun

The usual way of defining a function that is part of a program. A defun form looks like:

(defun name lambda-list
  body...)

name is the function spec you wish to define as a function. The lambda-list is a list of the names to give to the arguments of the function. Actually, it is a little more general than that; it can contain lambda-list keywords such as &optional and &rest. (These keywords are explained in (lambda-list) and other keywords are explained in (lambda-list-keywords).) See (additional-defun-explanation) for some additional syntactic features of defun.

defun creates a list that looks like

(named-lambda name lambda-list body...)

and puts it in the function cell of name. name is now defined as a function and can be called by other forms.

Examples:
(defun addone (x)
  (1+ x))

(defun foo (a &optional (b 5) c &rest e &aux j)
  (setq j (+ (addone a) b))
  (cond ((not (null c))
	 (cons j e))
	(t j))) 

addone is a function which expects a number as an argument, and returns a number one larger. foo is a complicated function that takes one required argument, two optional arguments, and any number of additional arguments that are given to the function as a list named e.

A declaration (a list starting with declare) can appear as the first element of the body. It applies to the entire function definition; if it is a special declaration, it applies to bindings made in the lambda list and to free references anywhere in the function. For example,

(defun foo (x)
  (declare (special x))
  (bar))             ;bar uses x free.

causes the binding of x to be a dynamic binding, and

(defun foo (&rest args)
  (declare (arglist a b c))
  (apply 'bar args))

causes (arglist 'foo) to return (a b c) rather than (&rest args), presumably because the former is more informative in the particular application.

A documentation string can also appear at the beginning of the body; it may precede or follow a declaration. This documentation string becomes part of the function’s debugging info and can be obtained with the function documentation (see (documentation-fun)). The first line of the string should be a complete sentence that makes sense read by itself, since there are two editor commands to get at the documentation, one of which is “brief” and prints only the first line. Example:

(defun my-append (&rest lists)
   "Like append but copies all the lists.
This is like the Lisp function append, except that
append copies all lists except the last, whereas
this function copies all of its arguments
including the last one."
   ...)

A documentation string may not be the last element of the body; a string in that position is interpreted as a form to evaluate and return and is not considered to be a documentation string.

For more information on defining functions, and other ways of doing so, see (function-defining).

11.4 User Operations on Functions

Here is a list of the various things a user (as opposed to a program) is likely to want to do to a function. In all cases, you specify a function spec to say where to find the function.

To print out the definition of the function spec with indentation to make it legible, use grindef (see (grindef-fun)). This works only for interpreted functions. If the definition is a compiled function, it can’t be printed out as Lisp code, but its compiled code can be printed by the disassemble function (see (disassemble-fun)).

To find out about how to call the function, you can ask to see its documentation or its argument names. (The argument names are usually chosen to have mnemonic significance for the caller). Use arglist ((arglist-fun)) to see the argument names and documentation ((documentation-fun)) to see the documentation string. There are also editor commands for doing these things: the Control-Shift-D and Meta-Shift-D commands are for looking at a function’s documentation, and Control-Shift-A is for looking at an argument list.

Control-Shift-A and Control-Shift-D do not ask for the function name; they act on the function that is called by the innermost expression which the cursor is inside. Usually this is the function that will be called by the form you are in the process of writing. They are available in the rubout handler as well.

You can see the function’s debugging info alist by means of the function debugging-info (see (debugging-info-fun)).

When you are debugging, you can use trace (see (trace-fun)) to obtain a printout or a break loop whenever the function is called. You can use breakon (see (breakon-fun)) to cause the error handler to be entered whenever the function is called; from there, you can step through further function calls and returns. You can customize the definition of the function, either temporarily or permanently, using advise (see (advise-fun)).

11.5 Kinds of Functions

There are many kinds of functions in Zetalisp. This section briefly describes each kind of function. Note that a function is also a piece of data and can be passed as an argument, returned, put in a list, and so forth.

There are four kinds of functions, classified by how they work.

First, there are interpreted functions: you define them with defun, they are represented as list structure, and they are interpreted by the Lisp evaluator.

Secondly, there are compiled functions: they are defined by compile or by loading a QFASL file, they are represented by a special Lisp data type, and they are executed directly by the microcode. Similar to compiled functions are microcode functions, which are written in microcode (either by hand or by the micro-compiler) and executed directly by the hardware.

Thirdly, there are various types of Lisp object that can be applied to arguments, but when they are applied they dig up another function somewhere and apply it instead. These include select-methods, closures, instances, and entities.

Finally, there are various types of Lisp object that, when called as functions, do something special related to the specific data type. These include arrays and stack-groups.

11.5.1 Interpreted Functions

An interpreted function is a piece of list structure that represents a program according to the rules of the Lisp interpreter. Unlike other kinds of functions, interpreted functions can be printed out and read back in (they have a printed representation that the reader understands), can be pretty-printed (see (grindef-fun)), and can be examined with the usual functions for list-structure manipulation.

There are four kinds of interpreted functions: lambdas, named-lambdas, substs, and named-substs. A lambda function is the simplest kind. It is a list that looks like this:

(lambda lambda-list form1 form2...)

The symbol lambda identifies this list as a lambda function. lambda-list is a description of what arguments the function takes; see (lambda-list) for details. The forms make up the body of the function. When the function is called, the argument variables are bound to the values of the arguments as described by lambda-list, and then the forms in the body are evaluated, one by one. The values of the function are the values of its last form.

A named-lambda is like a lambda but contains an extra element in which the system remembers the function’s name, documentation, and other information. Having the function’s name there allows the error handler and other tools to give the user more information. You would not normally write a named-lambda yourself; named-lambda exists so that defun can use it. A named-lambda function looks like this:

(named-lambda name lambda-list body forms...)

If the name slot contains a symbol, it is the function’s name. Otherwise it is a list whose car is the name and whose cdr is the function’s debugging information alist. (See debugging-info, (debugging-info-fun).) Note that the name need not be a symbol; it can be any function spec. For example,

(defun (foo bar) (x)
  (car (reverse x)))

gives foo a bar property whose value is

(named-lambda ((:property foo bar)) (x) (car (reverse x)))

A subst is a function which is open-coded by the compiler. A subst is just like a lambda as far as the interpreter is concerned. It is a list that looks like this:

(subst lambda-list form1 form2...)

The difference between a subst and a lambda is the way they are handled by the compiler. A call to a normal function is compiled as a closed subroutine; the compiler generates code to compute the values of the arguments and then apply the function to those values. A call to a subst is compiled as an open subroutine; the compiler incorporates the body forms of the subst into the function being compiled, substituting the argument forms for references to the variables in the subst’s lambda-list. subst’s are described more fully on (defsubst-fun), with the explanation of defsubst.

A named-subst is the same as a subst except that it has a name just as a named-lambda does. It looks like

(named-subst name lambda-list form1 form2 ...)

where name is interpreted the same way as in a named-lambda.

11.5.2 Lambda Macros

Lambda macros may appear in functions where lambda would have previously appeared. When the compiler or interpreter detects a function whose car is a lambda macro, they expand the macro in much the same way that ordinary Lisp macros are expanded–the lambda macro is called with the function as its argument and is expected to return another function as its value. The definition of a lambda macro (that is, the function which expands it) may be accessed with the (:lambda-macro name) function spec.

The value returned by the lambda macro expander function may be any valid function. Usually it is a list starting with lambda, subst, named-lambda or named-subst, but it could also be another use of a lambda macro, or even a compiled function.

Macro: lambda-macro name lambda-list &body body

By analogy with macro, defines a lambda macro to be called name. lambda-list should consist of one variable, which is bound to the function that caused the lambda macro to be called. The lambda macro must return a function. For example:

(lambda-macro ilisp (x)
  `(lambda (&optional ,@(second x) &rest ignore) . ,(cddr x)))

defines a lambda macro called ilisp which can be used to define functions that accept arguments like a standard Interlisp function: all arguments are optional and extra arguments are ignored. A typical use would be:

(fun-with-functional-arg #'(ilisp (x y z) (list x y z)))

This passes to fun-with-functional-arg a function which will ignore extra arguments beyond the third, and will default x, y and z to nil.

Macro: deflambda-macro

deflambda-macro is like defmacro, but defines a lambda macro instead of a normal macro. Here is how ilisp could be defined using deflambda-macro:

(deflambda-macro ilisp (argument-list &body body)
  `(lambda (&optional ,@argument-list &rest ignore) . ,body))
Macro: deffunction function-spec lambda-macro-name lambda-list &body body

Defines a function with a definition that uses an arbitrary lambda macro instead of lambda. It takes arguments like defun, expect that the argument immediatly following the function specifier is the name of the lambda macro to be used. deffunction expands the lambda macro immediatly, so the lambda macro must have been previously defined.

Example:

(deffunction some-interlisp-like-function ilisp (x y z)
  (list x y z))

would define a function called some-interlisp-like-function with the definition (ilisp (x y z) (list x y z)).

(defun foo ...) could be considered an abbreviation for (deffunction foo lambda ...)

11.5.3 Compiled Functions

There are two kinds of compiled functions: macrocoded functions and microcoded functions. The Lisp compiler converts lambda and named-lambda functions into macrocoded functions. A macrocoded function’s printed representation looks like:

#<dtp-fef-pointer append 1424771>

This type of Lisp object is also called a ‘Function Entry Frame’, or ‘FEF’ for short. Like ‘car’ and ‘cdr’, the name is historical in origin and doesn’t really mean anything. The object contains Lisp Machine machine code that does the computation expressed by the function; it also contains a description of the arguments accepted, any constants required, the name, documentation, and other things. Unlike Maclisp “subr-objects”, macrocoded functions are full-fledged objects and can be passed as arguments, stored in data structure, and applied to arguments.

The printed representation of a microcoded function looks like:

#<dtp-u-entry last 270>

Most microcompiled functions are basic Lisp primitives or subprimitives written in Lisp Machine microcode. You can also convert your own macrocode functions into microcode functions in some circumstances, using the micro-compiler.

11.5.4 Other Kinds of Functions

A closure is a kind of function that contains another function and a set of special variable bindings. When the closure is applied, it puts the bindings into effect and then applies the other function. When that returns, the closure bindings are removed. Closures are made with the function closure. See (closure) for more information. Entities are slightly different from closures; see (entity).

A select-method (internal type code dtp-select-method) contains an alist of symbols and functions. When one is called, the first argument is looked up in the alist to find the particular function to be called. This function is applied to the rest of the arguments. The alist may have a list of symbols in place of a symbol, in which case the associated function is called if the first argument is any of the symbols on the list. If cdr of last of the alist is non-nil, it is a default handler function, which gets called if the message key is not found in the alist. Select-methods can be created with the defselect special form (see (defselect-fun)). If the select-method is the definition of a function-spec, the individual functions in the alist can be referred to or defined using :select-method function specs (see (select-method-function-spec)).

An instance is a message-receiving object that has both a state and a table of message-handling functions (called methods). Refer to the chapter on flavors ((flavor)) for further information.

An array can be used as a function. The arguments to the array are the indices and the value is the contents of the element of the array. This is for Maclisp compatibility and is not recommended usage. Use aref ((aref-fun)) instead.

A stack group can be called as a function. This is one way to pass control to another stack group. See (stack-group).

11.5.5 Special Forms and Functions

The special forms of Zetalisp, such as quote, let and cond, are actually implemented with an unusual sort of function.

First, let’s restate the outline of how the evaluator works. When the evaluator is given a list whose first element is a symbol, the form may be a function form, a special form, or a macro form (see (description-of-evaluation)). If the definition of the symbol is a function, then the function is just applied to the result of evaluating the rest of the subforms. If the definition is a cons whose car is macro, then it is a macro form; these are explained in (macro). What about special forms?

A special form is implemented by a function that is flagged to tell the evaluator to refrain from evaluating some or all of the arguments to the function. Such functions make use of the lambda-list keyword &quote.

The evaluator, on seeing the &quote in the lambda list of an interpreted function (or something equivalent in a compiled function) skips the evaluation of the arguments to which the &quote applies. Aside from that, it calls the function normally.

For example, quote could be defined as

(defun quote (&quote arg) arg)

Evaluation of (quote x) would see the &quote in the definition, implying that the argument arg should not be evaluated. Therefore, the argument passed to the definition of quote would be the symbol x rather than the value of x. From then on, the definition of quote would execute in the normal fashion, so x would be the value of arg and x would be returned.

&quote applies to all the following arguments, but it can be cancelled with &eval. A simple setq that accepted only one variable and one value could be defined as follows:

(defun setq (&quote variable &eval value)
  (set variable value))

The actual definition of setq is more complicated and uses a lambda list (&quote &rest variables-and-values). Then it must go through the rest-argument, evaluating every other element.

The definitions of special forms are designed with the assumption that they will be called by eval. It does not usually make much sense to call one with funcall or apply. funcall and apply do not evaluate any arguments; they receive values of arguments, rather than expressions for them, and pass these values directly to the function to be called. There is no evaluation for funcall or apply to refrain from performing. Most special forms explicitly call eval on some of their arguments, or parts of them, and if called with apply or funcall they will still do so. This behavior is rarely useful, so calling special forms with apply or funcall should be avoided. Encapsulations can do this successfully, because they can arrange that quoted arguments are quoted also on entry to the encapsulation.

It is possible to define your own special form using &quote. Macros can also be used to accomplish the same thing. It is preferable to implement language extensions as macros rather than special forms, because macros directly define a Lisp-to-Lisp translation and therefore can be understood by both the interpreter and the compiler. Special forms, on the other hand, only extend the interpreter. The compiler has to be modified in an ad hoc way to understand each new special form so that code using it can be compiled. For example, it would not work for a compiled function to call the interpreted definition of setq; the set in that definition would not be able to act on local variables of the compiled function.

Since all real programs are eventually compiled, writing your own special functions is strongly discouraged. The purpose of &quote is to be used in the system’s own standard special forms.

New Lisp constructs in the system are also implemented as macros most of the time; macros are less work for us, too.

11.6 Function-Defining Special Forms

defun is a special form that is put in a program to define a function; defsubst and macro are others. This section explains how these special forms work, how they relate to the different kinds of functions, and how they interface to the rest of the function-manipulation system.

Function-defining special forms typically take as arguments a function spec and a description of the function to be made, usually in the form of a list of argument names and some forms that constitute the body of the function. They construct a function, give it the function spec as its name, and define the function spec to be the new function. Different special forms make different kinds of functions. defun makes a named-lambda function, and defsubst makes a named-subst function. macro makes a macro; though the macro definition is not really a function, it is like a function as far as definition handling is concerned.

These special forms are used in writing programs because the function names and bodies are constants. Programs that define functions usually want to compute the functions and their names, so they use fdefine. See (fdefine-fun).

All of these function-defining special forms alter only the basic definition of the function spec. Encapsulations are preserved. See (encapsulate).

The special forms only create interpreted functions. There is no special way of defining a compiled function. Compiled functions are made by compiling interpreted ones. The same special form that defines the interpreted function, when processed by the compiler, yields the compiled function. See (compiler) for details.

Note that the editor understands these and other “defining” special forms (e.g. defmethod, defvar, defmacro, defstruct, etc.) to some extent, so that when you ask for the definition of something, the editor can find it in its source file and show it to you. The general convention is that anything that is used at top level (not inside a function) and starts with def should be a special form for defining things and should be understood by the editor. defprop is an exception.

The defun special form (and the defunp macro which expands into a defun) are used for creating ordinary interpreted functions (see (defun-fun)).

For Maclisp compatibility, a type symbol may be inserted between name and lambda-list in the defun form. The following types are understood:

expr

The same as no type.

fexpr

&quote and &rest are prefixed to the lambda list.

macro

A macro is defined instead of a normal function.

If lambda-list is a non-nil symbol instead of a list, the function is recognized as a Maclisp lexpr and it is converted in such a way that the arg, setarg, and listify functions can be used to access its arguments (see (arg-fun)).

The defsubst special form is used to create substitutible functions. It is used just like defun but produces a list starting with named-subst instead of one starting with named-lambda. The named-subst function acts just like the corresponding named-lambda function when applied, but it can also be open-coded (incorporated into its callers) by the compiler. See (defsubst-fun) for full information.

The macro special form is the primitive means of creating a macro. It gives a function spec a definition that is a macro definition rather than a actual function. A macro is not a function because it cannot be applied, but it can appear as the car of a form to be evaluated. Most macros are created with the more powerful defmacro special form. See (macro).

The defselect special form defines a select-method function. See (defselect-fun).

Unlike the above special forms, the next two (deff and def) do not create new functions. They simply serve as hints to the editor that a function is being stored into a function spec here, and therefore if someone asks for the source code of the definition of that function spec, this is the place to look for it.

Special Form: def

If a function is created in some strange way, wrapping a def special form around the code that creates it informs the editor of the connection. The form

(def function-spec
  form1 form2...)

simply evaluates the forms form1, form2, etc. It is assumed that these forms will create or obtain a function somehow, and make it the definition of function-spec.

Alternatively, you could put (def function-spec) in front of or anywhere near the forms which define the function. The editor only uses it to tell which line to put the cursor on.

Special Form: deff function-spec definition-creator

deff is a simplified version of def. It evaluates the form definition-creator, which should produce a function, and makes that function the definition of function-spec, which is not evaluated. deff is used for giving a function spec a definition which is not obtainable with the specific defining forms such as defun. For example,

(deff foo 'bar)

makes foo equivalent to bar, with an indirection so that if bar changes foo will likewise change; conversely,

(deff foo (function bar))

copies the definition of bar into foo with no indirection, so that further changes to bar will have no effect on foo.

Special Form: deff-macro function-spec definition-creator

Is like deff (see (deff-fun)) but for defining macros. definition-creator is evaluated to produce a suitable definition-as-a-macro and then function-spec is defined that way. The definition-as-a-macro should be a cons whose car is macro and whose cdr is an expander function. Alternatively, a definition as a subst function can be used; either a list starting with subst or named-subst or a FEF which records it was compiled from such a list.

The difference between deff and deff-macro is that compile-file assumes that deff-macro is defining something which should be expanded during compilation. For the rest of the file, the macro defined here is available for expansion. When the file is ultimately loaded, or if compilation is done in-core, deff and deff-macro are equivalent.

Macro: @define

This macro turns into nil, doing nothing. It exists for the sake of the @ listing generation program, which uses it to declare names of special forms that define objects (such as functions) that @ should cross-reference.

Function: si:defun-compatibility x

This function is used by defun and the compiler to convert Maclisp-style lexpr, fexpr, and macro defuns to Zetalisp definitions. x should be the cdr of a (defun ...) form. defun-compatibility returns a corresponding (defun ...) or (macro ...) form, in the usual Zetalisp format. You shouldn’t ever need to call this yourself.

Special Form: defselect

defselect defines a function which is a select-method. This function contains a table of subfunctions; when it is called, the first argument, a symbol on the keyword package called the operation, is looked up in the table to determine which subfunction to call. Each subfunction can take a different number of arguments and have a different pattern of arguments. defselect is useful for a variety of “dispatching” jobs. By analogy with the more general message-passing facilities described in (flavor), the subfunctions are called methods and the list of arguments is sometimes called a message.

The special form looks like

(defselect (function-spec default-handler no-which-operations)
  (operation (args...)
        body...)
  (operation (args...)
        body...)
  ...)

function-spec is the name of the function to be defined. default-handler is optional; it must be a symbol and is a function which gets called if the select-method is called with an unknown operation. If default-handler is unsupplied or nil, then an unknown operation causes an error with condition name sys:unclaimed-message (see (sys:unclaimed-message-condition)).

Normally, methods for the operations :which-operations, :operation-handled-p and :send-if-handles are generated automatically based on the set of existing methods. These operations have the same meaning as they do on flavor instances; see (vanilla-flavor) for their definitions. If no-which-operations is non-nil, these methods are not created automatically; however, you can supply them yourself.

If function-spec is a symbol, and default-handler and no-which-operations are not supplied, then the first subform of the defselect may be just function-spec by itself, not enclosed in a list.

The remaining subforms in a defselect are the clauses, each defining one method. operation is the operation to be handled by this clause or a list of several operations to be handled by the same clause. args is a lambda-list; it should not include the first argument, which is the operation. body is the body of the function.

A clause can instead look like:

  (operation . symbol)

In this case, symbol is the name of a function that is to be called when the operation operation is performed. It will be called with the same arguments as the select-method, including the operation symbol itself.

The individual methods of the defselect can be examined, redefined, traced, etc. using :select-method function specs (see (select-method-function-spec)).

Special Form: defselect-incremental function-spec default-handler

defselect defines a select-method function all at once. By contrast, defselect-incremental defines an empty select-method to which methods can be added with defun.

Specifically, defselect-incremental function-spec, with just a default handler and the standard methods :which-operations, :operation-handled-p and :send-if-handles.

Individual methods are defined by using defun on a function spec of the form (:select-method function-spec operation). function-spec specifies where to find the select-method, and operation is the operation for which a method should be defined. The argument list of the defun must include a first argument which receives the operation name.

Example:
(defselect-incremental foo ignore)
   ;The function ignore is the default handler
(defun (:select-method foo :lose) (ignore a)
  (1+ a))
defines the same function foo as
(defselect (foo ignore)
  (:lose (a) (1+ a)))

These two examples are not completely equivalent, however. Reevaluating the defselect gets rid of any methods that used to exist but have been deleted from the defselect itself. Reevaluating the defselect-incremental has no such effect, and reevaluating an individual defun redefines only that method. Methods can be removed only with fundefine.

11.6.1 Maclisp Lexprs

Lexprs are the way Maclisp functions can accept variable numbers of arguments. They are supported for compatibility only; &optional and &rest are much preferable. A lexpr definition looks like

(defun foo nargs body...)

where a symbol (nargs, here) appears in place of a lambda-list. When the function is called, nargs is bound to the number of arguments it was given. The arguments themselves are accessed using the functions arg, setarg, and listify.

Function: arg x

(arg nil), when evaluated during the application of a lexpr, gives the number of arguments supplied to that lexpr. This is primarily a debugging aid, since lexprs also receive their number of arguments as the value of their lambda-variable.

(arg i), when evaluated during the application of a lexpr, gives the value of the i’th argument to the lexpr. i must be a fixnum in this case. It is an error if i is less than 1 or greater than the number of arguments supplied to the lexpr. Example:

(defun foo nargs            ;define a lexpr foo.
    (print (arg 2))         ;print the second argument.
    (+ (arg 1)              ;return the sum of the first
       (arg (- nargs 1))))  ;and next to last arguments.
Function: setarg i x

setarg is used only during the application of a lexpr. (setarg i x) sets the lexpr’s i’th argument to x. i must be greater than zero and not greater than the number of arguments passed to the lexpr. After (setarg i x) has been done, (arg i) returns x.

Function: listify n

(listify n) manufactures a list of n of the arguments of a lexpr. With a positive argument n, it returns a list of the first n arguments of the lexpr. With a negative argument n, it returns a list of the last (abs n) arguments of the lexpr. Basically, it works as if defined as follows:

(defun listify (n)
     (cond ((minusp n)
	    (listify1 (arg nil) (+ (arg nil) n 1)))
	   (t
	    (listify1 n 1))))

(defun listify1 (n m)      ; auxiliary function.
     (do ((i n (1- i))
	  (result nil (cons (arg i) result)))
	 ((< i m) result)))

11.7 How Programs Manipulate Function Specs

Function: fdefine function-spec definition &optional (carefully nil) (no-query nil)

This is the primitive used by defun and everything else in the system to change the definition of a function spec. If carefully is non-nil, which it usually should be, then only the basic definition is changed; the previous basic definition is saved if possible (see undefun, (undefun-fun)), and any encapsulations of the function such as tracing and advice are carried over from the old definition to the new definition. carefully also causes the user to be queried if the function spec is being redefined by a file different from the one that defined it originally. However, this warning is suppressed if either the argument no-query is non-nil, or if the global variable inhibit-fdefine-warnings is t.

If fdefine is called while a file is being loaded, it records what file the function definition came from so that the editor can find the source code.

If function-spec was already defined as a function, and carefully is non-nil, the function-spec’s :previous-definition property is used to save the previous definition. This property is used by the undefun function ((undefun-fun)), which restores the previous definition. The properties for different kinds of function specs are stored in different places; when a function spec is a symbol its properties are stored on the symbol’s property list.

defun and the other function-defining special forms all supply t for carefully and nil or nothing for no-query. Operations that construct encapsulations, such as trace, are the only ones which use nil for carefully.

Function: si:record-source-file-name name &optional (type defun) no-query

Records a definition of name, of type type. type should be defun to record a function definition; then name is a function spec. type can also be defvar, defflavor, defresource, defsignal or anything else you want to use.

The value of sys:fdefine-file-pathname is assumed to be the generic pathname of the file the definition is coming from, or nil if the definition is not from a file. If a definition of the same name and type has already been seen but not in the same file, and no-query is nil, a condition is signaled and then the user is queried.

If si:record-source-file-name returns nil, it means that the user or a condition handler said the redefinition should not be performed.

Variable: sys:fdefine-file-pathname

While the system is loading a file, this is the generic pathname for the file. The rest of the time it is nil. fdefine uses this to remember what file defines each function.

Function: si:get-source-file-name function-spec &optional type

Returns the generic pathname for the file in which function-spec received a definition of type type. If type is nil, the most recent definition is used, regardless of its type.

function-spec really is a function spec only if type is defun; for example, if type is defvar, function-spec is a variable name. Other types that are used by the system are defflavor and defstruct.

This function returns the generic pathname of the source file. To obtain the actual source file pathname, use the :source-pathname operation (see (pathname-source-pathname-method)).

A second value is returned, which is the type of the definition that was reported.

Function: si:get-all-source-file-names function-spec

Returns a list describing the generic pathnames of all the definitions this function-spec has received, of all types. The list is an alist whose elements look like

(type pathname...)
Condition Flavor: sys:redefinition (sys:warning)

This condition, which is not an error, is signaled by si:record-source-file-name when something is redefined by a different file. The handler for this condition can control what is done about the redefinition.

The condition instance provides the operations :name, :definition-type, :old-pathname and :new-pathname. :name and :definition-type return the name and type arguments to si:record-source-file-name. :old-pathname and :new-pathname return two generic pathnames saying where the old definition was and where this one is. The new pathname may be nil, meaning that the redefinition is being done by the user, not in any file.

Two proceed types are available, :proceed and :inhibit-definition. The first tells si:record-source-file-name to return t, the second tells it to return nil. If the condition is not handled at all, the user is queried or warned according to the value of inhibit-fdefine-warnings.

Variable: inhibit-fdefine-warnings

This variable is normally nil. Setting it to t prevents si:record-source-file-name from warning you and asking about questionable redefinitions such as a function being redefined by a different file than defined it originally, or a symbol that belongs to one package being defined by a file that belongs to a different package. Setting it to :just-warn allows the warnings to be printed out, but prevents the queries from happening; it assumes that your answer is ‘yes’, i.e. that it is all right to redefine the function.

Function: fset-carefully symbol definition &optional force-flag

This function is obsolete. It is equivalent to

(fdefine symbol definition t force-flag)
Function: fdefinedp function-spec

This returns t if function-spec has a definition, nil if it does not.

Function: fdefinition function-spec

This returns function-spec’s definition. If it has none, an error occurs.

Function: fdefinition-location function-spec

Equivalent to (locf (fdefinition function-spec)). For some kinds of function specs, though not for symbols, this (whichever way you write it) can cause data structure to be created to hold a definition. For example, if function-spec is of the :property kind, then an entry may have to be added to the property list if it isn’t already there.

Function: fundefine function-spec

Makes function-spec undefined; the cell where its definition is stored becomes void. For symbols this is equivalent to fmakunbound. If the function is encapsulated, fundefine removes both the basic definition and the encapsulations. Some types of function specs (:location for example) do not implement fundefine. fundefine on a :within function spec removes the replacement of function-to-affect, putting the definition of within-function back to its normal state. fundefine on a :method function spec removes the method completely, so that future messages will be handled by some other method (see the flavor chapter).

Function: undefun function-spec

If function-spec has a saved previous basic definition, this interchanges the current and previous basic definitions, leaving the encapsulations alone. If function-spec has no saved previous definition, undefun asks the user whether to make it undefined.

This undoes the effect of redefining a function. See also uncompile ((uncompile-fun)).

Function: si:function-spec-get function-spec indicator

Returns the value of the indicator property of function-spec, or nil if it doesn’t have such a property.

Function: si:function-spec-putprop function-spec value indicator

Gives function-spec an indicator property whose value is value.

Function: si:function-spec-lessp function-spec1 function-spec2

Compares the two function specs with an ordering that is useful in sorting lists of function specs for presentation to the user.

Function: si:function-parent function-spec

If function-spec does not have its own definition, textually speaking, but is defined as part of the definition of something else, this function returns the function spec for that something else. For example, if function-spec is an accessor function for a defstruct, the value returned is the name of the defstruct.

The intent is that if the caller has not been able to find the definition of function-spec in a more direct fashion, it can try looking for the definition of the function-parent of function-spec. This is used by the editor’s Meta-. command.

Condition: sys:invalid-function-spec (error)

This condition name belongs to the error signaled when you refer to a function spec that is syntactically invalid; such as, if it is a list whose car is not a recognized type of function spec.

The condition object supports the operation :function-spec, which returns the function spec which was invalid.

Note that in a few cases the condition :wrong-type-argument is signaled instead. These are the cases in which the error is correctable.

11.8 How Programs Examine Functions

These functions take a function as argument and return information about that function. Some also accept a function spec and operate on its definition. The others do not accept function specs in general but do accept a symbol as standing for its definition. (Note that a symbol is a function as well as a function spec).

The function documentation can be used to examine a function’s documentation string. See (documentation-fun).

Function: debugging-info function

This returns the debugging info alist of function, or nil if it has none.

Function: arglist function &optional real-flag

arglist is given a function or a function spec, and returns its best guess at the nature of the function’s lambda-list. It can also return a second value which is a list of descriptive names for the values returned by the function.

If function is a symbol, arglist of its function definition is used.

If the function is an actual lambda-expression, its cadr, the lambda-list, is returned. But if function is compiled, arglist attempts to reconstruct the lambda-list of the original definition, using whatever debugging information was saved by the compiler.

Some functions’ real argument lists are not what would be most descriptive to a user. A function may take a rest argument for technical reasons even though there are standard meanings for the first elements of that argument. For such cases, the definition of the function can specify, with a local declaration, a value to be returned when the user asks about the argument list. Example:

(defun foo (&rest rest-arg)
  (declare (arglist x y &rest z))
  .....)

real-flag has one of three values:

nil

Return the arglist declared by the user in preference to the actual one.

t

Return the actual arglist as computed from the function definition’s handling of arguments, ignoring any arglist declaration. For a compiled function, this omits all keyword arguments (replacing them with a rest argument) and may replace initial values of optional arguments with si:*hairy* if the actual expressions are too complicated.

compile

Like nil, but in the case of a compiled function it returns the actual arglist of the lambda-expression that was originally compiled. The compiler uses this as a basis for checking for incorrect calls to the function.

Programs interested in how many and what kind (evaluated or quoted) of arguments to pass should use args-info instead.

When a function returns multiple values, it is useful to give the values names so that the caller can be reminded which value is which. By means of a return-list declaration in the function’s definition, entirely analogous to the arglist declaration above, you can specify a list of mnemonic names for the returned values. This list is then returned by arglist as the second value.

(arglist 'arglist)
  => (function &optional real-flag) and (arglist return-list)
Function: function-name function &optional try-flavor-name

Returns the name of the function function, if that can be determined. If function does not describe what its name is, function itself is returned.

If try-flavor-name is non-nil, then if function is a flavor instance (which can, after all, be used as a function), then the flavor name is returned. If the optional argument is nil, flavor instances are treated as anonymous.

Function: eh:arg-name function arg-number

Returns the name of argument number arg-number in function function. Returns nil if the function doesn’t have such an argument, or if the name is not recorded. &rest arguments are not obtained with arg-number; use rest-arg-name to obtain the name of function’s &rest argument, if any.

Function: eh:rest-arg-name function

Returns the name of the rest argument of function function, or nil if function does not have one.

Function: eh:local-name function local-number

Returns the name of local variable number local-number in function function. If local-number is zero, this gets the name of the rest arg in any function that accepts a rest arg. Returns nil if the function doesn’t have such a local.

Function: args-info function

Returns a fixnum called the “numeric argument descriptor” of the function, which describes the way the function takes arguments. This descriptor is used internally by the microcode, the evaluator, and the compiler. function can be a function or a function spec.

The information is stored in various bits and byte fields in the fixnum, which are referenced by the symbolic names shown below. By the usual Lisp Machine convention, those starting with a single ‘%’ are bit-masks (meant to be logand’ed or bit-test’ed with the number), and those starting with ‘%%’ are byte specifiers, meant to be used with ldb or ldb-test.

Here are the fields:

%%arg-desc-min-args

’vindex %%arg-desc-min-args This is the minimum number of arguments that may be passed to this function, i.e. the number of required parameters.

%%arg-desc-max-args

’vindex %%arg-desc-max-args This is the maximum number of arguments that may be passed to this function, i.e. the sum of the number of required parameters and the number of optional parameters. If there is a rest argument, this is not really the maximum number of arguments that may be passed; an arbitrarily-large number of arguments is permitted, subject to limitations on the maximum size of a stack frame (about 200 words).

%arg-desc-evaled-rest

’vindex %arg-desc-evaled-rest If this bit is set, the function has a rest argument, and it is not quoted.

%arg-desc-quoted-rest

’vindex %arg-desc-quoted-rest If this bit is set, the function has a rest argument, and it is quoted. Most special forms have this bit.

%arg-desc-fef-quote-hair

’vindex %arg-desc-fef-quote-hair If this bit is set, there are some quoted arguments other than the rest argument (if any), and the pattern of quoting is too complicated to describe here. The ADL (Argument Description List) in the FEF should be consulted. This is only for special forms.

%arg-desc-interpreted

’vindex %arg-desc-interpreted This function is not a compiled-code object, and a numeric argument descriptor cannot be computed. Usually args-info does not return this bit, although %args-info does.

%arg-desc-fef-bind-hair

’vindex %arg-desc-fef-bind-hair There is argument initialization, or something else too complicated to describe here. The ADL (Argument Description List) in the FEF should be consulted.

Note that %arg-desc-quoted-rest and %arg-desc-evaled-rest cannot both be set.

Function: %args-info function

This is an internal function; it is like args-info but does not work for interpreted functions. Also, function must be a function, not a function spec. It exists because it has to be in the microcode anyway, for apply and the basic function-calling mechanism.

11.9 Encapsulations

The definition of a function spec actually has two parts: the basic definition, and encapsulations. The basic definition is what is created by functions like defun, and encapsulations are additions made by trace or advise to the basic definition. The purpose of making the encapsulation a separate object is to keep track of what was made by defun and what was made by trace. If defun is done a second time, it replaces the old basic definition with a new one while leaving the encapsulations alone.

Only advanced users should ever need to use encapsulations directly via the primitives explained in this section. The most common things to do with encapsulations are provided as higher-level, easier-to-use features: trace (see (trace-fun)), breakon (see (breakon-fun)) and advise (see (advise-fun)).

The actual definition of the function spec is the outermost encapsulation; this contains the next encapsulation, and so on. The innermost encapsulation contains the basic definition. The way this containing is done is as follows. An encapsulation is actually a function whose debugging info alist contains an element of the form

(si:encapsulated-definition uninterned-symbol encapsulation-type)

The presence of such an element in the debugging info alist is how you recognize a function to be an encapsulation. An encapsulation is usually an interpreted function (a list starting with named-lambda) but it can be a compiled function also, if the application which created it wants to compile it.

uninterned-symbol’s function definition is the thing that the encapsulation contains, usually the basic definition of the function spec. Or it can be another encapsulation, which has in it another debugging info item containing another uninterned symbol. Eventually you get to a function which is not an encapsulation; it does not have the sort of debugging info item which encapsulations all have. That function is the basic definition of the function spec.

Literally speaking, the definition of the function spec is the outermost encapsulation, period. The basic definition is not the definition. If you are asking for the definition of the function spec because you want to apply it, the outermost encapsulation is exactly what you want. But the basic definition can be found mechanically from the definition, by following the debugging info alists. So it makes sense to think of it as a part of the definition. In regard to the function-defining special forms such as defun, it is convenient to think of the encapsulations as connecting between the function spec and its basic definition.

An encapsulation is created with the macro si:encapsulate.

Macro: si:encapsulate

A call to si:encapsulate looks like

(si:encapsulate function-spec outer-function type
	     body-form
	     extra-debugging-info)

All the subforms of this macro are evaluated. In fact, the macro could almost be replaced with an ordinary function, except for the way body-form is handled.

function-spec evaluates to the function spec whose definition the new encapsulation should become. outer-function is another function spec, which should often be the same one. Its only purpose is to be used in any error messages from si:encapsulate.

type evaluates to a symbol which identifies the purpose of the encapsulation and says what the application is. For example, that could be advise or trace. The list of possible types is defined by the system because encapsulations are supposed to be kept in an order according to their type (see si:encapsulation-standard-order, (si:encapsulation-standard-order-var)). type should have an si:encapsulation-grind-function property which tells grindef what to do with an encapsulation of this type.

body-form evaluates to the body of the encapsulation-definition, the code to be executed when it is called. Backquote is typically used for this expression; see (backquote). si:encapsulate is a macro because, while body is being evaluated, the variable si:encapsulated-function is bound to a list of the form (function uninterned-symbol), referring to the uninterned symbol used to hold the prior definition of function-spec. If si:encapsulate were a function, body-form would just get evaluated normally by the evaluator before si:encapsulate ever got invoked, and so there would be no opportunity to bind si:encapsulated-function. The form body-form should contain `(apply ,si:encapsulated-function arglist) somewhere if the encapsulation is to live up to its name and truly serve to encapsulate the original definition. (The variable arglist is bound by some of the code which the si:encapsulate macro produces automatically. When the body of the encapsulation is run arglist’s value will be the list of the arguments which the encapsulation received.)

extra-debugging-info evaluates to a list of extra items to put into the debugging info alist of the encapsulation function (besides the one starting with si:encapsulated-definition, which every encapsulation must have). Some applications find this useful for recording information about the encapsulation for their own later use.

If compile-encapsulations-flag is non-nil, the encapsulation is compiled before it is installed. The encapsulations on a particular function spec can be compiled by calling compile-encapsulations. See (compile-encapsulations-fun). Compiled encapsulations can still be unencapsulated since the information needed to do so is stored in the debugging info alist, which is preserved by compilation. However, applications which wish to modify the code of the encapsulations they previously created must check for encapsulations that have been compiled and uncompile them. This can be done by finding the sys:interpreted-definition entry in the debugging info alist, which is present in all compiled functions except those made by file-to-file compilation.

When a special function is encapsulated, the encapsulation is itself a special function with the same argument quoting pattern. Therefore, when the outermost encapsulation is started, each argument has been evaluated or not as appropriate. Because each encapsulation calls the prior definition with apply, no further evaluation takes place, and the basic definition of the special form also finds the arguments evaluated or not as appropriate. The basic definition may call eval on some of these arguments or parts of them; the encapsulations should not.

Macros cannot be encapsulated, but their expander functions can be; if the definition of function-spec is a macro, then si:encapsulate automatically encapsulates the expander function instead. In this case, the definition of the uninterned symbol is the original macro definition, not just the original expander function. It would not work for the encapsulation to apply the macro definition. So during the evaluation of body-form, si:encapsulated-function is bound to the form (cdr (function uninterned-symbol)), which extracts the expander function from the prior definition of the macro.

Because only the expander function is actually encapsulated, the encapsulation does not see the evaluation or execution of the expansion itself. The value returned by the encapsulation is the expansion of the macro call, not the value computed by the expansion.

A program which creates encapsulations often needs to examine an encapsulation it created and find the body. For example, adding a second piece of advice to one function requires doing this. The proper way to do it is to use si:encapsulation-body.

Function: si:encapsulation-body encapsulation

Returns a list whose car is the body-form of encapsulation. It is the form that was the fourth argument of si:encapsulate when encapsulation was created. To illustrate this relationship,

(si:encapsulate 'foo 'foo 'trace 'body))

(si:encapsulation-body (fdefinition 'foo))
  => (body)

It is possible for one function to have multiple encapsulations, created by different subsystems. In this case, the order of encapsulations is independent of the order in which they were made. It depends instead on their types. All possible encapsulation types have a total order and a new encapsulation is put in the right place among the existing encapsulations according to its type and their types.

Variable: si:encapsulation-standard-order

The value of this variable is a list of the allowed encapsulation types, in the order in which the encapsulations are supposed to be kept (innermost encapsulations first). If you want to add new kinds of encapsulations, you should add another symbol to this list. Initially its value is

(advise breakon trace si:rename-within)

advise encapsulations are used to hold advice (see (advise-fun)). breakon encapsulations are used for implementing breakon (see (breakon-fun)). trace encapsulations are used for implementing tracing (see (trace-fun)). si:rename-within encapsulations are used to record the fact that function specs of the form (:within within-function altered-function) have been defined. The encapsulation goes on within-function (see (rename-within-section) for more information).

Every symbol used as an encapsulation type must be on the list si:encapsulation-standard-order. In addition, it should have an si:encapsulation-grind-function property whose value is a function that grindef will call to process encapsulations of that type. This function need not take care of printing the encapsulated function because grindef will do that itself. But it should print any information about the encapsulation itself which the user ought to see. Refer to the code for the grind function for advise to see how to write one.

To find the right place in the ordering to insert a new encapsulation, it is necessary to parse existing ones. This is done with the function si:unencapsulate-function-spec.

Function: si:unencapsulate-function-spec function-spec &optional encapsulation-types

This takes one function spec and returns another. If the original function spec is undefined, or has only a basic definition (that is, its definition is not an encapsulation), then the original function spec is returned unchanged.

If the definition of function-spec is an encapsulation, then its debugging info is examined to find the uninterned symbol that holds the encapsulated definition and the encapsulation type. If the encapsulation is of a type that is to be skipped over, the uninterned symbol replaces the original function spec and the process repeats.

The value returned is the uninterned symbol from inside the last encapsulation skipped. This uninterned symbol is the first one that does not have a definition that is an encapsulation that should be skipped. Or the value can be function-spec if function-spec’s definition is not an encapsulation that should be skipped.

The types of encapsulations to be skipped over are specified by encapsulation-types. This can be a list of the types to be skipped, or nil meaning skip all encapsulations (this is the default). Skipping all encapsulations means returning the uninterned symbol that holds the basic definition of function-spec. That is, the definition of the function spec returned is the basic definition of the function spec supplied. Thus,

(fdefinition (si:unencapsulate-function-spec 'foo))

returns the basic definition of foo, and

(fdefine (si:unencapsulate-function-spec 'foo) 'bar)

sets the basic definition (just like using fdefine with carefully supplied as t).

encapsulation-types can also be a symbol, which should be an encapsulation type; then we skip all types that are supposed to come outside of the specified type. For example, if encapsulation-types is trace, then we skip all types of encapsulations that come outside of trace encapsulations, but we do not skip trace encapsulations themselves. The result is a function spec that is where the trace encapsulation ought to be, if there is one. Either the definition of this function spec is a trace encapsulation, or there is no trace encapsulation anywhere in the definition of function-spec, and this function spec is where it would belong if there were one. For example,

(let ((tem (si:unencapsulate-function-spec spec 'trace)))
  (and (eq tem (si:unencapsulate-function-spec tem '(trace)))
       (si:encapsulate tem spec 'trace `(...body...))))

finds the place where a trace encapsulation ought to go and makes one unless there is already one there.

(let ((tem (si:unencapsulate-function-spec spec 'trace)))
  (fdefine tem (fdefinition (si:unencapsulate-function-spec
				tem '(trace)))))

eliminates any trace encapsulation by replacing it by whatever it encapsulates. (If there is no trace encapsulation, this code changes nothing.)

These examples show how a subsystem can insert its own type of encapsulation in the proper sequence without knowing the names of any other types of encapsulations. Only the variable si:encapsulation-standard-order, which is used by si:unencapsulate-function-spec, knows the order.

11.9.1 Rename-Within Encapsulations

One special kind of encapsulation is the type si:rename-within. This encapsulation goes around a definition in which renamings of functions have been done.

How is this used?

If you define, advise, or trace (:within foo bar), then bar gets renamed to #:altered-bar-within-foo wherever it is called from foo, and foo gets a si:rename-within encapsulation to record the fact. The purpose of the encapsulation is to enable various parts of the system to do what seems natural to the user. For example, grindef (see (grindef-fun)) notices the encapsulation, and so knows to print bar instead of #:altered-bar-within-foo when grinding the definition of foo.

Also, if you redefine foo, or trace or advise it, the new definition gets the same renaming done (bar replaced by #:altered-bar-within-foo). To make this work, everyone who alters part of a function definition should pass the new part of the definition through the function si:rename-within-new-definition-maybe.

Function: si:rename-within-new-definition-maybe function-spec new-structure

Given new-structure, which is going to become a part of the definition of function-spec, perform on it the replacements described by the si:rename-within encapsulation in the definition of function-spec, if there is one. The altered (copied) list structure is returned.

It is not necessary to call this function yourself when you replace the basic definition because fdefine with carefully supplied as t does it for you. si:encapsulate does this to the body of the new encapsulation. So you only need to call si:rename-within-new-definition-maybe yourself if you are rplac’ing part of the definition.

For proper results, function-spec must be the outer-level function spec. That is, the value returned by si:unencapsulate-function-spec is not the right thing to use. It will have had one or more encapsulations stripped off, including the si:rename-within encapsulation if any, and so no renamings will be done.

12 Closures

A closure is a type of Lisp functional object useful for implementing certain advanced access and control structures. Closures give you more explicit control over the environment by allowing you to save the dynamic bindings of specified variables and then to refer to those bindings later, even after the construct (let, etc.) which made the bindings has been exited.

12.1 What a Closure Is

There is a view of dynamic variable binding that we use in this section because it makes it easier to explain what closures do. In this view, when a variable is bound dynamically, a new binding is created for it. The old binding is saved away somewhere and is inaccessible. Any references to the variable then get the contents of the new binding, and any setq’s change the contents of the new value cell. Evantually the new binding goes away, and the old binding, along with its contents, becomes current again.

For example, consider the following sequence of Lisp forms:

(defvar a 3)		; a becomes 3.

(let ((a 10))		; a rebound to 10.
  (print (+ a 6)))      ; 16 is printed.

(print a)		; 3 is printed.

Initially there is a binding for a, and the setq form makes the contents of that binding be 3. Then the lambda-combination is evaluated. a is bound to 10: the old binding, which still contains 3, is saved away, and a new binding is created with 10 as its contents. The reference to a inside the lambda expression evaluates to the current binding of a, which is the contents of its current binding, namely 10. So 16 is printed. Then the newer binding is discarded and the old binding, which still contains a 3, is restored. The final print prints 3.

The form (closure var-list function), where var-list is a list of variables and function is any function, creates and returns a closure. When this closure is applied to some arguments, all of the bindings of the variables on var-list are saved away, and the bindings that those variables had at the time closure was called (that is, at the time the closure was created) are made to be the bindings of the symbols. Then function is applied to the arguments. (This paragraph is somewhat complex, but it completely describes the operation of closures; if you don’t understand it, come back and read it again after reading the next two paragraphs.)

Here is another, lower-level explanation. The closure object stores several things inside it. First, it saves the function. Secondly, for each variable in var-list, it remembers what that variable’s binding was when the closure was created. Then when the closure is called as a function, it first temporarily restores the bindings it has remembered inside the closure, and then applies function to the same arguments to which the closure itself was applied. When the function returns, the bindings are restored to be as they were before the closure was called.

Now, if we evaluate the form

(setq a 
      (let ((x 3))
	(declare (special x))
	(closure '(x) 'frob)))

what happens is that a new binding is created for x, containing a fixnum 3. Then a closure is created, which remembers the function frob, the symbol x, and that binding. Finally the old binding of x is restored, and the closure is returned. Notice that the new binding is still around, because it is still known about by the closure. When the closure is applied, say by doing (funcall a 7), this binding is temporarily restored and the value of x is 3 again. If frob uses x as a free variable, it sees 3 as the value.

A closure can be made around any function, using any form that evaluates to a function. The form could evaluate to a compiled function, as would (function (lambda () x)). In the example above, the form is 'frob and it evaluates to the symbol frob. A symbol is also a good function. It is usually better to close around a symbol that is the name of the desired function, so that the closure points to the symbol. Then, if the symbol is redefined, the closure will use the new definition. If you actually prefer that the closure continue to use the old definition that was current when the closure was made, use function, as in:

(closure '(x) (function frob))

Explicit closures made with closure record only the dynamic bindings of the specified variables. Another closure mechanism is activated automatically to record lexical bindings whenever function is used around an explicit lambda expression, but closure itself has no interaction with lexical bindings.

It is the user’s responsibility to make sure that the bindings that the closure is intended to record are dynamic bindings, either by means of special declarations (see (declare-fun)) as shown above or by making the variables globally special with defvar or equivalent. If the function closed over is an explicit lambda expression, it is occasionally necessary to use declarations within it to make sure that the variables are considered special there. But this is not needed if the variables are globally special or if a special declaration is lexically visible where closure is called.

Usually the compiler can tell when a special declaration is missing, but when making a closure the compiler detects this only after acting on the assumption that the variable is lexical, by which time it is too late to fix things. The compiler warns you if this happens.

In Zetalisp’s implementation of closures, lambda-binding never really allocates any storage to create new bindings. Bindings receive separate storage only when the closure function itself finds they need it. Thus, there is no cost associated with closures when they are not in use.

Zetalisp closures differ from the closures of Lisp 1.5 (which were made with function) in that they save specific variables rather than the entire variable-binding environment. For their intended applications, this is an advantage. The explicit declaration of the variables in closure permits higher efficiency and more flexibility. In addition the program is clearer because the intended effect of the closure is made manifest by listing the variables to be affected. Lisp 1.5 closures are more similar to Zetalisp’s automatic handling of lexical variables.

Closure implementation (which it not usually necessary for you to understand) involves two kinds of value cells. Every symbol has an internal value cell, part of the symbol itself, which is where its dynamic value is normally stored. When a variable is closed over, it gets an external value cell to hold its value. The external value cells behave according to the lambda-binding model used earlier in this section. The value in the external value cell is found through the usual access mechanisms (such as evaluating the symbol, calling symeval, etc.), because the internal value cell is made to contain a forwarding pointer to the external value cell that is current. Such a forwarding pointer is present in a symbol’s value cell whenever its current binding is being remembered by some closure; at other times, there won’t be an invisible pointer, and the value resides directly in the symbol’s internal value cell.

12.2 Examples of the Use of Closures

One thing we can do with closures is to implement a generator, which is a kind of function which is called successively to obtain successive elements of a sequence. We implement a function make-list-generator, which takes a list and returns a generator that returns successive elements of the list. When it gets to the end it should return nil.

The problem is that in between calls to the generator, the generator must somehow remember where it is up to in the list. Since all of its bindings are undone when it is exited, it cannot save this information in a bound variable. It could save it in a global variable, but the problem is that if we want to have more than one list generator at a time, they will all try to use the same global variable and get in each other’s way.

Here is how to solve this problem using closures:

(defun make-list-generator (l)
    (declare (special l))
    (closure '(l)
	     #'(lambda ()
		 (prog1 (car l)
		        (setq l (cdr l))))))

(make-list-generator '(1 2 3)) returns a generator which, on successive calls, returns 1, 2, 3, and nil.

Now we can make as many list generators as we like; they won’t get in each other’s way because each has its own binding for l. Each of these bindings was created when the make-list-generator function was entered, and the bindings are remembered by the closures.

The following example uses closures which share bindings:

(defvar a)
(defvar b)

(defun foo () (setq a 5))

(defun bar () (cons a b))

(let ((a 1) (b 1))
   (setq x (closure '(a b) 'foo))
   (setq y (closure '(a b) 'bar)))

When the let is entered, new bindings are created for the symbols a and b, and two closures are created that both point to those bindings. If we do (funcall x), the function foo is be run, and it changes the contents of the remembered binding of a to 5. If we then do (funcall y), the function bar returns (5 . 1). This shows that the binding of a seen by the closure y is the same binding seen by the closure x. The top-level binding of a is unaffected.

Here is how we can create a function that prints always using base 16:

(deff print-in-base-16
      (let ((*print-base* 16.))
        (closure '(*print-base*) 'print)))

12.3 Closure-Manipulating Functions

Function: closure var-list function

Creates and returns a closure of function over the variables in var-list. Note that all variables on var-list must be declared special if the function is to compile correctly.

To test whether an object is a closure, use the closurep predicate (see (closurep-fun)) or (typep object 'closure).

Function: symeval-in-closure closure symbol

Returns the binding of symbol in the environment of closure; that is, it returns what you would get if you restored the bindings known about by closure and then evaluated symbol. This allows you to “look around inside” a closure. If symbol is not closed over by closure, this is just like symeval.

symbol may be a locative pointing to a value cell instead of a symbol (this goes for all the whatever-in-closure functions).

Function: set-in-closure closure symbol x

Sets the binding of symbol in the environment of closure to x; that is, it does what would happen if you restored the bindings known about by closure and then set symbol to x. This allows you to change the contents of the bindings known about by a closure. If symbol is not closed over by closure, this is just like set.

Function: locate-in-closure closure symbol

Returns the location of the place in closure where the saved value of symbol is stored. An equivalent form is (locf (symeval-in-closure closure symbol)).

Function: boundp-in-closure closure symbol

Returns t if symbol’s binding in closure is not void. This is what (boundp symbol) would return if executed in closure’s saved environment.

Function: makunbound-in-closure closure symbol

Makes symbol’s binding in closure be void. This is what (makunbound symbol) would do if executed in closure’s saved environment.

Function: closure-alist closure

Returns an alist of (symbol . value) pairs describing the bindings that the closure performs when it is called. This list is not the same one that is actually stored in the closure; that one contains pointers to value cells rather than symbols, and closure-alist translates them back to symbols so you can understand them. As a result, clobbering part of this list does not change the closure.

The list that is returned may contain void cells if some of the closed-over variables were void in the closure’s environment. In this case, printing the value will get an error (accessing a cell that contains a void marker is always an error unless done in a special, careful way) but the value can still be passed around.

Function: closure-variables closure

Returns a list of variables closed over in closure. This is equal to the first argument specified to the function closure when this closure was created.

Function: closure-function closure

Returns the closed function from closure. This is the function that was the second argument to closure when the closure was created.

Function: closure-bindings closure

Returns the actual list of bindings to be performed when closure is entered. This list can be passed to sys:%using-binding-instances to enter the closure’s environment without calling the closure. See (sys:%using-binding-instances-fun).

Function: copy-closure closure

Returns a new closure that has the same function and variable values as closure. The bindings are not shared between the old closure and the new one, so that if the old closure changes some closed variable’s values, the values in the new closure do not change.

Macro: let-closed ((variable value)...) function

When using closures, it is very common to bind a set of variables with initial values only in order to make a closure over those variables. Furthermore, the variables must be declared special. let-closed is a special form which does all of this. It is best described by example:

(let-closed ((a 5) b (c 'x))
   (function (lambda () ...)))
macro-expands into
(let ((a 5) b (c 'x))
  (declare (special a b c))
  (closure '(a b c)
    (function (lambda () ...))))

Note that the following code, which would often be useful, does not work as intended if x is not special outside the let-closed:

(let-closed ((x x))
  (function ...))

This is because the reference to x as an initialization for the new binding of x is affected by the special declaration that the let-closed produces. It therefore does not see any lexical binding of x. This behavior is unfortunate, but it is required by the Common Lisp specifications. To avoid the problem, write

(let ((y x))
  (let-closed ((x y))
    (function ...)))

or simply change the name of the variable outside the let-closed to something other than x.

12.4 Entities

An entity is almost the same thing as a closure; an entity behaves just like a closure when applied, but it has a recognizably different data type which allows certain parts of the system such as the printer and describe to treat it differently. A closure is simply a kind of function, but an entity is assumed to be a message-receiving object. Thus, when the Lisp printer (see (printer)) is given a closure, it prints a simple textual representation, but when it is handed an entity, it sends the entity a :print-self message, which the entity is expected to handle. The describe function (see (describe-fun)) also sends entities messages when it is handed them. So when you want to make a message-receiving object out of a closure, as described on (entity-usage), you should use an entity instead.

To a large degree, entities are made obsolete by flavors (see (flavor)). Flavors have had considerably more attention paid to their efficiency and to good tools for using them. If what you are doing is flavor-like, it is better to use flavors.

Function: entity variable-list function

Returns a newly constructed entity. This function is just like the function closure except that it returns an entity instead of a closure.

The function argument should be a symbol which has a function definition and a value. When typep is applied to this entity, it returns the value of that symbol.

To test whether an object is an entity, use the entityp predicate (see (entityp-fun)). The functions symeval-in-closure, closure-alist, closure-function, etc. also operate on entities.

13 Stack Groups

A stack group (usually abbreviated ‘SG’) is a type of Lisp object useful for implementation of certain advanced control structures such as coroutines and generators. Processes, which are a kind of coroutine, are built on top of stack groups (see (process)). A stack group represents a computation and its internal state, including the Lisp stack.

At any time, the computation being performed by the Lisp Machine is associated with one stack group, called the current or running stack group. The operation of making some stack group be the current stack group is called a resumption or a stack group switch; the previously running stack group is said to have resumed the new stack group. The resume operation has two parts: first, the state of the running computation is saved away inside the current stack group, and secondly the state saved in the new stack group is restored, and the new stack group is made current. Then the computation of the new stack group resumes its course.

The stack group itself holds a great deal of state information. It contains the control stack, or regular PDL. The control stack is what you are shown by the backtracing commands of the error handler (Control-B, Meta-B, and Control-Meta-B); it remembers the function which is running, its caller, its caller’s caller, etc., and the point of execution of each function (the return address of each function). A stack group also contains the dynamic environment stack, or special PDL. The name ‘stack group’ derives from the existence of these two stacks. Finally, the stack group contains various internal state information (contents of machine registers and so on).

When the stack group is running, the special PDL contains all the dynamic bindings that are shadowed by other bindings in this stack group; bindings that are current reside in the symbols’ value cells. When the stack group is not running, all of the dynamic bindings it has made reside in its special PDL. Switching to a stack group moves the current bindings from the special PDL to the symbol value cells, exchanging them with the global or other shadowed bindings. Switching out of a stack group does the reverse process. Note that unwind-protect handlers are not run by a stack-group switch (see let-globally, (let-globally-fun)).

Each stack group is a separate environment for purposes of function calling, throwing, dynamic variable binding, and condition signalling. All stack groups run in the same address space; thus they share the same Lisp data and the same global (not lambda-bound) variables.

When a new stack group is created, it is empty: it doesn’t contain the state of any computation, so it can’t be resumed. In order to get things going, the stack group must be set to an initial state. This is done by presetting the stack group. To preset a stack group, you supply a function and a set of arguments. The stack group is placed in such a state that when it is first resumed it will apply this function to those arguments. The function is called the initial function of the stack group.

13.1 Resuming of Stack Groups

The interesting thing that happens to stack groups is that they resume each other. When one stack group resumes a second stack group, the current state of Lisp execution is saved away in the first stack group and is restored from the second stack group. Resuming is also called switching stack groups.

At any time, there is one stack group associated with the current computation; it is called the current stack group. The computations associated with other stack groups have their states saved away in memory and are not computing. So the only stack group that can do anything at all, in particular resuming other stack groups, is the current one.

You can look at things from the point of view of one computation. Suppose it is running along, and it resumes some stack group. The state of the computation state is saved away into its own stack group, and the computation associated with the called stack group starts up. The original computation lies dormant in the original stack group, while other computations go around resuming each other, until finally the original stack group is resumed by someone. Then the computation is restored from the stack group and gets to run again.

There are several ways that the current stack group can resume other stack groups. This section describes all of them.

Each stack group records a resumer which is nil or another stack group. Some forms of resuming examine and alter the resumer of some stack groups.

Resuming has another ability: it can transmit a Lisp object from the old stack group to the new stack group. Each stack group specifies a value to transmit whenever it resumes another stack group; whenever a stack group is resumed, it receives a value.

In the descriptions below, let c stand for the current stack group, s stand for some other stack group, and x stand for any arbitrary Lisp object.

Stack groups can be used as functions. They accept one argument. If c calls s as a function with one argument x, then s is resumed, and the object transmitted is x. When c is resumed (usually–but not necessarily–by s), the object transmitted by that resumption is returned as the value of the call to s. This is one of the simple ways to resume a stack group: call it as a function. The value you transmit is the argument to the function, and the value you receive is the value returned from the function. Furthermore, this form of resuming sets s’s resumer to be c.

Another way to resume a stack group is to use stack-group-return. Rather than allowing you to specify which stack group to resume, this function always resumes the resumer of the current stack group. Thus, this is a good way to go back to the stack group which called the current one, assuming that this was done through a function call. stack-group-return takes one argument which is the object to transmit. It returns when something resumes the current stack group, and returns one value, the object that was transmitted by that resumption. stack-group-return does not change the resumer of any stack group.

The most fundamental way to do resuming is with stack-group-resume, which takes two arguments: the stack group, and a value to transmit. It returns when someone resumes the current stack group, returning the value that was transmitted by that resumption, and does not affect any stack group’s resumer.

If the initial function of c attempts to return a value x, the regular kind of Lisp function return cannot take place, since the function did not have any caller (it got there when the stack group was initialized). So instead of normal function returning, a “stack group return” happens. c’s resumer is resumed, and the value transmitted is x. c is left in a state (“exhausted”) from which it cannot be resumed again; any attempt to resume it signals an error. Presetting it will make it work again.

Those are the “voluntary” forms of stack group switch; a resumption happens because the computation said it should. There are also two “involuntary” forms, in which another stack group is resumed without the explicit request of the running program.

If an error occurs, the current stack group resumes the error handler stack group. The value transmitted is partially descriptive of the error, and the error handler looks inside the saved state of the erring stack group to get the rest of the information. The error handler recovers from the error by changing the saved state of the erring stack group and then resuming it.

When certain events occur, typically a 1-second clock tick, a sequence break occurs. This forces the current stack group to resume a special stack group called the scheduler (see (scheduler)). The scheduler implements processes by resuming, one after another, the stack group of each process that is ready to run.

Variable: current-stack-group-resumer

Is the resumer of the current stack group.

Variable: current-stack-group

Is the stack group which is currently running. A program can use this variable to get its hands on its own stack group.

13.2 Stack Group States

A stack group has a state, which controls what it will do when it is resumed. The code number for the state is returned by the function sys:sg-current-state. This number is the value of one of the following symbols. Only the states actually used by the current system are documented here; some other codes are defined but not used.

sys:sg-state-active

The stack group is the current one.

sys:sg-state-resumable

The stack group is waiting to be resumed, at which time it will pick up its saved machine state and continue doing what it was doing before.

sys:sg-state-awaiting-return

The stack group called some other stack group as a function. When it is resumed, it will return from that function call.

sys:sg-state-awaiting-initial-call

The stack group has been preset (see below) but has never been called. When it is resumed, it will call its initial function with the preset arguments.

sys:sg-state-exhausted

The stack group’s initial function has returned. It cannot be resumed.

sys:sg-state-awaiting-error-recovery

When a stack group gets an error it goes into this state, which prevents anything from happening to it until the error handler has looked at it. In the meantime it cannot be resumed.

sys:sg-state-invoke-call-on-return

When the stack group is resumed, it will call a function. The function and arguments are already set up on the stack. The debugger uses this to force the stack group being debugged to do things.

13.3 Stack Group Functions

Function: make-stack-group name &rest options

Creates and returns a new stack group. name may be any symbol or string; it is used in the stack group’s printed representation. options is a list of alternating keywords and values. The options are not too useful; most calls to make-stack-group don’t need any options at all. The options are:

:sg-area

The area in which to create the stack group structure itself. Defaults to the default area (the value of default-cons-area).

:regular-pdl-area

The area in which to create the regular PDL. Only certain areas specially designated when they were created may be used for regular PDLs, because regular PDLs are cached in a hardware device called the pdl buffer. The default is sys:pdl-area.

:special-pdl-area

The area in which to create the special PDL. Defaults to the default area (the value of default-cons-area).

:regular-pdl-size

Length of the regular PDL to be created. Defaults to 3000 octal.

:special-pdl-size

Length of the special PDL to be created. Defaults to 2000 octal.

:swap-sv-on-call-out
:swap-sv-of-sg-that-calls-me

These flags default to 1. If these are 0, the system does not maintain separate binding environments for each stack group. You do not want to use this feature.

:trap-enable

This determines what to do if a microcode error occurs. If it is 1 the system tries to handle the error; if it is 0 the machine halts. Defaults to 1. It is 0 only in the error handler stack group, a trap in which would not work anyway.

:safe

If this flag is 1 (the default), a strict call-return discipline among stack-groups is enforced. If 0, no restriction on stack-group switching is imposed.

Condition: sys:pdl-overflow (error)

This condition is signaled when there is overflow on either the regular pdl or the special pdl. The :pdl-name operation on the condition instance returns either :special or :regular, to tell handlers which one.

The :grow-pdl proceed type is provided. It takes no arguments. Proceeding from the error automatically makes the affected pdl bigger.

Variable: eh:pdl-grow-ratio

This is the factor by which to increase the size of a pdl after an overflow. It is initially 1.5.

Function: eh:require-pdl-room regpdl-space specpdl-space

Makes the current stack group larger if necessary, to make sure that there are at least regpdl-space free words in the regular pdl, and at least specpdl-space free words in the special pdl, not counting the words currently in use.

Function: stack-group-preset stack-group function &rest arguments

This sets up stack-group so that when it is resumed, function will be applied to arguments within the stack group. Both stacks are made empty; all saved state in the stack group is destroyed. stack-group-preset is typically used to initialize a stack group just after it is made, but it may be done to any stack group at any time. Doing this to a stack group which is not exhausted destroys its present state without properly cleaning up by running unwind-protects.

Function: stack-group-resume s x

Resumes s, transmitting the value x. No stack group’s resumer is affected.

Function: si:sg-resumable-p s

t if s’s state permits it to be resumed.

Condition: sys:wrong-stack-group-state (error)

This is signaled if, for example, you try to resume a stack group which is in the exhausted state.

Function: stack-group-return x

Resumes the current stack group’s resumer, transmitting the value x. No stack group’s resumer is affected.

Function: symeval-in-stack-group symbol sg &optional frame as-if-current

Evaluates the variable symbol as a special variable in the binding environment of sg. If frame is not nil, it evaluates symbol in the binding environment of execution in that frame. (A frame is an index in the stack group’s regular pdl).

Two values are returned: the symbol’s value, and a locative to where the value is stored. If as-if-current is not nil, the locative points to where the value would be stored if sg were running. This may be different from where the value is stored now; for example, the current binding in stack group sg is stored in symbol’s value cell when sg is running, but is probably stored in sg’s special pdl when sg is not running. as-if-current makes no difference if sg actually is the current stack group.

If symbol’s current dynamic binding in the specified stack group and frame is void, this signals a sys:unbound-variable error.

13.4 Analyzing Stack Frames

A stack frame is represented by an index in the regular pdl array of the stack group. The word at this index is the function executing, or to be called, in the frame. The following words in the pdl contain the arguments.

Function: sg-regular-pdl sg

Returns the regular pdl of sg. This is an array of type art-reg-pdl. Stack frames are represented as indices into this array.

Function: sg-regular-pdl-pointer sg

Returns the index in sg’s regular pdl of the last word pushed.

Function: sg-special-pdl sg

Returns the special pdl of sg. This is an array of type art-special-pdl, used to hold special bindings made by functions executing in that stack group.

Function: sg-special-pdl-pointer sg

Returns the index in sg’s special pdl of the last word pushed.

The following functions are used to move from one stack frame to another.

Function: eh:sg-innermost-active sg

Returns (the regular pdl index of) the innermost frame in sg, the one that would be executing if sg were current. If sg is current, the value is the frame of the caller of this function.

Function: eh:sg-next-active sg frame

Returns the next active frame out from frame in sg. This is the one that called frame. If frame is the outermost frame, the value is nil.

Function: eh:sg-previous-active sg frame

Returns the previous active frame in from frame in sg. This is the one called by frame. If frame is the currently executing frame, the value is nil. If frame is nil, the value is the outermost or initial frame.

Function: eh:sg-innermost-open sg

Returns the innermost open frame in sg, which may be the same as the innermost active one or it may be within that. In other respects, this is like eh:sg-innermost-active.

Function: eh:sg-next-open sg frame

Like eh:sg-next-active but includes frames which are open, that is, still accumulating arguments prior to calling the function.

Function: eh:sg-previous-open sg frame

Like eh:sg-previous-active but includes frames which are open, that is, still accumulating arguments prior to calling the function.

Function: eh:sg-frame-active-p sg frame

Returns t if frame is active; that is, if the function has been entered.

Running interpreted code involves calls to eval, cond, etc. which would not be there in compiled code. The following three functions can be used to skip over the stack frames of such functions, showing only the frames for the functions the user would know about.

Function: eh:sg-next-interesting-active sg frame

Like eh:sg-next-active but skips over uninteresting frames.

Function: eh:sg-previous-interesting-active sg frame

Like eh:sg-previous-active but skips over uninteresting frames.

Function: eh:sg-out-to-interesting-active sg frame

If frame is interesting, returns frame. Otherwise, it returns the next interesting active frame.

Functions to analyze the data in a particular stack frame:

Function: sys:rp-function-word regpdl frame

Returns the function executing in frame. regpdl should be the sg-regular-pdl of the stack group.

Function: eh:sg-frame-number-of-spread-args sg frame

Returns the number of arguments received by frame, which should be an active frame. The rest argument (if any) and arguments received by it, do not count.

Function: eh:sg-frame-arg-value sg frame n

Returns the value of argument number n of stack frame frame in sg. An error is signaled if n is out of range, if the frame is active. (For an open frame, the number of arguments is not yet known, so there is no error check.)

The second value is the location in which the argument is stored when sg is running. The location may not actually be in the stack, if the argument is special. The location may then contain other contents when the stack group is not running.

Function: eh:sg-frame-rest-arg-value sg frame

Returns the value of the rest argument in frame, or nil if there is none.

The second value is t if the function called in frame expects an explicitly passed rest argument.

The third value is t if the rest argument was passed explicitly. If this is nil, the rest arg is a stack list that overlaps the arguments of stack frame frame. If it was passed explicitly, it may still be a stack list, but not in this frame. See (stack-list) for more information on stack lists.

Function: eh:sg-frame-number-of-locals sg frame

Returns the number of local variables in stack frame frame.

Function: eh:sg-frame-local-value sg frame n

Returns the value of local variable number n of stack frame frame in sg. An error is signaled if n is out of range.

The second value is the location in which the local is stored when sg is running. The location may not actually be in the stack; if not, it may have other contents when the stack group is not running.

Function: eh:sg-frame-value-value sg frame n &optional create-slot

Returns the value and location of the n’th multiple value frame has returned. If frame has not begun to return values, the first value returned is nil but the location still validly shows where value number n will be stored.

If frame was called with multiple-value-list, it can return any number of values, but they do not have cells to receive them until frame returns them. In this case, a non-nil create-slot means that this function should allocate cells as necessary so that a valid location can be returned. Otherwise, the location as well as the value is nil.

Function: eh:sg-frame-value-list sg frame &optional new-number-of-values

Returns three values that describe whether frame’s caller wants multiple values, and any values frame has returned already.

The first value is a list in which live the values being, or to be, returned by frame.

The second value is nil if this frame has not been invoked to return multiple values, a number which is the number of values it has been asked for, or a locative, meaning the frame was called with multiple-value-list. In the last case, the first value includes only the values frame has returned already, and the locative points to a cell that points to the cons whose cdr should receive the next link of the list.

The third value is how many values frame has returned so far.

If new-number-of-values is non-nil, it is used to alter the “number of values already returned” as recorded in the stack group. This may alter the length of the list that is the first value. The value you get is the altered one, in that case.

Function: eh:sg-frame-special-pdl-range sg frame

Returns two values delimiting the range of sg’s special pdl that belongs to the specified stack frame. The first value is the index of the first special pdl word that belongs to the frame, and the second value is the index of the next word that does not belong to it.

If the specified frame has no special bindings, both values are nil. Otherwise, the indicated special pdl words describe bindings made on entry to or during execution in this frame. The words come in pairs.

The first word of each pair contains the saved value; the second points to the location that was bound. When the stack group is not current, the saved value is the value for the binding made in this frame. When the stack group is current, the saved value is the shadowed value, and the value for this binding is either in the cell that was bound, or is the saved value of another binding, at a higher index, of the same cell.

The bit sys:%%specpdl-closure-binding is nonzero in the first word of the pair if the binding was made before entry to the function itself. This includes bindings made by closures, and by instances (including self). Otherwise, the binding was made by the function itself. This includes arguments that are declared special.

symeval-in-stack-group can be used to find the value of a special variable at a certain stack frame ((symeval-in-stack-group-fun)).

13.5 Input/Output in Stack Groups

Because each stack group has its own set of dynamic bindings, a stack group does not inherit its creator’s value of *terminal-io* (see (terminal-io-var)), nor its caller’s, unless you make special provision for this. The *terminal-io* a stack group gets by default is a “background” stream that does not normally expect to be used. If it is used, it turns into a “background window” that will request the user’s attention. Often this happens when an error invokes the debugger.

If you write a program that uses multiple stack groups, and you want them all to do input and output to the terminal, you should pass the value of *terminal-io* to the top-level function of each stack group as part of the stack-group-preset, and that function should bind the variable *terminal-io*.

Another technique is to use a closure as the top-level function of a stack group. This closure can bind *terminal-io* and any other variables that should be shared between the stack group and its creator.

13.6 An Example of Stack Groups

The canonical coroutine example is the so-called samefringe problem: Given two trees, determine whether they contain the same atoms in the same order, ignoring parenthesis structure. A better way of saying this is, given two binary trees built out of conses, determine whether the sequence of atoms on the fringes of the trees is the same, ignoring differences in the arrangement of the internal skeletons of the two trees. Following the usual rule for trees, nil in the cdr of a cons is to be ignored.

One way of solving this problem is to use generator coroutines. We make a generator for each tree. Each time the generator is called it returns the next element of the fringe of its tree. After the generator has examined the entire tree, it returns a special “exhausted” flag. The generator is most naturally written as a recursive function. The use of coroutines, i.e. stack groups, allows the two generators to recurse separately on two different control stacks without having to coordinate with each other.

The program is very simple. Constructing it in the usual bottom-up style, we first write a recursive function that takes a tree and stack-group-returns each element of its fringe. The stack-group-return is how the generator coroutine delivers its output. We could easily test this function by changing stack-group-return to print and trying it on some examples.

(defun fringe (tree)
  (cond ((atom tree) (stack-group-return tree))
	(t (fringe (car tree))
	   (if (not (null (cdr tree)))
	       (fringe (cdr tree))))))

Now we package this function inside another, which takes care of returning the special “exhausted” flag.

(defun fringe1 (tree exhausted)
  (fringe tree)
  exhausted)

The samefringe function takes the two trees as arguments and returns t or nil. It creates two stack groups to act as the two generator coroutines, presets them to run the fringe1 function, then goes into a loop comparing the two fringes. The value is nil if a difference is discovered, or t if they are still the same when the end is reached.

(defun samefringe (tree1 tree2)
  (let ((sg1 (make-stack-group "samefringe1"))
	(sg2 (make-stack-group "samefringe2"))
	(exhausted (ncons nil)))
    (stack-group-preset sg1 #'fringe1 tree1 exhausted)
    (stack-group-preset sg2 #'fringe1 tree2 exhausted)
    (do ((v1) (v2)) (nil)
      (setq v1 (funcall sg1 nil)
	    v2 (funcall sg2 nil))
      (cond ((neq v1 v2) (return nil))
	    ((eq v1 exhausted) (return t))))))

Now we test it on a couple of examples:

(samefringe '(a b c) '(a (b c))) => t
(samefringe '(a b c) '(a b c d)) => nil

As stack groups are large, and slow to create, it is desirable to avoid the overhead of creating one each time two fringes are compared. It can easily be eliminated with a modest amount of explicit storage allocation, using the resource facility (see (defresource-fun)). While we’re at it, we can avoid making the exhausted flag fresh each time; its only important property is that it not be an atom.

(defresource samefringe-coroutine ()
   :constructor (make-stack-group "for-samefringe"))

(defvar exhausted-flag (ncons nil))

(defun samefringe (tree1 tree2)
  (using-resource (sg1 samefringe-coroutine)
    (using-resource (sg2 samefringe-coroutine)
      (stack-group-preset sg1 #'fringe1 tree1 exhausted-flag)
      (stack-group-preset sg2 #'fringe1 tree2 exhausted-flag)
      (do ((v1) (v2)) (nil)
	(setq v1 (funcall sg1 nil)
	      v2 (funcall sg2 nil))
	(cond ((neq v1 v2) (return nil))
	      ((eq v1 exhausted-flag) (return t)))))))

Now we can compare the fringes of two trees with no allocation of memory whatsoever.

14 Locatives

A locative is a type of Lisp object used as a pointer to a cell. Locatives are inherently a more low level construct than most Lisp objects; they require some knowledge of the nature of the Lisp implementation.

14.1 Cells and Locatives

A cell is a machine word that can hold a (pointer to a) Lisp object. For example, a symbol has five cells: the print name cell, the value cell, the function cell, the property list cell, and the package cell. The value cell holds (a pointer to) the binding of the symbol, and so on. Also, an array leader of length n has n cells, and an art-q array of n elements has n cells. (Numeric arrays do not have cells in this sense.) A locative is an object that points to a cell; it lets you refer to a cell so that you can examine or alter its contents.

Function: contents locative

Returns the contents of the cell which the locative points to. This is actually the same as cdr, for reasons explained below, but it is clearer to use contents when the argument is normally a locative.

To modify the contents of the cell, use setf on contents:

(setf (contents loc) newvalue)

The macro locf (see (locf-fun)) can be used to convert a form that accesses a cell to one that creates a locative pointer to that cell: for example,

(locf (fsymeval x))

evaluates to a locative that points to the function cell of the value of x; that is to say, it points to the place where (fsymeval x) is stored.

locf is very convenient because it saves the writer and reader of a program from having to remember the names of many functions that would create locatives to cells found in different fashions.

One thing you should know is that it is not possible to make a locative to an element of a numeric array. For example,

(setq foo (make-array 10 :type art-1b))
(locf (aref foo 0))

signals an error. Locatives may only point at entire words of memory, which contain standard Lisp data.

Because of cdr-coding (see (cdr-code)), a cons does not always contain an explicit cell which points to its cdr. Therefore, it is impossible to obtain a locative which points to such a cell. However, this is such a useful thing to do that the cons itself is usually treated as if it were a locative pointing to a cell which holds the cons’s cdr. (locf (cdr x)) returns the value of x, and (contents x) returns the cdr when x is a cons, so (contents (locf (cdr x))) is the same as (cdr x), as it should be. Most functions that are normally given locatives also accept a cons and treat it as if it were a magic locative to the (nonexistent) cell containing the cdr of the cons.

A cons always does contain a cell which points to the car, and (locf (car x)) returns a locative whose pointer field is the same as that of x’s value.

14.2 Functions That Operate on Locatives

Function: location-boundp locative

Returns t if the cell to which locative points contains anything except a void marker.

The void marker is a special data type, dtp-null, which is stored in cells to say that their value is missing. For example, an unbound variable actually has a void marker in its value cell, and (location-boundp (locf x)) is equivalent to (variable-boundp x).

Function: location-makunbound locative &optional pointer

Stores a void marker into the cell to which locative points. This consists of data type field dtp-null and a pointer copied from pointer.

The pointer field of the void marker is used to tell the error handler what variable was unbound. In the case of a symbol’s value cell or function cell, it should point to the symbol header. In the case of a flavor method, it should point to the beginning of the block of data that holds the definition, which is a word containing the method’s function spec.

If the second arg is not specified, then where the void marker points is not defined.

Other functions with which locatives are expected or useful include get (the locative points to the cell in which the plist is stored), store-conditional (the locative points to the cell to be tested and modified), and %bind (the locative points to the cell to be bound).

14.3 Mixing Locatives with Lists

Either of the functions car and cdr (see (car-fun)) may be given a locative, and will return the contents of the cell at which the locative points. They are both equivalent to contents when the argument is a locative.

Similarly, either of the functions rplaca and rplacd may be used to store an object into the cell at which a locative points.

For example,
(rplaca locative y)
or
(rplaca locative y)
is the same as
(setf (contents locative) y)

If you are just using locatives, you should use contents rather than car or cdr. But you can also mix locatives and conses. For example, the same variable may usefully sometimes have a locative as its value and sometimes a cons. Then it is useful that car and cdr work on locatives, and it also matters which one you use. Pick the one that is right for the case of a cons.

For example, the following function conses up a list in the forward order by adding onto the end. It needs to know where to put the pointer to the next cell. Usually it goes in the previous cell’s cdr, but the first cell gets put in the cell where the list is supposed to end up. A locative is used as the pointer to this cell. The first time through the loop, the rplacd is equivalent to (setq res ...); on later times through the loop the rplacd tacks an additional cons onto the end of the list.

(defun simplified-version-of-mapcar (fcn lst)
  (do ((lst lst (cdr lst))
       (res nil)
       (loc (locf res)))
      ((null lst) res)
    (setf (cdr loc)
	  (setq loc (ncons (funcall fcn (car lst)))))))

cdr is used here rather than contents because the normal case is that the argument is a list.

15 Subprimitives

Subprimitives are functions which are not intended to be used by the average program, only by system programs. They allow one to manipulate the environment at a level lower than normal Lisp. They are described in this chapter. Subprimitives usually have names starting with a % character. The primitives described in other sections of the manual typically use subprimitives to accomplish their work. To some extent the subprimitives take the place of what in other systems would be individual machine instructions. Subprimitives are normally hand-coded in microcode.

There is plenty of stuff in this chapter that is not fully explained; there are terms that are undefined, there are forward references, and so on. Furthermore, most of what is in here is considered subject to change without notice. In fact, this chapter does not exactly belong in this manual, but in some other more low-level manual. Since the latter manual does not exist, it is here for the interim.

Subprimitives by their very nature cannot do full checking. Improper use of subprimitives can destroy the environment. Subprimitives come in varying degrees of dangerousness. Generally, those without a % sign in their name are not directly dangerous, whereas those whose names begin with % can ruin the Lisp world just as readily as they can do something useful. The subprimitives are documented here since they need to be documented somewhere, but this manual does not document all the things you need to know in order to use them. Still other subprimitives are not documented here because they are very specialized. Most of these are never used explicitly by a programmer; the compiler inserts them into the program to perform operations which are expressed differently in the source code.

The most common problem you can cause using subprimitives, though by no means the only one, is to create illegal pointers: pointers that are, for one reason or another, according to storage conventions, not allowed to exist. The storage conventions are not documented; as we said, you have to be an expert to use a lot of the functions in this chapter correctly. If you create such an illegal pointer, it probably will not be detected immediately, but later on parts of the system may see it, notice that it is illegal, and (probably) halt the Lisp Machine.

In a certain sense car, cdr, rplaca, and rplacd are subprimitives. If these are given a locative instead of a list, they access or modify the cell addressed by the locative without regard to what object the cell is inside. Subprimitives can be used to create locatives to strange places.

15.1 Data Types

Function: data-type arg

data-type returns a symbol that is the name for the internal data-type of arg. The type-of function ((type-of-fun)) is a higher-level primitive that is more useful in most cases; normal programs should always use type-of (or, when appropriate, typep) rather than data-type.

Note that some types as seen by the user are not distinguished from each other at this level, and some user types may be represented by more than one internal type. For example, dtp-extended-number is the symbol that data-type would return for either a single-float or a bignum, even though those two types are quite different.

Some of these type codes occur in memory words but cannot be the type of an actual Lisp object. These include header types such as dtp-symbol-header, which identify the first word of a structure, and forwarding or “invisible” pointer types such as dtp-one-q-forward.

dtp-symbol

’vindex dtp-symbol The object is a symbol.

dtp-fix

’vindex dtp-fix The object is a fixnum; the numeric value is contained in the address field of the pointer.

dtp-small-flonum

’vindex dtp-small-flonum The object is a short float; the numeric value is contained in the address field of the pointer.

dtp-extended-number

’vindex dtp-extended-number The object is a single-float, ratio, bignum or complexnum. This value will also be used for future numeric types.

dtp-character

’vindex dtp-character The object is a character object; the value is contained in the address field of the pointer.

dtp-list

’vindex dtp-list The object is a cons.

dtp-locative

’vindex dtp-locative The object is a locative pointer.

dtp-array-pointer

’vindex dtp-array-pointer The object is an array.

dtp-fef-pointer

’vindex dtp-fef-pointer The object is a compiled function.

dtp-u-entry

’vindex dtp-u-entry The object is a microcode entry.

dtp-closure

’vindex dtp-closure The object is a closure; see (closure).

dtp-stack-closure

’vindex dtp-stack-closure The object is a closure which lives inside a stack, and which must be copied if it is stored anywhere but farther down in the same stack. Lexical scoping is implemented using these.

dtp-instance

’vindex dtp-instance The object is an instance of a flavor; see (flavor).

dtp-entity

’vindex dtp-entity The object is an entity; see (entity).

dtp-select-method

’vindex dtp-select-method The object is a select-method; see (select-method).

dtp-stack-group

’vindex dtp-stack-group The object is a stack-group; see (stack-group).

The remaining types are internal only.
dtp-header

’vindex dtp-header An internal type used to mark the first word of several kinds of multi-word structure, including single-floats, ratios, bignums and FEFs.

dtp-array-header

’vindex dtp-array-header An internal type used to mark the first word of an array.

dtp-symbol-header

’vindex dtp-symbol-header An internal type used to mark the first word of a symbol. The pointer field points to the symbol’s print-name, which is a string.

dtp-instance-header

’vindex dtp-instance-header An internal type used to mark the first word of an instance. The pointer field points to the structure that describes the instance’s flavor.

dtp-null

’vindex dtp-null Nothing to do with nil. This type code identifies a void marker. An attempt to refer to the contents of a cell that contains a dtp-null signals an error. This is how “unbound variable” and “undefined function” errors are detected.

dtp-trap

’vindex dtp-trap The zero data-type, which is not used. This hopes to detect microcode bugs.

dtp-free

’vindex dtp-free This type is used to fill free storage, to catch wild references.

dtp-external-value-cell-pointer

’vindex dtp-external-value-cell-pointer An “invisible pointer” used for external value cells, which are part of the closure mechanism (see (closure)), and used by compiled code to address value and function cells.

dtp-self-ref-pointer

’vindex dtp-self-ref-pointer An “invisible pointer” used to refer to an instance variable of self. This data type appears in FEFs of flavor methods.

dtp-header-forward

’vindex dtp-header-forward An “invisible pointer” used to indicate that the structure containing it has been moved elsewhere. The “header word” of the structure is replaced by one of these invisible pointers. See the function structure-forward ((structure-forward-fun)).

dtp-body-forward

’vindex dtp-body-forward An “invisible pointer” used to indicate that the structure containing it has been moved elsewhere. This points to the word containing the header-forward, which points to the new copy of the structure.

dtp-one-q-forward

’vindex dtp-one-q-forward An “invisible pointer” used to indicate that the single cell containing it has been moved elsewhere.

dtp-gc-forward

’vindex dtp-gc-forward This is used by the copying garbage collector to flag the obsolete copy of an object; it points to the new copy.

Constant: q-data-types

The value of q-data-types is a list of all of the symbolic names for data types described above under data-type. These are the symbols whose print names begin with ‘dtp-’. The values of these symbols are the internal numeric data-type codes for the various types.

Function: q-data-types type-code

Given the internal numeric data-type code, returns the corresponding symbolic name. This “function” is actually an array.

15.2 Forwarding

An invisible pointer or forwarding pointer is a kind of pointer that does not represent a Lisp object, but just resides in memory. There are several kinds of invisible pointer, and there are various rules about where they may or may not appear. The basic property of an invisible pointer is that if the Lisp Machine reads a word of memory and finds an invisible pointer there, instead of seeing the invisible pointer as the result of the read, it does a second read, at the location addressed by the invisible pointer, and returns that as the result instead. Writing behaves in a similar fashion. When the Lisp Machine writes a word of memory it first checks to see if that word contains an invisible pointer; if so it goes to the location pointed to by the invisible pointer and tries to write there instead. Many subprimitives that read and write memory do not do this checking.

The simplest kind of invisible pointer has the data type code dtp-one-q-forward. It is used to forward a single word of memory to someplace else. The invisible pointers with data types dtp-header-forward and dtp-body-forward are used for moving whole Lisp objects (such as cons cells or arrays) somewhere else. The dtp-external-value-cell-pointer is very similar to the dtp-one-q-forward; the difference is that it is not “invisible” to the operation of binding. If the (internal) value cell of a symbol contains a dtp-external-value-cell-pointer that points to some other word (the external value cell), then symeval or set operations on the symbol consider the pointer to be invisible and use the external value cell, but binding the symbol saves away the dtp-external-value-cell-pointer itself, and stores the new value into the internal value cell of the symbol. This is how closures are implemented.

dtp-gc-forward is not an invisible pointer at all; it only appears in “old spaced” and can never be seen by any program other than the garbage collector. When an object is found not to be garbage, and the garbage collector moves it from “old space” to “new space”, a dtp-gc-forward is left behind to point to the new copy of the object. This ensures that other references to the same object get the same new copy.

Function: structure-forward old-object new-object

This causes references to old-object actually to reference new-object, by storing invisible pointers in old-object. It returns old-object.

An example of the use of structure-forward is adjust-array. If the array is being made bigger and cannot be expanded in place, a new array is allocated, the contents are copied, and the old array is structure-forwarded to the new one. This forwarding ensures that pointers to the old array, or to cells within it, continue to work. When the garbage collector goes to copy the old array, it notices the forwarding and uses the new array as the copy; thus the overhead of forwarding disappears eventually if garbage collection is in use.

Function: follow-structure-forwarding object

Normally returns object, but if object has been structure-forward’ed, returns the object at the end of the chain of forwardings. If object is not exactly an object, but a locative to a cell in the middle of an object, a locative to the corresponding cell in the latest copy of the object is returned.

Function: forward-value-cell from-symbol to-symbol

This alters from-symbol so that it always has the same value as to-symbol, by sharing its value cell. A dtp-one-q-forward invisible pointer is stored into from-symbol’s value cell. Do not do this while from-symbol’s current dynamic binding is not global, as the microcode does not bother to check for that case and something bad will happen when from-symbol’s binding is unbound. The microcode check is omitted to speed up binding and unbinding.

This is how synonymous variables (such as *terminal-io* and terminal-io) are created.

To forward one arbitrary cell to another (rather than specifically one value cell to another), given two locatives, do

(%p-store-tag-and-pointer locative1 dtp-one-q-forward locative2)
Function: follow-cell-forwarding loc evcp-p

loc is a locative to a cell. Normally loc is returned, but if the cell has been forwarded, this follows the chain of forwardings and returns a locative to the final cell. If the cell is part of a structure which has been forwarded, the chain of structure forwardings is followed, too. If evcp-p is t, external value cell pointers are followed; if it is nil they are not.

15.3 Pointer Manipulation

It should again be emphasized that improper use of these functions can damage or destroy the Lisp environment. It is possible to create pointers with illegal data-type, pointers to non-existent objects, and pointers to untyped storage, which will completely confuse the garbage collector.

Function: %data-type x

Returns the data-type field of x, as a fixnum.

Function: %pointer x

Returns the pointer field of x, as a fixnum. For most types, this is dangerous since the garbage collector can copy the object and change its address.

Function: %make-pointer data-type pointer

Makes up a pointer, with data-type in the data-type field and pointer in the pointer field, and returns it. data-type should be an internal numeric data-type code; these are the values of the symbols that start with dtp-. pointer may be any object; its pointer field is used. This is most commonly used for changing the type of a pointer. Do not use this to make pointers which are not allowed to be in the machine, such as dtp-null, invisible pointers, etc.

Function: %make-pointer-offset data-type pointer offset

Returns a pointer with data-type in the data-type field, and pointer plus offset in the pointer field. The data-type and pointer arguments are like those of %make-pointer; offset may be any object but is usually a fixnum. The types of the arguments are not checked; their pointer fields are simply added together. This is useful for constructing locative pointers into the middle of an object. However, note that it is illegal to have a pointer to untyped data, such as the inside of a FEF or a numeric array.

Function: %pointer-difference pointer-1 pointer-2

Returns a fixnum which is pointer-1 minus pointer-2. No type checks are made. For the result to be meaningful, the two pointers must point into the same object, so that their difference cannot change as a result of garbage collection.

Function: %pointerp object

t if object points to storage. For example, (%pointerp "foo") is t, but (%pointerp 5) is nil.

Function: %pointer-type-p data-type

t if the specified data type is one which points to storage. For example, (%pointer-type-p dtp-fix) returns nil.

15.4 Special Memory Referencing

Function: %p-pointerp location

t if the contents of the word at location points to storage. This is similar to (%pointerp (contects location)), but the latter may get an error if location contains a forwarding pointer, a header type, or a void marker. In such cases, %p-pointerp correctly tells you whether the header or forward points to storage.

Function: %p-pointerp-offset location offset

Similar to %p-pointerp but operates on the word offset words beyond location.

Function: %p-contents-offset base-pointer offset

Returns the contents of the word offset words beyond base-pointer. This first checks the cell pointed to by base-pointer for a forwarding pointer. Having followed forwarding pointers to the real structure pointed to, it adds offset to the resulting forwarded base-pointer and returns the contents of that location.

There is no %p-contents, since car performs that operation.

Function: %p-contents-safe-p location

t if the contents of word location are a valid Lisp object, at least as far as data type is concerned. It is nil if the word contains a header type, a forwarding pointer, or a void marker. If the value of this function is t, you will not get an error from (contents location).

Function: %p-contents-safe-p-offset location offset

Similar to %p-contents-safe-p but operates on the word offset words beyond location.

Function: %p-contents-as-locative pointer

Given a pointer to a memory location containing a pointer that isn’t allowed to be “in the machine” (typically an invisible pointer) this function returns the contents of the location as a dtp-locative. It changes the disallowed data type to dtp-locative so that you can safely look at it and see what it points to.

Function: %p-contents-as-locative-offset base-pointer offset

Extracts the contents of a word like %p-contents-offset, but changes it into a locative like %p-contents-as-locative. This can be used, for example, to analyze the dtp-external-value-cell-pointer pointers in a FEF, which are used by the compiled code to reference value cells and function cells of symbols.

Function: %p-safe-contents-offset location offset

Returns the contents of the word offset words beyond location as accurately as possible without getting an error.

If the contents are a valid Lisp object, it is returned exactly.

If the contents are not a valid Lisp object but do point to storage, the value returned is a locative which points to the same place in storage.

If the contents are not a valid Lisp object and do not point to storage, the value returned is a fixnum with the same pointer field.

Forwarding pointers are checked as in %p-contents-offset.

Function: %p-store-contents pointer value

Stores value into the data-type and pointer fields of the location addressed by pointer, and returns value. The cdr-code field of the location remains unchanged.

Function: %p-store-contents-offset value base-pointer offset

Stores value in the location offset beyond words beyond base-pointer, then returns value. The cdr-code field remains unchanged. Forwarding pointers in the location at base-pointer are handled as they are in %p-contents-offset.

Function: %p-store-tag-and-pointer pointer miscfields pointerfield

Stores miscfields and pointerfield into the location addressed by pointer. 25 bits are taken from pointerfield to fill the pointer field of the location, and the low 7 bits of miscfields are used to fill both the data-type and cdr-code fields of the location. The low 5 bits of miscfields become the data-type, and the top two bits become the cdr-code. This is a good way to store a forwarding pointer from one structure to another (for example).

%p-store-tag-and-pointer should be used only for storing into ‘boxed’ words, for the same reason as %blt-typed: the microcode could halt if the data stored is not valid boxed data. See (%blt-typed-fun).

Function: %p-ldb byte-spec pointer

Extracts a byte according to byte-spec from the contents of the location addressed by pointer, in effect regarding the contents as a 32-bit number and using ldb. The result is always a fixnum. For example, (%p-ldb %%q-cdr-code loc) returns the cdr-code of the location addressed by loc.

Function: %p-ldb-offset byte-spec base-pointer offset

Extracts a byte according to byte-spec from the contents of the location offset words beyond base-pointer, after handling forwarding pointers like %p-contents-offset.

This is the way to reference byte fields within a structure without violating system storage conventions.

Function: %p-mask-field byte-spec pointer

Like %p-ldb, except that the selected byte is returned in its original position within the word instead of right-aligned.

Function: %p-mask-field-offset byte-spec base-pointer offset

Like %p-ldb-offset, except that the selected byte is returned in its original position within the word instead of right-aligned.

Note: %p-dbp, %p-dpb-offset, %p-deposit-field and %p-deposit-field-offset should never be used to modify the pointer field of a boxed word if the data type is one which actually points to storage, unless you are sure that the new pointer is such as to cause no trouble (such as, if it points to a static area). Likewise, it should never be used to change a data type which does not point to storage into one which does. Either action could confuse the garbage collector.

Function: %p-dpb value byte-spec pointer

Stores value, a fixnum, into the byte selected by byte-spec in the word addressed by pointer. nil is returned. You can use this to alter data types, cdr-codes, etc., but see the note above for restrictions.

Function: %p-dpb-offset value byte-spec base-pointer offset

Stores value into the specified byte of the location offset words beyond that addressed by base-pointer, after first handling forwarding pointers in the location addressed by base-pointer as in %p-contents-offset. nil is returned.

This is the way to alter unboxed data within a structure without violating system storage conventions. You can use this to alter boxed words too, but see the note above for restrictions.

Function: %p-deposit-field value byte-spec pointer

Like %p-dpb, except that the selected byte is stored from the corresponding bits of value rather than the right-aligned bits. See the note above %p-dpb for restrictions.

Function: %p-deposit-field-offset value byte-spec base-pointer offset

Like %p-dpb-offset, except that the selected byte is stored from the corresponding bits of value rather than the right-aligned bits. See the note above %p-dpb for restrictions.

Function: %p-pointer pointer

Extracts the pointer field of the contents of the location addressed by pointer and returns it as a fixnum.

Function: %p-data-type pointer

Extracts the data-type field of the contents of the location addressed by pointer and returns it as a fixnum.

Function: %p-cdr-code pointer

Extracts the cdr-code field of the contents of the location addressed by pointer and returns it as a fixnum.

Function: %p-store-pointer pointer value

Stores value in the pointer field of the location addressed by pointer, and returns value.

Function: %p-store-data-type pointer value

Stores value in the data-type field of the location addressed by pointer, and returns value.

Function: %p-store-cdr-code pointer value

Stores value in the cdr-code field of the location addressed by pointer, and returns value.

Function: %stack-frame-pointer

Returns a locative pointer to its caller’s stack frame. This function is not defined in the interpreted Lisp environment; it only works in compiled code. Since it turns into a “misc” instruction, the “caller’s stack frame” really means “the frame for the FEF that executed the %stack-frame-pointer instruction”.

15.5 Storage Layout Definitions

The following special variables have values which define the most important attributes of the way Lisp data structures are laid out in storage. In addition to the variables documented here, there are many others that are more specialized. They are not documented in this manual since they are in the system package rather than the global package. The variables whose names start with %% are byte specifiers, intended to be used with subprimitives such as %p-ldb. If you change the value of any of these variables, you will probably bring the machine to a crashing halt.

Constant: %%q-cdr-code

The field of a memory word that contains the cdr-code. See (cdr-code).

Constant: %%q-data-type

The field of a memory word that contains the data-type code. See (data-type-fun).

Constant: %%q-pointer

The field of a memory word that contains the pointer address, or immediate data.

Constant: %%q-pointer-within-page

The field of a memory word that contains the part of the address that lies within a single page.

Constant: %%q-typed-pointer

The concatenation of the %%q-data-type and %%q-pointer fields.

Constant: %%q-all-but-typed-pointer

This is now synonymous with %%q-cdr-code, and therefore obsolete.

Constant: %%q-all-but-pointer

The concatenation of all fields of a memory word except for %%q-pointer.

Constant: %%q-all-but-cdr-code

The concatenation of all fields of a memory word except for %%q-cdr-code.

Constant: %%q-high-half
Constant: %%q-low-half

The two halves of a memory word. These fields are only used in storing compiled code.

Constant: cdr-normal
Constant: cdr-next
Constant: cdr-nil
Constant: cdr-error

The values of these four variables are the numeric values that go in the cdr-code field of a memory word. See (cdr-code) for the details of cdr-coding.

15.6 Analyzing Structures

Function: %find-structure-header pointer

This subprimitive finds the structure into which pointer points, by searching backward for a header. It is a basic low-level function used by such things as the garbage collector. pointer is normally a locative, but its data-type is ignored. Note that it is illegal to point into an “unboxed” portion of a structure, for instance the middle of a numeric array.

In structure space, the “containing structure” of a pointer is well-defined by system storage conventions. In list space, it is considered to be the contiguous, cdr-coded segment of list surrounding the location pointed to. If a cons of the list has been copied out by rplacd, the contiguous list includes that pair and ends at that point.

Function: %find-structure-leader pointer

This is identical to %find-structure-header, except that if the structure is an array with a leader, this returns a locative pointer to the leader-header, rather than returning the array-pointer itself. Thus the result of %find-structure-leader is always the lowest address in the structure. This is the one used internally by the garbage collector.

Function: %structure-boxed-size object

Returns the number of “boxed Q’s” in object. This is the number of words at the front of the structure which contain normal Lisp objects. Some structures, for example FEFs and numeric arrays, contain additional “unboxed Q’s” following their boxed Q’s. Note that the boxed size of a PDL (either regular or special) does not include Q’s above the current top of the PDL. Those locations are boxed, but their contents are considered garbage and are not protected by the garbage collector.

Function: %structure-total-size object

Returns the total number of words occupied by the representation of object, including boxed Q’s, unboxed Q’s, and garbage Q’s off the ends of PDLs.

15.7 Creating Objects

Function: %allocate-and-initialize data-type header-type header second-word area size

This is the subprimitive for creating most structured-type objects. area is the area in which it is to be created, as a fixnum or a symbol. size is the number of words to be allocated. The value returned points to the first word allocated and has data-type data-type. Uninterruptibly, the words allocated are initialized so that storage conventions are preserved at all times. The first word, the header, is initialized to have header-type in its data-type field and header in its pointer field. The second word is initialized to second-word. The remaining words are initialized to nil. The cdr-codes of all words except the last are set to cdr-next; the cdr-code of the last word is set to cdr-nil. It is probably a bad idea to rely on this.

Function: %allocate-and-initialize-array header data-length leader-length area size

This is the subprimitive for creating arrays, called only by make-array. It is different from %allocate-and-initialize because arrays have a more complicated header structure.

The basic functions for creating list-type objects are cons and make-list; no special subprimitive is needed. Closures, entities, and select-methods are based on lists, but there is no primitive for creating them. To create one, create a list and then use %make-pointer to change the data type from dtp-list to the desired type.

15.8 Copying Data

%blt and %blt-typed are subprimitives for copying blocks of data, word aligned, from one place in memory to another with little or no type checking.

Function: %blt from to count increment
Function: %blt-typed from to count increment

Copies count words, separated by increment. The word at address from is moved to address to, the word at address from+increment is moved to address to+increment, and so on until count words have been moved.

Only the pointer fields of from and to are significant; they may be locatives or even fixnums. If one of them must point to the unboxed data in the middle of a structure, you must make it a fixnum, and you must do so with interrupts disabled, or else garbage collection could move the structure after you have already created the fixnum.

%blt-typed assumes that each copied word contains a data type field and checks that field, interfacing suitably with the garbage collector if necessary. %blt does not check the data type fields of the copied words.

%blt may be used on any data except boxed data containing pointers to storage, while %blt-typed may be used on any boxed data. Both %blt and %blt-typed can be used validly on data which is formatted with data types (boxed) but whose contents never point to storage. This includes words whose contents are always fixnums or short floats, and also words which contain array headers, array leader headers, or FEF headers. Whether or not the machine is told to examine the data types of such data makes no difference since, on examining them, it would decide that nothing needed to be done.

For unboxed data (data which is formatted not containing valid data type fields), such as the inside of a numeric array or the instruction words of a FEF, only %blt may be used. If %blt-typed were used, it would examine the data type fields of the data words, and probably halt due to an invalid data type code.

For boxed data which may contain pointers, only %blt-typed may be used. If %blt were used, it would appear to work, but problems could appear mysteriously later because nothing would notice the presence of the pointer there. For example, the pointer might point to a bignum in the number consing area, and moving it in this way would fail to copy it into a nontemporary area. Then the pointer would become invalidated the next time the number consing area was emptied out. There could also be problems with lexical closures and with garbage collection.

15.9 Returning Storage

Function: return-storage object

This peculiar function attempts to return object to free storage. If it is a displaced array, this returns the displaced array itself, not the data that the array points to. Currently return-storage does nothing if the object is not at the end of its region, i.e. if it was not either the most recently allocated non-list object in its area, or the most recently allocated list in its area.

If you still have any references to object anywhere in the Lisp world after this function returns, the garbage collector can get a fatal error if it sees them. Since the form that calls this function must get the object from somewhere, it may not be clear how to legally call return-storage. One of the only ways to do it is as follows:

(defun func ()
   (let ((object (make-array 100)))
      ...
      (return-storage (prog1 object (setq object nil)))))

so that the variable object does not refer to the object when return-storage is called. Alternatively, you can free the object and get rid of all pointers to it while interrupts are turned off with without-interrupts.

You should only call this function if you know what you are doing; otherwise the garbage collector can get fatal errors. Be careful.

15.10 Locking Subprimitive

Function: %store-conditional pointer old new

This is the basic locking primitive. pointer is a locative to a cell which is uninterruptibly read and written. If the contents of the cell is eq to old, then it is replaced by new and t is returned. Otherwise, nil is returned and the contents of the cell are not changed.

See also store-conditional, a higher-level function which provides type checking ((store-conditional-fun)).

15.11 CADR I/O Device Subprimitives

The CADR processor has a 32-bit memory bus called the Xbus. In addition to main memory and TV screen memory, most I/O device registers are on this bus. There is also a Unibus compatible with the PDP-11. A map of Xbus and Unibus addresses can be found in SYS: DOC; UNADDR TEXT.

Function: %unibus-read address

Returns as a fixnum the contents of the register at the specified Unibus address. You must specify a full 18-bit address. This is guaranteed to read the location only once. Since the Lisp Machine Unibus does not support byte operations, this always references a 16-bit word, and so address should normally be an even number.

Function: %unibus-write address data

Writes the 16-bit number data at the specified Unibus address, exactly once.

Function: %xbus-read io-offset

Returns the contents of the register at the specified Xbus address. io-offset is an offset into the I/O portion of Xbus physical address space. This is guaranteed to read the location exactly once. The returned value can be either a fixnum or a bignum.

Function: %xbus-write io-offset data

Writes data, which can be a fixnum or a bignum, into the register at the specified Xbus address. io-offset is an offset into the I/O portion of Xbus physical address space. This is guaranteed to write the location exactly once.

Function: sys:%xbus-write-sync w-loc w-data delay sync-loc sync-mask sync-value

Does (%xbus-write w-loc w-data), but first synchronizes to within about one microsecond of a certain condition. The synchronization is achieved by looping until

(= (logand (%xbus-read sync-loc) sync-mask) sync-value)

is false, then looping until it is true, then looping delay times. Thus the write happens a specified delay after the leading edge of the synchronization condition. The number of microseconds of delay is roughly one third of delay.

This primitive is used to alter the color TV screen’s color map during vertical retrace.

15.12 Lambda I/O-Device Subprimitives

Function: sys:%nubus-read slot byte-address

Returns the contents of a word read from the Nu bus. Addresses on the Nu bus are divided into an 8-bit slot number which identifies which physical board is being referenced and a 24-bit address within slot. The address is measured in bytes and therefore should be a multiple of 4. Which addresses are valid depends on the type of board plugged into the specified slot. If, for example, the board is a 512k main memory board, then the valid address range from 0 to 4 * (512k - 1). (Of course, main memory boards are normally accessed through the virtual memory mechanism.)

Function: sys:%nubus-write slot byte-address word

Writes word into a word of the Nu bus, whose address is specified by slot and byte-address as described above.

Function: sys:%nubus-physical-address apparent-physical-page

The valid portions of the Nu bus address space are not contiguous. Each board is allocated 16m bytes of address space, but no memory board actually provides 16m bytes of memory.

The Lisp Machine virtual memory system maps virtual addresses into a contiguous physical address space. On the Lambda, this contiguous address space is mapped a second time into the discontiguous Nu bus address space. Unlike the mapping of virtual addresses to physical ones, the second mapping is determined from the hardware configuration when the machine is booted and does not change during operation.

This function performs exactly that mapping. The argument is a physical page number (a physical address divided by sys:page-size). The argument is a "Nu bus page number"; multiplied by sys:page-size and then by four, it yields the Nu bus byte address of the beginning of that physical page.

See also sys:%physical-address, (sys:%physical-address-fun).

15.13 Function-Calling Subprimitives

These subprimitives can be used (carefully!) to call a function with the number of arguments variable at run time. They only work in compiled code and are not defined in the interpreted Lisp environment. The preferred higher-level primitive is apply ((apply-fun)).

Function: %open-call-block function n-adi-pairs destination

Starts a call to function. n-adi-pairs is the number of pairs of additional information words already %push’ed; normally this should be 0. destination is where to put the result; the useful values are 0 for the value to be ignored, 1 for the value to go onto the stack, 3 for the value to be the last argument to the previous open call block, and 2 for the value to be returned from this frame.

Function: %push value

Pushes value onto the stack. Use this to push the arguments.

Function: %activate-open-call-block

Causes the call to happen.

Function: %pop

Pops the top value off of the stack and returns it as its value. Use this to recover the result from a call made by %open-call-block with a destination of 1.

Function: %assure-pdl-room n-words

Call this before doing a sequence of %push’s or %open-call-block’s that will add n-words to the current frame. This subprimitive checks that the frame will not exceed the maximum legal frame size, which is 255 words including all overhead. This limit is dictated by the way stack frames are linked together. If the frame is going to exceed the legal limit, %assure-pdl-room signals an error.

15.14 Special-Binding Subprimitive

Function: %bind locative value
Function: bind locative value

Binds the cell pointed to by locative to x, in the caller’s environment. This function is not defined in the interpreted Lisp environment; it only works from compiled code. Since it turns into an instruction, the “caller’s environment” really means “the binding block for the compiled function that executed the %bind instruction”. The preferred higher-level primitives that turn into this are let ((let-fun)), let-if ((let-if-fun)), and progv ((progv-fun)).

The binding is in effect for the scope of the innermost binding construct, such as prog or let–even one that binds no variables itself.

%bind is the preferred name; bind is an older name which will eventually be eliminated.

15.15 The Paging System

[Someday this may discuss how it works.]

Variable: sys:%disk-switches

This variable contains bits that control various disk usage features.

Bit 0 (the least significant bit) enables read-compares after disk read operations. This causes a considerable slowdown, so it is rarely used.

Bit 1 enables read-compares after disk write operations.

Bit 2 enables the multiple page swap-out feature. When this is enabled, as it is by default, each time a page is swapped out, up to 16. contiguous pages are also written out to the disk if they have been modified. This greatly improves swapping performance.

Bit 3 controls the multiple page swap-in feature, which is also on by default. This feature causes pages to be swapped in in groups; each time a page is needed, several contiguous pages are swapped in in the same disk operation. The number of pages swapped in can be specified for each area using si:set-swap-recommendations-of-area.

Function: si:set-swap-recommendations-of-area area-number recommendation

Specifies that pages of area area-number should be swapped in in groups of recommendation at a time. This recommendation is used only if the multiple page swap-in feature is enabled.

Generally, the more memory a machine has, the higher the swap recommendations should be to get optimum performance. The recommendations are set automatically according to the memory size when the machine is booted.

Function: si:set-all-swap-recommendations recommendation

Specifies the swap-in recommendation of all areas at once.

Function: si:wire-page address &optional (wire-p t)

If wire-p is t, the page containing address is wired-down; that is, it cannot be paged-out. If wire-p is nil, the page ceases to be wired-down.

Function: si:unwire-page address

(si:unwire-page address) is the same as (si:wire-page address nil).

Function: sys:page-in-structure object

Makes sure that the storage that represents object is in main memory. Any pages that have been swapped out to disk are read in, using as few disk operations as possible. Consecutive disk pages are transferred together, taking advantage of the full speed of the disk. If object is large, this is much faster than bringing the pages in one at a time on demand. The storage occupied by object is defined by the %find-structure-leader and %structure-total-size subprimitives.

Function: sys:page-in-array array &optional from to

This is a version of sys:page-in-structure that can bring in a portion of an array. from and to are lists of subscripts; if they are shorter than the dimensionality of array, the remaining subscripts are assumed to be zero.

Function: sys:page-in-pixel-array array &optional from to

Like sys:page-in-array except that the lists from and to, if present, are assumed to have their subscripts in the order horizontal, vertical, regardless of which of those two is actually the first axis of the array. See make-pixel-array, (make-pixel-array-fun).

Function: sys:page-in-words address n-words

Any pages that have been swapped out to disk in the range of address space starting at address and continuing for n-words are read in with as few disk operations as possible.

Function: sys:page-in-area area-number
Function: sys:page-in-region region-number

All swapped-out pages of the specified region or area are brought into main memory.

Function: sys:page-out-structure object
Function: sys:page-out-array array &optional from to
Function: sys:page-out-pixel-array array &optional from to
Function: sys:page-out-words address n-words
Function: sys:page-out-area area-number
Function: sys:page-out-region region-number

These are similar to the above, except that they take pages out of main memory rather than bringing them in. Actually, they only mark the pages as having priority for replacement by others. Use these operations when you are done with a large object, to make the virtual memory system prefer reclaiming that object’s memory over swapping something else out.

Function: sys:%page-status virtual-address

If the page containing virtual-address is swapped out, or if it is part of one of the low-numbered fixed areas, this returns nil. Otherwise it returns the entire first word of the page hash table entry for the page.

The %%pht1- symbols in SYS: SYS; QCOM LISP are byte specifiers you can use with %logldb for decoding the value.

Function: sys:%change-page-status virtual-address swap-status access-status-and-meta-bits

The page hash table entry for the page containing virtual-address is found and altered as specified. t is returned if it was found, nil if it was not (presumably the page is swapped out). swap-status and access-status-and-meta-bits can be nil if those fields are not to be changed. This doesn’t make any error checks; you can really screw things up if you call it with the wrong arguments.

Function: sys:%compute-page-hash virtual-address

Makes the hashing function for the page hash table available to the user.

Function: sys:%physical-address virtual-address

Returns the physical address which virtual-address currently maps into. The value is unpredictable if the virtual page is not swapped in; therefore, this function should be used on wired pages, or you should do

(without-interrupts
  (%p-pointer virtual-address)     ;swap it in
  (sys:%physical-address virtual-address))
Function: sys:%create-physical-page physical-address

This is used when adjusting the size of real memory available to the machine. It adds an entry for the page frame at physical-address to the page hash table, with virtual address -1, swap status flushable, and map status 120 (read only). This doesn’t make error checks; you can really screw things up if you call it with the wrong arguments.

Function: sys:%delete-physical-page physical-address

If there is a page in the page frame at physical-address, it is swapped out and its entry is deleted from the page hash table, making that page frame unavailable for swapping in of pages in the future. This doesn’t make error checks; you can really screw things up if you call it with the wrong arguments.

Function: sys:%disk-restore high-16-bits low-16-bits

Loads virtual memory from the partition named by the concatenation of the two 16-bit arguments, and starts executing it. The name 0 refers to the default load (the one the machine loads when it is started up). This is the primitive used by disk-restore (see (disk-restore-fun)).

Function: sys:%disk-save physical-mem-size high-16-bits low-16-bits

Copies virtual memory into the partition named by the concatenation of the two 16-bit arguments (0 means the default), then restarts the world, as if it had just been restored. The physical-mem-size argument should come from %sys-com-memory-size in system-communication-area. If physical-mem-size is negative, it is minus the memory size, and an incremental save is done. This is the primitive used by disk-save (see (disk-save-fun)).

Function: si:set-memory-size nwords

Specifies the size of physical memory in words. The Lisp machine determines the actual amount of physical memory when it is booted, but with this function you can tell it to use less memory than is actually present. This may be useful for comparing performance based on the amount of memory.

15.16 Closure Subprimitives

These functions deal with things like what closures deal with: the distinction between internal and external value cells and control over how they work.

Function: sys:%binding-instances list-of-symbols

This is the primitive that could be used by closure. First, if any of the symbols in list-of-symbols has no external value cell, a new external value cell is created for it, with the contents of the internal value cell. Then a list of locatives, twice as long as list-of-symbols, is created and returned. The elements are grouped in pairs: pointers to the internal and external value cells, respectively, of each of the symbols. closure could have been defined by:

(defun closure (variables function)
  (%make-pointer dtp-closure
     (cons function (sys:%binding-instances variables))))
Function: sys:%using-binding-instances instance-list

This function is the primitive operation that invocation of closures could use. It takes a list such as sys:%binding-instances returns, and for each pair of elements in the list, it “adds” a binding to the current stack frame, in the same manner that the %bind function does. These bindings remain in effect until the frame returns or is unwound.

sys:%using-binding-instances checks for redundant bindings and ignores them. (A binding is redundant if the symbol is already bound to the desired external value cell.) This check avoids excessive growth of the special pdl in some cases and is also made by the microcode which invokes closures, entities, and instances.

Given a closure, closure-bindings extracts its list of binding instances, which you can then pass to sys:%using-binding-instances.

Function: sys:%internal-value-cell symbol

Returns the contents of the internal value cell of symbol. dtp-one-q-forward pointers are considered invisible, as usual, but dtp-external-value-cell-pointers are not; this function can return a dtp-external-value-cell-pointer. Such pointers will be considered invisible as soon as they leave the “inside of the machine”, meaning internal registers and the stack.

15.17 Distiguishing Processor Types

The MIT Lisp Machine system runs on two types of processors: the CADR and the Lambda. These are similar enough that there is no difference in compiled code for them, and no provision for compile-time conditionalization. However, obscure or internal I/O code sometimes needs to behave differently at run-time depending on the type of processor. This is possible through the use of these macros.

Variable: sys:processor-type-code

This variable is 1 on a CADR processor or equivalent, 2 on a Lambda.

Macro: if-in-cadr body...

Executes body only when executing on a CADR.

Macro: if-in-lambda body

Executes body only when executing on a Lambda.

Macro: if-in-cadr-else-lambda if-cadr-form else-body...

Executes if-cadr-form when executing on a CADR, executes else-body when executing on a Lambda.

(format t "~&Processor is a ~A.~%"
        (if-in-cadr-else-lambda "CADR" "Lambda"))
Macro: if-in-lambda-else-cadr if-lambda-form else-body...

Executes if-cadr-form when executing on a Lambda executes else-body when executing on a CADR.

Macro: select-processor clauses

Each clause consists of :cadr or :lambda followed by forms to execute when running on that kind of processor. Example:

(format t "~&Processor is a ~A.~%"
        (select-processor
          (:cadr "CADR")
	  (:lambda "Lambda")))

15.18 Microcode Variables

The following variables’ values actually reside in the scratchpad memory of the processor. They are put there by dtp-one-q-forward invisible pointers. The values of these variables are used by the microcode. Many of these variables are highly internal and you shouldn’t expect to understand them.

Variable: %microcode-version-number

This is the version number of the currently-loaded microcode, obtained from the version number of the microcode source file.

Variable: sys:%number-of-micro-entries

Size of micro-code-entry-area and related areas.

default-cons-area is documented on (default-cons-area-var).

Variable: sys:number-cons-area

The area number of the area where bignums, ratios, full-size floats and complexnums are consed. Normally this variable contains the value of sys:extra-pdl-area, which enables the “temporary storage” feature for numbers, saving garbage collection overhead.

current-stack-group and current-stack-group-resumer are documented on (current-stack-group-var).

Variable: sys:%current-stack-group-state

The sg-state of the currently-running stack group.

Variable: sys:%current-stack-group-calling-args-pointer

The argument list of the currently-running stack group.

Variable: sys:%current-stack-group-calling-args-number

The number of arguments to the currently-running stack group.

Variable: sys:%trap-micro-pc

The microcode address of the most recent error trap.

Variable: sys:%initial-fef

The function that is called when the machine starts up. Normally this is the definition of si:lisp-top-level.

Variable: sys:%initial-stack-group

The stack group in which the machine starts up. Normally this is the initial Lisp Listener window’s process’s stack group.

Constant: sys:%error-handler-stack-group

The stack group that receives control when a microcode-detected error occurs. This stack group cleans up, signals the appropriate condition, or assigns a stack group to run the debugger on the erring stack group.

Constant: sys:%scheduler-stack-group

The stack group that receives control when a sequence break occurs.

Constant: sys:%chaos-csr-address

A fixnum, the virtual address that maps to the Unibus location of the Chaosnet interface.

Variable: %mar-low

A fixnum, the inclusive lower bound of the region of virtual memory subject to the MAR feature (see (mar)).

Variable: %mar-high

A fixnum, the inclusive upper bound of the region of virtual memory subject to the MAR feature (see (mar)).

Variable: sys:%inhibit-read-only

If non-nil, you can write into read-only areas. This is used by fasload.

self is documented on (self-var).

inhibit-scheduling-flag is documented on (inhibit-scheduling-flag-var).

Variable: inhibit-scavenging-flag

If non-nil, the scavenger is turned off. The scavenger is the quasi-asynchronous portion of the garbage collector, which normally runs during consing operations.

Variable: sys:scavenger-ws-enable

If this is nil, scavenging can compete for all of the physical memory of the machine. Otherwise, it should be a fixnum, which specifies how much physical memory the scavenger can use: page numbers as high as this number or higher are not available to it.

Variable: sys:%region-cons-alarm

Increments whenever a new region is allocated.

Variable: sys:%page-cons-alarm

Increments whenever a new page is allocated.

Variable: sys:%gc-flip-ready

t while the scavenger is running, nil when there are no pointers to oldspace.

Variable: sys:%gc-generation-number

A fixnum which is incremented whenever the garbage collector flips, converting one or more regions from newspace to oldspace. If this number has changed, the %pointer of an object may have changed.

Constant: sys:%disk-run-light

A fixnum, the virtual address of the TV buffer location of the run-light which lights up when the disk is active. This plus 2 is the address of the run-light for the processor. This minus 2 is the address of the run-light for the garbage collector.

Variable: sys:%loaded-band

A fixnum, the high 24 bits of the name of the disk partition from which virtual memory was booted. Used to create the greeting message.

Variable: sys:%disk-blocks-per-track
Variable: sys:%disk-blocks-per-cylinder

Configuration of the disk being used for paging. Don’t change these!

sys:%disk-switches is documented on (sys:%disk-switches-var).

Variable: sys:%qlaryh

This is the last array to be called as a function, remembered for the sake of the function store.

Variable: sys:%qlaryl

This is the index used the last time an array was called as a function, remembered for the sake of the function store.

Variable: sys:%mc-code-exit-vector

This is a vector of pointers that microcompiled code uses to refer to quoted constants.

Variable: sys:currently-prepared-sheet

Used for communication between the window system and the microcoded graphics primitives.

alphabetic-case-affects-string-comparison is documented on (alphabetic-case-affects-string-comparison-var).

sys:tail-recursion-flag is documented on (tail-recursion-flag-var).

zunderflow is documented on (zunderflow-var).

The next four have to do with implementing the metering system described in (meter-section).

Variable: sys:%meter-global-enable

t if the metering system is turned on for all stack-groups.

Variable: sys:%meter-buffer-pointer

A temporary buffer used by the metering system.

Variable: sys:%meter-disk-address

Where the metering system writes its next block of results on the disk.

Variable: sys:%meter-disk-count

The number of disk blocks remaining for recording of metering information.

Variable: sys:lexical-environment

This is the static chain used in the implementation of lexical scoping of variable bindings in compiled code.

Variable: sys:amem-evcp-vector

No longer used.

background-cons-area is documented on (background-cons-area-var).

sys:self-mapping-table is documented on (sys:self-mapping-table-var).

sys:processor-type-code is documented on (sys:processor-type-code-var).

Constant: sys:a-memory-location-names

A list of all of the above symbols (and any others added after this documentation was written).

15.19 Microcode Meters

Microcode meters are locations in the scratchpad memory which contain numbers. Most of them are used to count events of various sorts. They are accessible only through the functions read-meter and write-meter. They have nothing to do with the Lisp metering tools.

Function: read-meter name

Returns the contents of the microcode meter named name, which can be a fixnum or a bignum. name must be one of the symbols listed below.

Function: write-meter name value

Writes value, a fixnum or a bignum, into the microcode meter named name. name must be one of the symbols listed below.

The microcode meters are as follows:

Meter: sys:%count-chaos-transmit-aborts

The number of times transmission on the Chaosnet was aborted, either by a collision or because the receiver was busy.

Meter: sys:%count-cons-work
Meter: sys:%count-scavenger-work

Internal state of the garbage collection algorithm.

Meter: sys:%tv-clock-rate

The number of TV frames per clock sequence break. The default value is 67., which causes clock sequence breaks to happen about once per second.

Meter: sys:%count-first-level-map-reloads

The number of times the first-level virtual-memory map was invalid and had to be reloaded from the page hash table.

Meter: sys:%count-second-level-map-reloads

The number of times the second-level virtual-memory map was invalid and had to be reloaded from the page hash table.

Meter: sys:%count-meta-bits-map-reloads

The number of times the virtual address map was reloaded to contain only “meta bits”, not an actual physical address.

Meter: sys:%count-pdl-buffer-read-faults

The number of read references to the pdl buffer that were virtual memory references that trapped.

Meter: sys:%count-pdl-buffer-write-faults

The number of write references to the pdl buffer that were virtual memory references that trapped.

Meter: sys:%count-pdl-buffer-memory-faults

The number of virtual memory references that trapped in case they should have gone to the pdl buffer, but turned out to be real memory references after all (and therefore were needlessly slowed down).

Meter: sys:%count-disk-page-reads

The number of pages read from the disk.

Meter: sys:%count-disk-page-writes

The number of pages written to the disk.

Meter: sys:%count-fresh-pages

The number of fresh (newly-consed) pages created in core, which would have otherwise been read from the disk.

Meter: sys:%count-disk-page-read-operations

The number of paging read operations; this can be smaller than the number of disk pages read when more than one page at a time is read.

Meter: sys:%count-disk-page-write-operations

The number of paging write operations; this can be smaller than the number of disk pages written when more than one page at a time is written.

Meter: sys:%count-disk-prepages-used

The number of times a page was used after being read in before it was needed.

Meter: sys:%count-disk-prepages-not-used

The number of times a page was read in before it was needed, but got evicted before it was ever used.

Meter: sys:%count-disk-page-write-waits

The number of times the machine waited for a page to finish being written out in order to evict the page.

Meter: sys:%count-disk-page-write-busys

The number of times the machine waited for a page to finish being written out in order to do something else with the disk.

Meter: sys:%disk-wait-time

The time spent waiting for the disk, in microseconds. This can be used to distinguish paging time from running time when measuring and optimizing the‘ performance of programs.

Meter: sys:%count-disk-errors

The number of recoverable disk errors.

Meter: sys:%count-disk-recalibrates

The number of times the disk seek mechanism was recalibrated, usually as part of error recovery.

Meter: sys:%count-disk-ecc-corrected-errors

The number of disk errors that were corrected through the error correcting code.

Meter: sys:%count-disk-read-compare-differences

The number of times a read compare was done, no disk error occurred, but the data on disk did not match the data in memory.

Meter: sys:%count-disk-read-compare-rereads

The number of times a disk read was done over because after the read a read compare was done and did not succeed (either it got an error or the data on disk did not match the data in memory).

Meter: sys:%count-disk-read-compare-rewrites

The number of times a disk write was done over because after the write a read compare was done and did not succeed (either it got an error or the data on disk did not match the data in memory).

Meter: sys:%disk-error-log-pointer

Address of the next entry to be written in the disk error log. The function si:print-disk-error-log (see (si:print-disk-error-log-fun)) prints this log.

Meter: sys:%count-aged-pages

The number of times the page ager set an age trap on a page, to determine whether it was being referenced.

Meter: sys:%count-age-flushed-pages

The number of times the page ager saw that a page still had an age trap and hence made it “flushable”, a candidate for eviction from main memory.

Meter: sys:%aging-depth

A number from 0 to 3 that controls how long a page must remain unreferenced before it becomes a candidate for eviction from main memory.

Meter: sys:%count-findcore-steps

The number of pages inspected by the page replacement algorithm.

Meter: sys:%count-findcore-emergencies

The number of times no evictable page was found and extra aging had to be done.

Constant: sys:a-memory-counter-block-names

A list of all of the above symbols (and any others added after this documentation was written).

15.20 Miscellaneous Subprimitives

Function: sys:%halt

Stops the machine.

16 Areas

Storage in the Lisp Machine is divided into areas. Each area contains related objects, of any type. Areas are intended to give the user control over the paging behavior of the program, among other things. Putting frequently used data and rarely used data in different areas can cause the frequently used data to occupy fewer pages. For example, the system puts the debugging info alists of compiled functions in a special area so that the other list structure the functions point to will be more compact.

Whenever a new object is created the area to be used can optionally be specified. For example, instead of using cons you can use cons-in-area (see (cons-in-area-fun)). Object-creating functions which take keyword arguments generally accept a :area argument. You can also control which area is used by binding default-cons-area (see (default-cons-area-var)); most functions that allocate storage use the value of this variable, by default, to specify the area to use.

There is a default ‘working storage’ area that collects those objects that the user has not chosen to control explicitly.

Areas also give the user a handle to control the garbage collector. Some areas can be declared to be static, which means that they change slowly and the garbage collector should not attempt to reclaim any space in them. This can eliminate a lot of useless copying. A static area can be explicitly garbage-collected at infrequent intervals when it is believed that that might be worthwhile.

Each area can potentially have a different storage discipline, a different paging algorithm, and even a different data representation. The microcode dispatches on attributes of the area at the appropriate times. The structure of the machine makes the performance cost of these features negligible; information about areas is stored in extra bits in the memory mapping hardware where it can be quickly dispatched on by the microcode; these dispatches usually have to be done anyway to make the garbage collector work and to implement invisible pointers. This feature is not currently used by the system, except for the list/structure distinction described below.

Each area has a name and a number. The name is a symbol whose value is the number. The number is an index into various internal tables. Normally the name is treated as a special variable, so the number is what is given as an argument to a function that takes an area as an argument. Thus, areas are not Lisp objects; you cannot pass an area itself as an argument to a function; you just pass its number. There is a maximum number of areas (set at cold-load generation time); you can only have that many areas before the various internal tables overflow. Currently (as this manual is written) the limit is 256 areas, of which 64 already exist when you start.

The storage of an area consists of one or more regions. Each region is a contiguous section of address space with certain homogeneous properties. The most important of these is the data representation type. A given region can only store one type. The two types that exist now are list and structure. A list is anything made out of conses (a closure for instance). A structure is anything made out of a block of memory with a header at the front; symbols, strings, arrays, instances, compiled functions, etc. Since lists and structures cannot be stored in the same region, they cannot be on the same page. It is necessary to know about this when using areas to increase locality of reference.

When you create an area, one region is created initially. When you try to allocate memory to hold an object in some area, the system tries to find a region that has the right data representation type to hold this object, and that has enough room for it to fit. If there isn’t any such region, it makes a new one (or signals an error; see the :size option to make-area, below). The size of the new region is an attribute of the area (controllable by the :region-size option to make-area). If regions are too large, memory may get taken up by a region and never used. If regions are too small, the system may run out of regions because regions, like areas, are defined by internal tables that have a fixed size (set at cold-load generation time). Currently (as this manual is written) the limit is 256 regions, of which about 105 already exist when you start. (If you’re wondering why the limit on regions isn’t higher than the limit on areas, as it clearly ought to be, it’s just because both limits have to be multiples of 256 for internal reasons, and 256 regions seem to be enough.)

16.1 Area Functions and Variables

Variable: default-cons-area

The value of this variable is the number of the area in which objects are created by default. It is initially the number of working-storage-area. Giving nil where an area is required uses the value of default-cons-area. Note that to put objects into an area other than working-storage-area you can either bind this variable or use functions such as cons-in-area (see (cons-in-area-fun)) which take the area as an explicit argument.

Variable: background-cons-area

The value of this variable is the number of a non-temporary area in which objects created as incidental side effects by system functions should be created. This area is used whenever an object is created that should never be in a temporary area, even if default-cons-area is a temporary area.

By default, this area is working-storage-area.

Function: make-area &key name size region-size representation gc read-only pdl room

Creates a new area, whose name and attributes are specified by the keywords. You must specify a symbol as a name; the symbol is setq’ed to the area-number of the new area, and that number is also returned, so that you can use make-area as the initialization of a defvar.

Here are the meanings of the keywords:

name

A symbol that will be the name of the area. This item is required.

size

The maximum allowed size of the area, in words. Defaults to infinite. (Actually, the default is the largest positive fixnum; but the area is not limited to that size!) If the number of words allocated to the area reaches this size, attempting to cons an object in the area will signal an error.

region-size

The approximate size, in words, for regions within this area. The default is the area size if a :size argument was given, otherwise it is a suitable medium size. Note that if you specify :size and not :region-size, the area will have exactly one region. When making an area that will grow very big, it is desirable to make the region size larger than the default region size to avoid creating very many regions and possibly overflowing the system’s fixed-size region tables.

representation

The type of object to be contained in the area’s initial region. The argument to this keyword can be :list, :structure, or a numeric code. :structure is the default. If you are only going to cons lists in your area, you should specify :list so you don’t get a useless structure region.

gc

The type of garbage-collection to be employed. The choices are :dynamic (which is the default), :static, and :temporary. :static means that the area will not be copied by the garbage collector, and nothing in the area or pointed to by the area will ever be reclaimed, unless a garbage collection of this area is manually requested. :temporary is like :static, but in addition you are allowed to use si:reset-temporary-area on this area.

read-only

With an argument of t, causes the area to be made read-only. Defaults to nil. If an area is read-only, then any attempt to change anything in it (altering a data object in the area or creating a new object in the area) will signal an error unless sys:%inhibit-read-only (see (sys:%inhibit-read-only-var)) is bound to a non-nil value.

pdl

With an argument of t, makes the area suitable for storing regular-pdls of stack-groups. This is a special attribute due to the pdl-buffer hardware. Defaults to nil. Areas for which this is nil may not be used to store regular-pdls. Areas for which this is t are relatively slow to access; all references to pages in the area will take page faults to check whether the referenced location is really in the pdl-buffer.

room

With an argument of t, adds this area to the list of areas that are displayed by default by the room function (see (room-fun)).

Example:
(make-area :name 'foo-area
	   :gc :dynamic
	   :representation :list)
Function: describe-area area

area may be the name or the number of an area. Various attributes of the area are printed.

Variable: area-list

The value of area-list is a list of the names of all existing areas. This list shares storage with the internal area name table, so you should not change it.

Function: %area-number pointer

Returns the number of the area to which pointer points, or nil if it does not point within any known area. The data-type of pointer is ignored.

Function: %region-number pointer

Returns the number of the region to which pointer points, or nil if it does not point within any known region. The data-type of pointer is ignored. (This information is generally not very interesting to users; it is important only inside the system.)

Function: area-name number

Given an area number, returns the name. This “function” is actually an array.

Function: si:reset-temporary-area area-number

This very dangerous operation marks all the storage in area area-number as free and available for re-use. Any data in the area is lost and pointers to it become meaningless. In principle, this operation should only be used if you are sure there are no pointers into the area.

If the area was not defined as temporary, this function gets an error.

See also cons-in-area ((cons-in-area-fun)), list-in-area ((list-in-area-fun)), and room ((room-fun)).

16.2 Interesting Areas

This section lists the names of some of the areas and tells what they are for. Only the ones of the most interest to a user are listed; there are many others.

Constant: working-storage-area

This is the normal value of default-cons-area. Most working data are consed in this area.

Constant: permanent-storage-area

This area is to be used for permanent data, which will (almost) never become garbage. Unlike working-storage-area, the contents of this area are not continually copied by the garbage collector; it is a static area.

Constant: sys:extra-pdl-area

The ‘number consing area’ in which floating point numbers, ratios and bignums are normally created. If a pointer to a number in this area is stored anywhere outside the machine registers and current stack, a copy of the number is made in working-storage-area and a pointer to the copy is stored instead. When sys:extra-pdl-area gets full, the all numbers pointed to by the registers and current stack are copied, and then nothing in the area can be in use any more, so it is marked as empty.

Constant: sys:p-n-string

Print-names of symbols are stored in this area.

Constant: sys:nr-sym

Contains most of the symbols in the Lisp world, except t and nil.

Constant: sys:resident-symbol-area

Contains the symbols t and nil. nil is known to be at address zero.

Constant: sys:pkg-area

This area contains packages, principally the hash tables with which intern keeps track of symbols.

Constant: macro-compiled-program

Compiled functions (FEFs) are put here by the compiler and by fasload. So are the constants that they refer to.

Constant: sys:property-list-area

This area holds the property lists of symbols.

16.3 Errors Pertaining to Areas

Condition: sys:area-overflow (error)

This is signaled on an attempt to make an area bigger than its declared maximum size.

The condition instance supports the operations :area-name and :area-maximum-size.

Condition: sys:region-table-overflow (error)

This is signaled if you run out of regions.

Condition: sys:virtual-memory-overflow (error)

This is signaled if all of virtual memory is part of some region and an attempt is made to allocate a new region. There may be free space left in some regions in other areas, but there is no way to apply it to the area in which storage is to be allocated.

Condition: sys:cons-in-fixed-area (error)

This is signaled if an attempt is made add a second region to a fixed area. The fixed areas are certain areas, created at system initialization, that are only allowed a single region, because their contents must be contiguous in virtual memory.

17 The Compiler

17.1 The Basic Operations of the Compiler

The purpose of the Lisp compiler is to convert Lisp functions into programs in the Lisp Machine’s instruction set, so that they run more quickly and take up less storage. Compiled functions are represented in Lisp by FEFs (Function Entry Frames), which contain machine code as well as various other information. The printed representation of a FEF is

#<DTP-FEF-POINTER address name>

If you want to understand the output of the compiler, refer to (understanding-compiled-code).

There are three ways to invoke the compiler from the Lisp Machine. First, you may have an interpreted function in the Lisp environment that you would like to compile. The function compile is used to do this. Second, you may have code in an editor buffer that you would like to compile. The Zmacs editor has commands to read code into Lisp and compile it. Third, you may have a program (a group of function definitions and other forms) written in a file on the file system. The function compile-file can translate this file into a QFASL file that describes the compiled functions and associated data. The QFASL file format is capable of representing an arbitrary collection of Lisp objects, including shared structure. The name derives from ‘Q’, a prefix once used to mean “for the Lisp Machine, not for Maclisp”, and ‘FASL’, an abbreviation for “fast loading”.

17.2 How to Invoke the Compiler

Function: compile function-spec &optional definition

Compiles an individual interpreted function definition. If definition is supplied, it is the definition to be compiled. Otherwise, the current definition of function-spec is used. If function-spec is non-nil, the compiled function is stored as the definition of function-spec, and function-spec is returned. Otherwise, the compiled function object itself is returned. (However, it is preferable to use compile-lambda if your wish is to create a compiled function object without storing it anywhere.)

The compiled function object created by compile records the interpreted definition it was made from on its debugging info alist (see (debugging-info-fun)). This is useful in two ways: the function uncompile can be used to reinstall the interpreted definition, and compile invoked again on the same function-spec can find the interpreted definition used before and compile it again. The latter is useful if you have changed some macros or subst functions which the definition refers to.

Function: uncompile function-spec

If function-spec is defined as a compiled function that records the original definition that was compiled, then function-spec is redefined with that original definition. This undoes the effect of calling compile on function-spec.

Function: compile-lambda lambda-exp function-spec

Returns a compiled function object pro