SECTION 5
PRIMITIVE FUNCTIONS AND PREDICATES
5.1 Primitive Functions
car[x] car gives the first element of a list x, or the
left element of a dotted pair x. car of NIL is
always NIL. For all other nonlists, e.g.,
atoms, strings, arrays, and numbers, the value
is undefined (and on some implementations may
generate an error).
cdr[x] cdr gives the rest of a list (all but the first
element). This is also the right member of a
dotted pair. cdr of NIL is always NIL. The
value of cdr is undefined for other nonlists.
caar[x] = car[car[x]] All 30 combinations of nested cars and cdrs up
to 4 deep
cadr[x] = car[cdr[x]] are included in the system. All are compiled
cddddr[x] = open by the compiler.
cdr[cdr[cdr[cdr[x]]]]
cons[x;y] cons constructs a dotted pair of x and y. If y
is a list, x becomes the first element of that
list. To minimize drum accesses the following
algorithm is used in INTERLISP-10, for finding a
page on which to put the constructed INTERLISP
word.
cons[x;y] is placed
1) on the page with y if y is a list and there is room;
otherwise
2) on the page with x if x is a list and there is room;
otherwise
3) on the same page as the last cons if there is room;
otherwise
4) on any page with a specified minimum of storage, presently 16
LISP words.
conscount[] value is the number of conses since this
INTERLISP was started up.
rplacd[x;y] Places the pointer y in the decrement, i.e.,
5.1
cdr, of the cell pointed to by x. Thus it
physically changes the internal list structure
of x, as opposed to cons which creates a new
list element. The only way to get a circular
list is by using rplacd to place a pointer to
the beginning of a list in a spot at the end of
the list.
The value of rplacd is x. An attempt to rplacd
NIL will cause an error, ATTEMPT TO RPLAC NIL,
(except for rplacd[NIL;NIL]). An attempt to
rplacd any other non-list will cause an error
ARG NOT LIST.
rplaca[x;y] similar to rplacd, but replaces the address
pointer of x, i.e., car, with y. The value of
rplaca is x. An attempt to rplaca NIL will
cause an error, ATTEMPT TO RPLAC NIL, (except
for rplaca[NIL;NIL]). An attempt to rplaca any
other non-list will cause an error, ARG NOT
LIST.
Convention: Naming a function by prefixing an existing function name
with f usually indicates that the new function is a fast version of the
old, i.e., one which has the same definition but compiles open and runs
without any "safety" error checks.
frplacd[x;y] Has the same definition as rplacd but compiles
open as one instruction. Note that no checks
are made on x, so that a compiled frplacd can
clobber NIL, producing strange and wondrous
effects.
frplaca[x;y] Similar to frplacd.
quote[x] This is a function that prevents its arguments
from being evaluated. Its value is x itself,
1
e.g., (QUOTE FOO) is FOO.
kwote[x] (LIST (QUOTE QUOTE) x),
if x=A, and y=B, then
(KWOTE (CONS x y))= (QUOTE (A . B)).
------------------------------------------------------------------------
1
Since giving quote more than one argument, e.g.,
(QUOTE EXPR (CONS X Y)), is almost always a parentheses error, and
one that would otherwise go undetected, quote itself generates an
error in this case, PARENTHESIS ERROR.
5.2
cond[c1;c2;...;ck] The conditional function of INTERLISP, cond,
takes an indefinite number of arguments c1,c2,
... ck, called clauses. Each clause ci is a list
(e1i ... eni) of n > 1 items, where the first
element is the predicate, and the rest of the
elements the consequents. The operation of cond
can be paraphrased as IF e11 THEN e21 ... en1
ELSEIF e12 THEN e22 ... en2 ELSEIF e13 ...
The clauses are considered in sequence as
follows: the first expression e1i of the clause
ci is evaluated and its value is classified as
false (equal to NIL) or true (not equal to NIL).
If the value of e1i is true, the expressions e2i
... eni that follow in clause ci are evaluated
in sequence, and the value of the conditional is
the value of eni, the last expression in the
clause. In particular, if n=1, i.e., if there
is only one expression in the clause ci, the
value of the conditional is the value of e1i.
(which is evaluated only once).
If e1i is false, then the remainder of clause ci
is ignored, and the next clause ci+1 is
considered. If no e1i is true for any clause,
the value of the conditional expression is NIL.
selectq[x;y1;y2;...;yn;z]
selects a form or sequence of forms based on the
value of its first argument x. Each yi is a
list of the form (si e1i e2i ... eki) where si
is the selection key. The operation of selectq
can be paraphrased as:
IF x=s1 THEN e1i ... eki
ELSEIF x=s2 THEN ... ELSE z.
If si is an atom, the value of x is tested to
see if it is eq to si (not evaluated). If so,
the expressions e1i ... eki are evaluated in
sequence, and the value of the selectq is the
value of the last expression evaluated,
i.e., eki.
If si is a list, the value of x is compared with
each element (not evaluated) of si, and if x is
eq to any one of them, then e1i to eki are
evaluated in turn as above.
If yi is not selected in one of the two ways
described, yi+1 is tested, etc., until all the
y's have been tested. If none is selected, the
value of the selectq is the value of z. z must
be present.
An example of the form of a selectq is:
5.3
[SELECTQ (CAR X)
(Q (PRINT FOO)
(FIE X))
((A E I O U)
(VOWEL X))
(COND
((NULL X)
NIL)
(T (QUOTE STOP]
which has two cases, Q and (A E I O U) and a
default condition which is a cond.
selectq compiles open, and is therefore very
fast; however, it will not work if the value of
x is a list, a large integer, or floating point
number, since selectq uses eq for all
comparisons.
prog1[x1;x2;...;xn] evaluates its arguments in order, that is, first
x1, then x2, etc, and returns the value of its
first argument x1, e.g., (PROG1 X (SETQ X Y))
sets x to y, and returns x's original value.
progn[x1i;x2i;...;xn] progn evaluates each of its arguments in order,
and returns the value of its last argument as
its value. progn is used to specify more than
one computation where the syntax allows only
one, e.g., (SELECTQ ... (PROGN ...)) allows
evaluation of several expressions as the default
condition for a selectq.
prog[args;e1;e2;...;en] This function allows the user to write an
ALGOL-like program containing INTERLISP
expressions (forms) to be executed. The first
argument, args, is a list of local variables
(must be NIL if no variables are used). Each
atom in args is treated as the name of a local
variable and bound to NIL. args can also
contain lists of the form (atom form). In this
case, atom is the name of the variable and is
bound to the value of form. The evaluation
takes place before any of the bindings are
performed, e.g., (PROG ((X Y) (Y X)) ...) will
bind x to the value of y and y to the (original)
value of x.
The rest of the prog is a sequence of non-atomic
statements (forms) and atomic symbols used as
labels for go. The forms are evaluated
sequentially; the labels serve only as markers.
The two special functions go and return alter
this flow of control as described below. The
value of the prog is usually specified by the
5.4
function return. If no return is executed,
i.e., if the prog "falls off the end," the value
of the prog is NIL.
go[x] go is the function used to cause a transfer in a
prog. (GO L) will cause the program to continue
at the label L. A go can be used at any level
in a prog. If the label is not found, go will
search higher progs within the same function,
e.g., (PROG -- A -- (PROG -- (GO A))). If the
label is not found in the function in which the
prog appears, an error is generated, UNDEFINED
OR ILLEGAL GO.
return[x] A return is the normal exit for a prog. Its
argument is evaluated and is the value of the
prog in which it appears.
If a go or return is executed in an interpreted function which is not a
prog, the go or return will be executed in the last interpreted prog
entered if any, otherwise cause an error.
go or return inside of a compiled function that is not a prog is not
allowed, and will cause an error at compile time.
As a corollary, go or return in a functional argument, e.g., to sort,
will not work compiled. Also, since nlsetq's and ersetq's compile as
separate functions, a go or return cannot be used inside of a compiled
nlsetq or ersetq if the corresponding prog is outside, i.e., above, the
nlsetq or ersetq.
set[x;y] This function sets x to y. Its value is y. If
x is not a literal atom, causes an error,
ARG NOT LITATOM. If x is NIL, causes an error,
ATTEMPT TO SET NIL. Note that set is a normal
lambda-spread function, i.e., its arguments are
evaluated before it is called. Thus, if the
value of x is c, and the value of y is b, then
set[x;y] would result in c having value b, and b
being returned as the value of set.
setq[x;y] An nlambda version of set: the first argument is
5.5
2
not evaluated, the second is. Thus if the value
of X is C and the value of Y is B, (SETQ X Y)
would result in X (not C) being set to B, and B
being returned. If x is not a literal atom, an
error is generated, ARG NOT LITATOM. If x is
NIL, the error ATTEMPT TO SET NIL is generated.
setqq[x;y] Like setq except that neither argument is
evaluated, e.g., (SETQQ X (A B C)) sets x to
(A B C).
gettopval[atm] returns top level value of atm from its value
cell (even if NOBIND), regardless of any
intervening bindings. Interpreted, generates an
error, ARG NOT LITATOM, if atm is not a literal
atom. Compiles open without any error checks.
settopval[atm;val] Sets top level value of atm, regardless of any
intervening bindings, i.e., stores val in value
cell of atm. Value is val. Interpreted,
generates an error ATTEMPT TO SET NIL, if
atm=NIL, or ARG NOT LITATOM, if atm is not a
literal atom. Compiles open without any error
checks.
rpaq[x;y] An nlambda function like setq, except always
works on top level value of x, i.e., on the
value cell.
rpaqq[x;y] An nlambda function like setqq for top level
values.
rpaq and rpaqq are used by prettydef (Section 14). Both rpaq and rpaqq
generate errors if x is not a literal atom. Both are affected by the
value of dfnflg (Section 8). If dfnflg = ALLPROP (and the value of x is
other than NOBIND), instead of setting x, the corresponding value is
stored on the property list of x under the property VALUE. Both are
undoable.
------------------------------------------------------------------------
2
Since setq is an nlambda, neither argument is evaluated during the
calling process. However, setq itself calls eval on its second
argument. Note that as a result, typing (SETQ var form) and
SETQ(var form) to lispx is equivalent: in both cases var is not
evaluated, and form is.
5.6
Changing and Restoring System State
In INTERLISP, a computation can be interrupted/aborted at any point due
to an error, or more forcefully, because a control-D was typed, causing
return to the top level. This situation creates problems for programs
that need to perform a computation with the system in a "different
state", e.g., different radix, input file, readtable, etc. or simply a
different value for some global variable, e.g., helpflag, dfnflg, etc.,
but want to "protect" the calling environment, i.e., be able to restore
the state when the computation has completed. While errors can be
3
"caught" by errorsets, control-D cannot. Thus the system may be left in
its changed state as a result of the computation being aborted. The
following functions address this problem:
resetlst[resetx] nlambda, nospread. resetx is a list of forms.
resetlst sets up an errorset so that any reset
operations performed by resetsave (see below)
are restored when the evaluation of resetx has
been completed (or an error occurs, or a
control-D is typed). If no error occurs, the
value of resetlst is the value of the last form
on resetx, otherwise resetlst generates an error
(after performing the necessary restorations).
resetlst compiles open.
resetsave[resetx] nlambda, nospread function for use under a
4
resetlst. If car of resetx is atomic, resets
the top level value of car of resetx to the
value of cadr of resetx, e.g.,
(RESETSAVE LISPXHISTORY EDITHISTORY) resets the
value of lispxhistory to be edithistory and
provides for the original value of lispxhistory
to be restored when the resetlst completes
operation, (or an error occurs, or a control-D
is typed).
If car of resetx is not atomic, it is a form
that is evaluated. If cdr of resetsave is NIL,
e.g., (RESETSAVE (RADIX 8)), the form must
return as its value its "former state", so that
------------------------------------------------------------------------
3
i.e., not conveniently. The program could of course redefine
control-D as a userinterrupt, check for it, reenable it, and call
reset or something similar.
4
resetsave can be called when not under a resetlst. In this case,
the restoration will be performed at the next RESET, i.e., control-D
or control-C reenter. In other words, there is an "implicit"
resetlst at the top level in evalqt.
5.7
the effect of evaluating the form can be
reversed, and the system state can be restored,
by applying car of the form to the value of the
form, e.g., (RESETSAVE (RADIX 8)) performs
(RADIX 8), and provides for radix to be reset to
its original value when the resetlst completes
by applying radix to the value returned by
(RADIX 8).
For functions which do not return their
"previous setting", the restoring expression can
be specified as the value of the second argument
to resetsave, which in this case is evaluated
before the first argument, e.g.,
5
[RESETSAVE(SETBRK --)(LIST(QUOTE SETBRK)(GETBRK].
will restore the break characters by applying
setbrk to the value returned by (GETBRK), which
was computed before the (SETBRK --) expression
was evaluated.
(RESETSAVE NIL form) is permissible. It simply
specifies that the value of form be treated as a
restoration expression, e.g.,
(RESETSAVE NIL (LIST (QUOTE CLOSEF) FILE)) will
cause file to be closed when the resetlst that
the resetsave is under completes (or an error
occurs or a control-D is typed).
resetsave compiles open. Its value is not a
"useful" quantity.
resetvar[var;new-value;form]
Nlambda function. Simplified form of resetlst
and resetsave for resetting and restoring global
variables. Equivalent to
(RESETLST (RESETSAVE var new-value) form), e.g.,
(RESETVAR LISPXHISTORY EDITHISTORY (FOO)) resets
lispxhistory to the value of edithistory while
evaluating (FOO). resetvar compiles open. If
no error occurs, its value is the value of form.
resetform[form1;form2] Nlambda function. Simplified form of resetlst
and resetsave for resetting a system state when
the corresponding function returns as its value
the "previous setting." Equivalent to
(RESETLST (RESETSAVE form1) form2), e.g.,
(RESETFROM (RADIX 8) (FOO)). resetform compiles
open. If no error occurs, its value is the
value returned by form2.
------------------------------------------------------------------------
5
Note that the restoration expression is still "evaluated" by
applying its car to its cdr.
5.8
For some applications, the restoration operation must be different
depending on whether the computation completed successfully or was
aborted by an error or control-D. To facilitate this, while the
restoration operation is being performed, the value of resetstate will
be bound to NIL, ERROR, or RESET, depending on whether the exit was
normal, due to an error, or reset (i.e., control-D, or in INTERLISP-10,
control-C followed by reenter). For example,
(RESETLST (RESETSAVE (INFILE X) (LIST '[LAMBDA (FL)
(AND (EQ RESETSTATE 'RESET) (CLOSEF FL) (DELFILE FL] X))
. forms)
will cause X to be closed and deleted only if a control-D was typed
during the execution of forms.
For convenience in specifying complicated restoring expressions, the
variable oldvalue is bound to the value of the saving expression. For
example,
6
(RESETLST (RESETSAVE (INPUT FL) '(AND RESETSAVE (INPUT OLDVALUE)))
. forms)
will restore the primary input file if an error or control-D occurs.
In addition, the function resetundo, in conjunction with resetlst and
resetsave, provides a way of specifying that the system be restored to
its prior state by undoing the side effects of the computations
performed under the resetlst. Undoing and resetundo are described in
Section 22.
5.2 Predicates and Logical Connectives
atom[x] is T if x is an atom; NIL otherwise.
litatom[x] is T if x is a literal atom, i.e., an atom and
not a number, NIL otherwise.
numberp[x] is x if x is a number, NIL otherwise.
Convention: Functions that end in p are usually predicates, i.e., they
test for some condition.
------------------------------------------------------------------------
6
Without using oldvalue, the user would have to write
(RESETLST
(SETQ TEM (INPUT FL))
(RESETSAVE NIL (LIST '(LAMBDA (FL) (AND RESETSTATE (INPUT
FL)))
TEM))
forms)
5.9
7
stringp[x] is x if x is a string, NIL otherwise.
arrayp[x] is x if x is an array, NIL otherwise.
listp[x] is x if x is a list-structure, i.e., one created
by one or more conses; NIL otherwise.
Note that arrays and strings are not atoms, but are also not lists,
i.e., both atom and listp will return NIL when given an array or a
string.
nlistp[x] not[listp[x]]
eq[x;y] The value of eq is T, if x and y are pointers to
the same structure in memory, and NIL otherwise.
eq is compiled open by the compiler. Its value
is not guaranteed T for equal numbers which are
not small integers. See eqp.
neq[x;y] The value of neq is T, if x is not eq to y, and
NIL otherwise.
null[x] eq[x;NIL]
not[x] same as null, that is eq[x;NIL].
eqp[x;y] The value of eqp is T if x and y are eq, i.e.,
pointers to the same structure in memory, or if
8
x and y are numbers and are equal in value. Its
value is NIL otherwise.
equal[x;y] The value of equal is T (1) if x and y are eq,
i.e., pointers to the same structure in memory;
or (2) eqp, i.e., numbers with equal value; or
(3) strequal, i.e., strings containing the same
sequence of characters; or (4) lists and car of
------------------------------------------------------------------------
7
For other string functions, see Section 10.
8
For more discussion of eqp and other number functions, see Section
13.
5.10
x is equal to car of y, and cdr of x is equal to
9
cdr of y. The value of equal is NIL otherwise.
Note that x and y do not have to be eq.
equaln[x;y;depth] like equal, except if depth of car recursion
plus depth of cdr recursion exceeds depth,
assumes equality and does not search further
along that chain, e.g.,
equaln[(((A)) B);(((Z)) B);2]=T. For use with
(possibly) circular structures.
and[x1;x2;...;xn] Takes an indefinite number of arguments
(including 0). If all of its arguments have
non-null value, its value is the value of its
last argument, otherwise NIL. e.g.,
and[x;member[x;y]] will have as its value either
NIL or a tail of y. and[]=T. Evaluation stops
at the first argument whose value is NIL.
or[x1;x2;...;xn] Takes an indefinite number of arguments
(including 0). Its value is that of the first
argument whose value is not NIL, otherwise NIL
if all arguments have value NIL. e.g.,
or[x;numberp[y]] has its value x, y, or NIL.
or[]=NIL. Evaluation stops at the first
argument whose value is not NIL.
every[everyx;everyfn1;everyfn2]
Is T if the result of applying everyfn1 to each
element in everyx is true, otherwise NIL.
e.g., every[(X Y Z); ATOM]=T.
every operates by computing
10
everyfn1[car[everyx]]. If this yields NIL,
every immediately returns NIL. Otherwise, every
computes everyfn2[everyx], or cdr[everyx] if
everyfn2=NIL, and uses this as the "new" everyx,
and the process continues, e.g.,
every[x;ATOM;CDDR] is true if every other
element of x is atomic.
every compiles open.
------------------------------------------------------------------------
9
A loose description of equal might be to say that x and y are equal
if they print out the same way.
10
Actually, everyfn1[car[everyx];everyx] is computed, so for example
everyfn1 can look at the next element on everyx if necessary.
5.11
some[somex;somefn1;somefn2]
value is the tail of somex beginning with the
first element that satisfies somefn1, i.e., for
which somefn1 applied to that element is true.
Value is NIL if no such element exists.
e.g., some[x;(LAMBDA (Z) (EQUAL Z Y))] is
equivalent to member[y;x]. some operates
analogously to every. At each stage,
somefn1[car[somex];somex] is computed, and if
this is not NIL, somex is returned as the value
of some. Otherwise, somefn2[somex] is computed,
or cdr[somex] if somefn2=NIL, and used for the
next somex.
some compiles open.
notany[somex;somefn1,somefn2]
same as not[some[somex;somefn1;somefn2]]
notevery[everyx;everyfn1;everyfn2]
not[every[everyx;everyfn1;everyfn2]]
memb[x;y] Determines if x is a member of the list y, i.e.,
if there is an element of y eg to x. If so, its
value is the tail of the list y starting with
that element. If not, its value is NIL.
fmemb[x;y] Fast version of memb that compiles open as a
five instruction loop, terminating on a NULL
check. Interpreted, fmemb gives an error,
BAD ARGUMENT - FMEMB, if y ends in a non-list
other than NIL.
member[x;y] Identical to memb except that it uses equal
instead of eq to check membership of x in y.
The reason for the existence of both memb and member is that eq compiles
as one instruction but equal requires a function call, and is therefore
considerably more expensive. Wherever possible, the user should write
(and use) functions that use eq instead of equal.
tailp[x;y] Is x, if x is a tail of y, i.e., x is eq to some
11
number of cdrs > 0 1 of y, we say x is a
proper tail.> of y, NIL otherwise.
------------------------------------------------------------------------
11
If x is eq to some number of cdrs
5.12
assoc[key;alst] alst is a list of lists (usually dotted pairs).
The value of assoc is the first sublist of alst
whose car is eq to key. If such a list is not
found, the value is NIL. Example:
assoc[B;((A . 1) (B . 2) (C . 3))] = (B . 2).
fassoc[key;alst] Fast version of assoc that compiles open as a 6
instruction loop, terminating on a NULL check.
Interpreted, fassoc gives an error if alst ends
in a non-list other than NIL, BAD ARGUMENT -
FASSOC.
sassoc[key;alst] Same as assoc but uses equal instead of eq.
putassoc[key;val;alst] Searches alst for an element car of which is eq
to key. If one is found, cdr is replaced (using
rplacd) with val. If no such element is found,
cons[prop;val] is added at the end of alst.
Value is ?. If alst is NIL, generates an error,
ATTEMPT TO RPLAC NIL. Otherwise, if alst is not
a list, generates an error, ARG NOT LIST.
listget[lst;prop] Similar to getprop (Section 7) but works on
lists using property list format. Searches lst
two elements at a time, i.e., by cddr, looking
for an element eq to prop. If one is found,
returns the next element of lst, otherwise NIL.
Generates an ARG NOT LIST error if lst is non-
NIL and not a list.
listput[lst;prop;val] Similar to putprop. Searches lst by cddr
looking for prop. If prop is found, replaces
the next element of lst with val. Otherwise,
prop and val are added to the end of lst. Value
is ?. Generates an ARG NOT LIST error if lst is
not a list.
listget1[lst;prop] Like listget but searches lst one cdr at a time,
i.e., looks at each element.
listput1[lst;prop;val] Like listput except searches lst one cdr at a
time.
5.13