Trailing-Edge
-
PDP-10 Archives
-
decuslib20-01
-
decus/20-0004/8lisp.tty
There are no other files named 8lisp.tty in the archive.
SECTION 8
FUNCTION DEFINITION AND EVALUATION
General Comments
A function definition in INTERLISP is stored in a special cell called
the function definition cell, which is associated with each literal
atom. This cell is directly accessible via the two functions putd,
which puts a definition in the cell, and getd which gets the definition
from the cell. In addition, the function fntyp returns the function
type, i.e., EXPR, EXPR* ... FSUBR* as described in Section 4. Exprp,
ccodep, and subrp are true if the function is an expr, compiled
function, or subr respectively; argtype returns 0, 1, 2, or 3, depending
on whether the function is a spread or nospread (i.e., its fntyp ends in
*), or evaluate or no-evaluate (i.e., its fntyp begins with F or CF);
arglist returns the list of arguments; and nargs returns the number of
arguments. fntyp, exprp, ccodep, subrp, argtype, arglist, and nargs can
be given either a literal atom, in which case they obtain the function
definition from the atom's definition cell, or a function definition
itself.
Subrs
1
Because subrs are called in a special way, their definitions are stored
differently than those of compiled or interpreted functions. getd of a
subr returns a dotted pair, car of which is an encoding of the argtype
and number of arguments of the subr, and cdr of which is the address of
the first instruction. Note that each getd of a subr performs a cons.
Similarly, putd of a definition of the form (number . address), where
number and address are in the appropriate ranges, stores the definition
as a subr.
------------------------------------------------------------------------
1
Basic functions, handcoded in machine language, e.g., cons, car,
cond. The terms subr includes spread/nospread, eval/noeval
functions, i.e., the four fntyp's SUBR, FSUBR, SUBR*, and FSUBR*.
8.1
Validity of Definitions in INTERLISP-10
Although the function definition cell is intended for function
definitions, putd and getd do not make thorough checks on the validity
of definitions that "look like" exprs, compiled code, or subrs. Thus if
putd is given an array pointer, it treats it as compiled code, and
simply stores the array pointer in the definition cell. getd will then
return the array pointer. Similarly, a call to that function will
simply transfer to what would normally be the entry point for the
function, and produce random results if the array were not compiled
function.
Similarly, if putd is given a dotted pair of the form (number . address)
where number and address fall in the subr range, putd assumes it is a
subr and stores it away as described earlier. getd would then return a
dotted pair equal (but not eq) to the expression originally given putd.
Similarly, a call to this function would transfer to the corresponding
address.
Finally, if putd is given any other list, it simply stores it away. A
call to this function would then go through the interpreter as described
in the appendix.
Note that putd does not actually check to see if the s-expression is
valid definition, i.e., begins with LAMBDA or NLAMBDA. Similarly, exprp
is true if a definition is a list and not of the form
(number . address), number = 0, 1, 2, or 3 and address a subr address;
subrp is true if it is of this form. arglist and nargs work
correspondingly.
Only fntyp and argtype check function definitions further than that
described above: both argtype and fntyp return NIL when exprp is true
2
but car of the definition is not LAMBDA or NLAMBDA. In other words, if
the user uses putd to put (A B C) in a function definition cell, getd
will return this value, the editor and prettyprint will both treat it as
a definition, exprp will return T, ccodep and subrp NIL, arglist B, and
nargs 1.
getd[x] gets the function definition of x. Value is the
3
definition. Value is NIL if x is not a
literal atom, or has no definition.
------------------------------------------------------------------------
2
These functions have different value on LAMBDAs and NLAMBDAs and
hence must check. The compiler and interpreter also take different
actions for LAMBDAs and NLAMBDAs, and therefore generate errors if
the definition is neither.
3
Note that in INTERLISP-10, getd of a subr performs a cons, as
described on page 8.1.
8.2
fgetd[x] fast version of getd that compiles open.
Interpreted, generates an error, BAD ARGUMENT -
FGETD, if x is not a literal atom. Fgetd is
intended primarily to check whether a function
has a definition, rather than to obtain the
definition. Therefore, for subrs, fgetd returns
just the address of the function definition, not
the dotted pair returned by getd, page 8.1,
thereby saving the cons.
putd[x;y] puts the definition y into x's function cell.
Value is y. Generates an error, ARG NOT
LITATOM, if x is not a literal atom. Generates
an error, ILLEGAL ARG, if y is a string, number,
or literal atom other than NIL.
putdq[x;y] nlambda version of putd; both arguments are
considered quoted. Value is x.
movd[from;to;copyflg] Moves the definition of from to to, i.e.,
redefines to. If copyflg=T, a copy of the
definition of from is used. copyflg=T is only
meaningful for exprs, although movd works for
compiled functions and subrs as well. The value
of movd is to.
Note: fntyp, subrp, ccodep, exprp, argtype, nargs, and arglist all can
be given either the name of a function, or a definition.
fntyp[fn] Value is NIL if fn is not a function definition
or the name of a defined function. Otherwise
fntyp returns one of the following as defined in
the section on function types:
EXPR CEXPR SUBR
FEXPR CFEXPR FSUBR
EXPR* CEXPR* SUBR*
FEXPR* CFEXPR* FSUBR*
The prefix F indicates unevaluated arguments,
the prefix C indicates compiled code, and the
suffix * indicates an indefinite number of
arguments.
fntyp returns FUNARG if fn is a funarg
expression. See Section 11.
subrp[fn] is true if and only if fntyp[fn] is either SUBR,
FSUBR, SUBR*, or FSUBR*, i.e., the third column
of fntyp's.
8.3
ccodep[fn] is true if and only if fntyp[fn] is either
CEXPR, CFEXPR, CEXPR*, or CFEXPR*, i.e., second
column of fntyp's.
exprp[fn] is true if fntyp[fn] is either EXPR, FEXPR,
EXPR*, or FEXPR*, i.e., first column of fntyp's.
However, exprp[fn] is also true if fn is (has) a
list definition that is not a SUBR, but does not
begin with either LAMBDA or NLAMBDA. In other
words, exprp is not quite as selective as fntyp.
argtype[fn] fn is the name of a function or its definition.
The value of argtype is the argtype of fn, i.e.,
0, 1, 2, or 3, or NIL if fn is not a function.
The interpretation of the argtype is:
0 eval/spread function (EXPR,CEXPR,SUBR)
1 no-eval/spread functions (FEXPR,CFEXPR,FSUBR)
2 eval/nospread functions (EXPR*,CEXPR*,SUBR*)
3 no-eval/nospread functions
(FEXPR*,CFEXPR*,FSUBR*)
i.e., argtype corresponds to the rows of fntyps.
nargs[fn] value is the number of arguments of fn, or NIL
4
if fn is not a function. nargs uses exprp,
not fntyp, so that nargs[(A (B C) D)]=2. If fn
is a nospread function, the value of nargs is 1.
arglist[fn] value is the "argument list" for fn. Note that
the "argument list" is an atom for nospread
functions. Since NIL is a possible value for
arglist, an error is generated,
5
ARGS NOT AVAILABLE, if fn is not a function.
If fn is a SUBR or FSUBR in INTERLISP-10, the value of arglist is (U),
(U V), (U V W), etc. depending on the number of arguments, if a SUBR* or
FSUBR*, the value is U. This is merely a "feature" of arglist, subrs do
not actually store the names of their arguments(s) on the stack.
------------------------------------------------------------------------
4
i.e., if exprp, ccodep, and subrp are all NIL.
5
If fn is a compiled function, the argument list is constructed,
i.e., each call to arglist requires making a new list. For
interpreted functions, the argument list is simply cadr of getd.
8.4
smartarglist[fn;explainflg;tail]
If explainflg=T and fn is a nospread function,
e.g., list, selectq, etc., smartarglist uses
helpsys to interrogate the INTERLISP manual to
obtain more descriptive argument names, e.g.,
smartarglist[SELECTQ;T]=(X Y1 Y2 ... YN Z). If
fn is a nospread function, and explainflg=NIL,
then smartarglist returns arglist[fn].
If fn is a spread SUBR, regardless of the value
of explainflg, smartarglist also consults the
manual, e.g.,
smartarglist[READ]=(FILE RDTBL FLG),
smartarglist[STKPOS]=(FN N POS).
For all other cases, and when helpsys is
undefined or unsuccessful in finding the
arguments, smartarglist simply returns
arglist[fn].
smartarglist first calls fncheck (Section 17) on
fn. fncheck will attempt spelling correction if
6
fn is not the name of a function. If
unsuccessful, an error will be generated, fn NOT
A FUNCTION.
smartarglist is used by break (Section 15) and advise (Section 19) with
explainflg=NIL for constructing equivalent EXPR definitions, and by the
?= lispxmacro (Section 22), with explainflg=T. In order to avoid
repeated calls to helpsys, and also to provide the user with an
override, smartarglist stores the arguments returned from helpsys on the
property list of fn under the property ARGNAMES and checks for this
7
property before calling helpsys.
define[x] The argument of define is a list. Each element
of the list is itself a list either of the form
(name definition) or (name arguments ...). In
the second case, following "arguments" is the
body of the definition. As an example, consider
the following two equivalent expressions for
defining the function null.
1) (NULL (LAMBDA (X) (EQ X NIL)))
2) (NULL (X) (EQ X NIL))
------------------------------------------------------------------------
6
tail is used for the call to fixspell.
7
For spread functions, the argument list itself is stored. For
nospread, the form is (NIL arglist1 . arglist2) where arglist1 is
the value of smartarglist when explainflg=T, and arglist2 the value
when explainflg=NIL, e.g., getp[SELECTQ;ARGNAMES]=(NIL (X Y1 Y2 ...
YN Z) . SELCQ).
8.5
define will generate an error, INCORRECT DEFINING FORM, on encountering
an atom where a defining list is expected. If dfnflg=NIL, an attempt to
redefine a function fn will cause define to print the message (fn
REDEFINED) and to save the old definition of fn using savedef before
redefining it. If dfnflg=T, the function is simply redefined. If
dfnflg=PROP or ALLPROP, the new definition is stored on the property
list under the property EXPR. (ALLPROP affects the operation of rpaqq
and rpaq, Section 5). dfnflg is initially NIL.
dfnflg is reset by load to enable various ways of handling the defining
of functions and setting of variables when loading a file. For most
applications, the user will not reset dfnflg directly himself.
Note: define will operate correctly if the function is already defined
and broken, advised, or broken-in.
defineq[x1;xi;...;xn] nlambda nospread version of define, i.e., takes
an indefinite number of arguments which are not
evaluated. Each xi must be a list, of the form
described in define. defineq calls define, so
dfnflg affects its operation the same as define.
savedef[fn] Saves the definition of fn on its property list
under property EXPR, CODE, or SUBR depending on
its fntyp. Value is the property name used. If
getd[fn] is non-NIL, but fntyp[fn] is NIL, saves
on property name LIST. This situation can arise
when a function is redefined which was
originally defined with LAMBDA misspelled or
omitted.
If fn is a list, savedef operates on each
function in the list, and its value is a list of
the individual values.
unsavedef[fn;prop] Restores the definition of fn from its property
list under property prop (see savedef above).
Value is prop. If nothing saved under prop, and
fn is defined, returns (prop NOT FOUND),
otherwise generates an error, NOT A FUNCTION.
If prop is not given, i.e., NIL, unsavedef looks
under EXPR, CODE, and SUBR, in that order. The
value of unsavedef is the property name, or if
nothing is found and fn is a function, the value
is (NOTHING FOUND); otherwise generates an
error, NOT A FUNCTION.
If dfnflg=NIL, the current definition of fn, if
any, is saved using savedef. Thus one can use
unsavedef to switch back and forth between two
definitions of the same function, keeping one on
its property list and the other in the function
definition cell.
8.6
If fn is a list, unsavedef operates on each
function of the list, and its value is a list of
the individual values.
8
eval[x] eval evaluates the expression x and returns this
value i.e., eval provides a way of calling the
interpreter. Note that eval is itself a lambda
type function, so its argument is first
evaluated, e.g.,
_SET(FOO (ADD1 3))
(ADD1 3)
_(EVAL FOO)
4
_EVAL(FOO) or (EVAL (QUOTE FOO))
(ADD1 3)
e[x] nlambda nospread version of eval. Thus it
eliminates the extra pair of parentheses for the
list of arguments for eval. i.e., e x is
equivalent to eval[x]. Note however that in
INTERLISP, the user can type just x to get x
evaluated. (See Section 3.)
apply[fn;args] apply applies the function fn to the arguments
args. The individual elements of args are not
evaluated by apply, fn is simply called with
9
args as its argument list. Thus for the
purposes of apply, nlambda's and lambda's are
treated the same. However like eval, apply is a
lambda function so its arguments are evaluated
before it is called e.g.,
------------------------------------------------------------------------
8
In INTERLISP-10, eval is a subr so that the "name" x does not
actually appear on the stack.
9
Note that fn may still explicitly evaluate one or more of its
arguments itself, as in the case of setq. Thus,
(APPLY (QUOTE SETQ) (QUOTE (FOO (ADD1 3)))) will set FOO to 4,
whereas (APPLY (QUOTE SET) (QUOTE (FOO (ADD1 3)))) will set FOO to
the expression (ADD1 3).
8.7
_SET(FOO1 3)
3
_SET(FOO2 4)
4
_(APPLY (QUOTE IPLUS) (LIST FOO1 FOO2]
7
Here, fool and foo2 were evaluated when the
second argument to apply was evaluated. Compare
with:
_SET(FOO1 (ADD1 2))
(ADD1 2)
_SET(FOO2 (SUB1 5))
(SUB1 5)
_(APPLY (QUOTE IPLUS) (LIST FOO1 FOO2]
NON-NUMERIC ARG
(ADD1 2)
apply*[fn;arg1;...;argn]equivalent to apply[fn;list[arg1;...;argn]] For
example, if fn is the name of a functional
argument to be applied to x and y, one can write
(APPLY* FN X Y), which is equivalent to
(APPLY FN (LIST X Y)). Note that (FN X Y)
specifies a call to the function FN itself, and
will cause an error if FN is not defined. (See
Section 16.) FN will not be evaluated.
evala[x;a] Simulates a-list evaluation as in LISP 1.5. x is
a form, a is a list of dotted pairs of variable
name and value. a is "spread" on the stack, and
then x is evaluated, i.e., any variables
appearing free in x, that also appears as car of
an element of a will be given the value in the
cdr of that element.
rpt[rptn;rptf] Evaluates the expression rptf rptn times. At
any point, rptn is the number of evaluations yet
to take place. Returns the value of the last
evaluation. If rptn <= 0, rptf is not
evaluated, and the value of rpt is NIL.
Note: rpt is a lambda function, so both its arguments are evaluated
before rpt is called. For most applications, the user will probably
want to use rptq.
rptq[rptn;rptf] nlambda version of rpt: rptn is evaluated, rptf
is not, e.g., (RPTQ 10 (READ)) will perform ten
calls to read. rptq compiles open.
arg[var;m] Used to access the individual arguments of a
8.8
lambda nospread function. arg is an nlambda
function used like set. var is the name of the
atomic argument list to a lambda-nospread
function, and is not evaluated; m is the number
of the desired argument, and is evaluated. For
example, consider the following definition of
iplus in terms of plus.
[LAMBDA X
(PROG ((M 0)
(N 0))
LP (COND
((EQ N X)
(RETURN M)))
(SETQ N (ADD1 N))
[SETQ M (PLUS M (ARG X N)))
(GO LP]
The value of arg is undefined for m less than or
10
equal to 0 or greater than the value of var.
Lower numbered arguments appear earlier in the
form, e.g., for (IPLUS A B C),
arg[X;1]=the value of A,
arg[X;2]=the value of B, and
arg[X;3]=the value of C.
Note that the lambda variable should never be
reset. However, individual arguments can be
reset using setarg described below.
setarg[var;m;x] sets to x the mth argument for the lambda
nospread function whose argument list is var.
var is considered quoted, m and x are evaluated;
e.g., in the previous example,
(SETARG X (ADD1 N)(MINUS M)) would be an example
of the correct form for setarg.
------------------------------------------------------------------------
10
For lambda nospread functions, the lambda variable is bound to the
number of arguments actually given to the function. See Section 4.
8.9