Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap1_198111 - decus/20-0004/08lisp.doc
There are no other files named 08lisp.doc 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