* New version of IRM New version of the IRM, updated to Medley. * moved to docs/medley-irm as discussed
1177 lines
89 KiB
Plaintext
1177 lines
89 KiB
Plaintext
INTERLISP-D REFERENCE MANUAL
|
||
FUNCTION DEFINITION, MANIPULATION AND EVALUATION
|
||
"10"FUNCTION DEFINITION, MANIPULATION AND EVALUATION
|
||
3
|
||
|
||
|
||
Medley is designed to help you define and debug functions. Developing an applications program with Medley involves defining a number of functions in terms of the system primitives and other user-defined functions. Once defined, your functions may be used exactly like Interlisp primitive functions, so the programming process can be viewed as extending the Interlisp language to include the required functionality.
|
||
A function's definition specifies if the function has a fixed or variable number of arguments, whether these arguments are evaluated or not, the function argument names, and a series of forms which define the behavior of the function. For example:
|
||
(LAMBDA (X Y) (PRINT X) (PRINT Y))
|
||
This function has two evaluated arguments, X and Y, and it will execute (PRINT X) and (PRINT Y) when evaluated. Other types of function definitions are described below.
|
||
A function is defined by putting an expr definition in the function definition cell of a symbol. There are a number of functions for accessing and setting function definition cells, but one usually defines a function with DEFINEQ (see the Defining Functions section below). For example:
|
||
¬ (DEFINEQ (FOO (LAMBDA (X Y) (PRINT X) (PRINT Y))))(FOO)
|
||
The expression above will define the function FOO to have the expr definition (LAMBDA (X Y) (PRINT X) (PRINT Y)). After being defined, this function may be evaluated just like any system function:
|
||
¬ (FOO 3 (IPLUS 3 4))
|
||
3
|
||
7
|
||
7
|
||
Not all function definition cells contain expr definitions. The compiler (see the first page of Chapter 18) translates expr definitions into compiled code objects, which execute much faster. Interlisp provides a number of ªfunction type functionsº which determine how a given function is defined, the number and names of function arguments, etc. See the Function Type Functions section below.
|
||
Usually, functions are evaluated automatically when they appear within another function or when typed into Interlisp. However, sometimes it is useful to envoke the Interlisp interpreter explicitly to apply a given ªfunctional argumentº to some data. There are a number of functions which will apply a given function repeatedly. For example, MAPCAR will apply a function (or an expr definition) to all of the elements of a list, and return the values returned by the function:
|
||
¬ (MAPCAR '(1 2 3 4 5) '(LAMBDA (X) (ITIMES X X))
|
||
(1 4 9 16 25)
|
||
When using functional arguments, there are a number of problems which can arise, related to accessing free variables from within a function argument. Many times these problems can be solved using the function FUNCTION to create a FUNARG object.
|
||
The macro facility provides another way of specifying the behavior of a function (see the Macros section below). Macros are very useful when developing code which should run very quickly, which should be compiled differently than when it is interpreted, or which should run differently in different implementations of Interlisp.
|
||
Function Types
|
||
1
|
||
|
||
Interlisp functions are defined using list expressions called ªexpr definitions.º An expr definition is a list of the form (LAMBDA-WORD ARG-LIST FORM1 ... FORMN). LAMBDA-WORD determines whether the arguments to this function will be evaluated or not. ARG-LIST determines the number and names of arguments. FORM1 ... FORMN are a series of forms to be evaluated after the arguments are bound to the local variables in ARG-LIST.
|
||
If LAMBDA-WORD is the symbol LAMBDA, then the arguments to the function are evaluated. If LAMBDA-WORD is the symbol NLAMBDA, then the arguments to the function are not evaluated. Functions which evaluate or don't evaluate their arguments are therefore known as ªlambdaº or ªnlambdaº functions, respectively.
|
||
If ARG-LIST is NIL or a list of symbols, this indicates a function with a fixed number of arguments. Each symbol is the name of an argument for the function defined by this expression. The process of binding these symbols to the individual arguments is called ªspreadingº the arguments, and the function is called a ªspreadº function. If the argument list is any symbol other than NIL, this indicates a function with a variable number of arguments, known as a ªnospreadº function.
|
||
If ARG-LIST is anything other than a symbol or a list of symbols, such as (LAMBDA "FOO" ...), attempting to use this expr definition will generate an Arg not symbol error. In addition, if NIL or T is used as an argument name, the error Attempt to bind NIL or T is generated.
|
||
These two parameters (lambda/nlambda and spread/nospread) may be specified independently, so there are four nain function types, known as lambda-spread, nlanbda-spread, lanbda-nospread, and nlambda-nospread functions. Each one has a different form and is used for a different purpose. These four function types are described more fully below.
|
||
For lambda-spread, lanbda-nospread, or nlambda-spread functions, there is an upper limit to the number of arguments that a function can have, based on the number of arguments that can be stored on the stack on any one function call. Currently, the limit is 80 arguments. If a function is called with more than that many arguments, the error Too many arguments occurs. However, nlambda-nospread functions can be called with an arbitrary number of arguments, since the arguments are not individually saved on the stack.
|
||
Lambda-Spread Functions(LAMBDA-SPREAD% FUNCTIONS NIL Lambda-Spread% Functions NIL ("10") 2)
|
||
Lambda-spread functions take a fixed number of evaluated arguments. This is the most common function type. A lambda-spread expr definition has the form:
|
||
(LAMBDA (ARG1 ... ARGM) FORM1 ... FORMN)
|
||
The argument list (ARG1 ... ARGM) is a list of symbols that gives the number and names of the formal arguments to the function. If the argument list is ( ) or NIL, this indicates that the function takes no arguments. When a lambda-spread function is applied to some arguments, the arguments are evaluated, and bound to the local variables ARG1 ... ARGM. Then, FORM1 ... FORMN are evaluated in order, and the value of the function is the value of FORMN.
|
||
¬ (DEFINEQ (FOO (LAMBDA (X Y) (LIST X Y))))
|
||
(FOO)
|
||
¬ (FOO 99 (PLUS 3 4))
|
||
(99 7)
|
||
In the above example, the function FOO defined by (LAMBDA (X Y) (LIST X Y)) is applied to the arguments 99 and (PLUS 3 4). These arguments are evaluated (giving 99 and 7), the local variable X is bound to 99 and Y to 7, (LIST X Y) is evaluated, returning (99 7), and this is returned as the value of the function.
|
||
A standard feature of the Interlisp system is that no error occurs if a spread function is called with too many or too few arguments. If a function is called with too many argumnents, the extra arguments are evaluated but ignored. If a function is called with too few arguments, the unsupplied ones will be delivered as NIL. In fact, a spread function cannot distinguish between being given NIL as an argument, and not being given that argument, e.g., (FOO) and (FOO NIL) are exactly the same for spread functions. If it is necessary to distinguish between these two cases, use an nlambda function and explicitly evaluate the arguments with the EVAL function.
|
||
Nlambda-Spread Functions(NLAMBDA-SPREAD% FUNCTIONS NIL Nlambda-Spread% Functions NIL ("10") 3)
|
||
Nlambda-spread functions take a fixed number of unevaluated arguments. An nlambda-spread expr definition has the form:
|
||
(NLAMBDA (ARG1 ... ARGM) FORM1 ... FORMN)
|
||
Nlambda-spread functions are evaluated similarly to lanbda-spread functions, except that the arguments are not evaluated before being bound to the variables ARG1 ... ARGM.
|
||
¬ (DEFINEQ (FOO (NLAMBDA (X Y) (LIST X Y))))
|
||
(FOO)
|
||
¬ (FOO 99 (PLUS 3 4))
|
||
(99 (PLUS 3 4))
|
||
In the above example, the function FOO defined by (NLAMBDA (X Y) (LIST X Y)) is applied to the arguments 99 and (PLUS 3 4). These arguments are unevaluated to X and Y. (LIST X Y) is evaluated, returning (99 (PLUS 3 4)), and this is returned as the value of the function.
|
||
Functions can be defined so that all of their arguments are evaluated (lambda functions) or none are evaluated (nlambda functions). If it is desirable to write a function which only evaluates some of its arguments (e.g., SETQ), the functions should be defined as an nlambda, with some arguments explicitly evaluated using the function EVAL. If this is done, the user should put the symbol EVAL on the property list of the function under the property INFO. This informs various system packages, such as DWIM, CLISP, and Masterscope, that this function in fact does evaluate its arguments, even though it is an nlambda.
|
||
Warning: A frequent problem that occurs when evaluating arguments to nlambda functions with EVAL is that the form being evaluated may reference variables that are not accessible within the nlambda function. This is usually not a problem when interpreting code, but when the code is compiled, the values of ªlocalº variables may not be accessible on the stack (see Chapter 18). The system nlambda functions that evaluate their arguments (such as SETQ) are expanded in-line by the compiler, so this is not a problem. Using the macro facility is recommended in cases where it is necessary to evaluate some arguments to an nlambda function.
|
||
Lambda-Nospread Functions(LAMBDA-NOSPREAD% FUNCTIONS NIL Lambda-Nospread% Functions NIL ("10") 3)
|
||
Lambda-nospread functions take a variable number of evaluated arguments. A lambda-nospread expr definition has the form:
|
||
(LAMBDA VAR FORM1 ... FORMN)
|
||
VAR may be any symbol, except NIL and T. When a lambda-nospread function is applied to some arguments, each of these arguments is evaluated and the values stored on the stack. VAR is then bound to the number of arguments which have been evaluated. For example, if FOO is defined by (LAMBDA X ...), when (FOO A B C) is evaluated, A, B, and C are evaluated and X is bound to 3. VAR should never be reset
|
||
The following functions are used for accessing the arguments of lambda-nospread functions.
|
||
(ARG(ARG (Function) NIL NIL ("10") 4) VAR M) [NLambda Function]
|
||
Returns the Mth argument for the lambda-nospread function whose argument list is VAR. 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. The value of ARG is undefined for M less than or equal to 0 or greater than the value of VAR.
|
||
(SETARG(SETARG (Function) NIL NIL ("10") 4) VAR M X) [NLambda Function]
|
||
Sets the Mth argument for the lambda-nospread function whose argument list is VAR to X. VAR is not evaluated; M and X are evaluated. M should be between 1 and the value of VAR.
|
||
In the example below, the function FOO is defined to collect and return a list of all of the evaluated arguments it is given (the value of the for statement).
|
||
¬ (DEFINEQ (FOO
|
||
(LAMBDA X (for ARGNUM from 1 to X collect (ARG X ARGNUM)]
|
||
(FOO)
|
||
¬ (FOO 99 (PLUS 3 4))
|
||
(99 7)
|
||
¬ (FOO 99 (PLUS 3 4)(TIMES 3 4)))
|
||
(99 7 12)
|
||
NLambda-Nospread Functions(NLAMBDA-NOSPREAD% FUNCTIONS NIL NLambda-Nospread% Functions NIL ("10") 4)
|
||
Nlambda-nospread functions take a variable number of unevaluated arguments. An nlambda-nospread expr definition has the form:
|
||
(NLAMBDA VAR FORM1 ... FORMN)
|
||
VAR may be any symbol, except NIL and T. Though similar in form to lambda-nospread expr definitions, an nlambda-nospread is evaluated quite differently. When an nlambda-nospread function is applied to some arguments, VAR is simply bound to a list of the unevaluated arguments. The user may pick apart this list, and evaluate different arguments.
|
||
In the example below, FOO is defined to return the reverse of the list of arguments it is given (unevaluated):
|
||
¬ (DEFINEQ (FOO (NLAMBDA X (REVERSE X))))
|
||
(FOO)
|
||
¬ (FOO 99 (PLUS 3 4))
|
||
((PLUS 3 4) 99)
|
||
¬ (FOO 99 (PLUS 3 4)(TIMES 3 4))
|
||
(TIMES 3 4)(PLUS 3 4) 99)
|
||
The warning about evaluating arguments to nlambda functions also applies to nlambda-nospread function.
|
||
Compiled Functions(COMPILED% FUNCTIONS NIL Compiled% Functions NIL ("10") 5)
|
||
Functions defined by expr definitions can be compiled by the Interlisp compiler (see Chapter 18). The compiler produces compiled code objects (of data type CCODEP) which execute more quickly than the corresponding expr definition code. Functions defined by compiled code objects may have the same four types as expr definitions (lambda/nlambda, spread/nospread). Functions created by the compiler are referred to as compiled functions.
|
||
Function Type Functions
|
||
There are a variety of functions used for examining the type, argument list, etc. of functions. These functions may be given either a symbol (in which case they obtain the function definition from the definition cell), or a function definition itself.
|
||
(FNTYP(FNTYP (Function) NIL NIL ("10") 5) FN) [Function]
|
||
Returns NIL if FN is not a function definition or the name of a defined function. Otherwise, FNTYP returns one of the following symbols, depending on the type of function definition.
|
||
EXPR Lambda-spread expr definition
|
||
CEXPR Lambda-spread compiled definition
|
||
FEXPR Nlambda-spread expr definition
|
||
CFEXPR Nlambda-spread compiled definition
|
||
EXPR* Lambda-nospread expr definition
|
||
CEXPR* Lambda-nospread compiled definition
|
||
FEXPR* Nlambda-nospread expr definition
|
||
CFEXPR* Nlambda-nospread compiled definition
|
||
FUNARG FNTYP returns the symbol FUNARG if FN is a FUNARG expression.
|
||
EXP, FEXPR, EXPR*, and FEXPR* indicate that FN is defined by an expr definition. CEXPR, CFEXPR, CEXPR*, and CFEXPR* indicate that FN is defined by a compiled definition, as indicated by the prefix C. The suffix * indicates that FN has an indefinite number of arguments, i.e., is a nospread function. The prefix F indicates unevaluated arguments. Thus, for example, a CFEXPR* is a compiled nospread nlambda function.
|
||
(EXPRP(EXPRP (Function) NIL NIL ("10") 5) FN) [Function]
|
||
Returns T if (FNTYP FN) is EXPR, FEXPR, EXPR*, or FEXPR*; NIL otherwise. However, (EXPRP FN) is also true if FN is (has) a list definition, even if it does not begin with LAMBDA or NLAMBDA. In other words, EXPRP is not quite as selective as FNTYP.
|
||
(CCODEP(CCODEP (Function) NIL NIL ("10") 5) FN) [Function]
|
||
Returns T if (FNTYP FN) is either CEXPR, CFEXPR, CEXPR*, or CFEXPR*; NIL otherwise.
|
||
(ARGTYPE(ARGTYPE (Function) NIL NIL ("10") 6) FN) [Function]
|
||
FN is the name of a function or its definition. ARGTYPE returns 0, 1, 2, or 3, or NIL if FN is not a function. ARGTYPE corresponds to the rows of FNTYPs. The interpretation of this value is as follows:
|
||
0 Lambda-spread function (EXPR, CEXPR)
|
||
1 Nlambda-spread function (FEXPR, CFEXPR)
|
||
2 Lambda-nospread function (EXPR*, CEXPR*)
|
||
3 Nlambda-nospread function (FEXPR*, CFEXPR*)
|
||
(NARGS(NARGS (Function) NIL NIL ("10") 6) FN) [Function]
|
||
Returns the number of arguments of FN, or NIL if FN is not a function. If FN is a nospread function, the value of NARGS is 1.
|
||
(ARGLIST(ARGLIST (Function) NIL NIL ("10") 6) FN) [Function]
|
||
Returns the ªargument listº for FN. Note that the ªargument listº is a symbol for nospread functions. Since NIL is a possible value for ARGLIST, the error Args not available is generated if FN is not a function.
|
||
If FN is a compiled function, the argument list is constructed, i.e., each call to ARGLIST requires making a new list. For functions defined by expr definitions, lists beginning with LAMBDA or NLAMBDA, the argument list is simply CADR of GETD. If FN has an expr definition, and CAR of the definition is not LAMBDA or NLAMBDA, ARGLIST will check to see if CAR of the definition is a member of LAMBDASPLST (see Chapter 20). If it is, ARGLIST presumes this is a function object the user is defining via DWIMUSERFORMS, and simply returns CADR of the definition as its argument list. Otherwise ARGLIST generates an error as described above.
|
||
(SMARTARGLIST(SMARTARGLIST (Function) NIL NIL ("10") 6) FN EXPLAINFLG TAIL) [Function]
|
||
A ªsmartº version of ARGLIST that tries various strategies to get the arglist of FN.
|
||
First SMARTARGLIST checks the property list of FN under the property ARGNAMES. For spread functions, the argument list itself is stored. For nospread functions, the form is (NIL ARGLIST1 . ARGLIST2), where ARGLIST1 is the value SMARTARGLIST should return when EXPLAINFLG = T, and ARGLIST2 the value when EXPLAINFLG = NIL. For example, (GETPROP 'DEFINEQ 'ARGNAMES) = (NIL (X1 Xl ... XN) . X). This allows the user to specify special argument lists.
|
||
Second, if FN is not defined as a function, SMARTARGLIST attempts spelling correction on FN by calling FNCHECK (see Chapter 20), passing TAIL to be used for the call to FIXSPELL. If unsuccessful, the FN Not a function error will be generated.
|
||
Third, if FN is known to the file package (see Chapter 17) but not loaded in, SMARTARGLIST will obtain the arglist information from the file.
|
||
Otherwise, SMARTARGLIST simply returns (ARGLIST FN).
|
||
SMARTARGLIST is used by BREAK (see Chapter 15) and ADVISE with EXPLAINFLG = NIL for constructing equivalent expr definitions, and by the TTYIN in-line command ?= (see Chapter 26), with EXPLAINFLG = T.
|
||
Defining Functions
|
||
1
|
||
|
||
Function definitions are stored in a ªfunction definition cellº associated with each symbol. This cell is directly accessible via the two functions PUTD and GETD (see below), but it is usually easier to define functions with DEFINEQ:
|
||
(DEFINEQ(DEFINEQ (Function) NIL NIL ("10") 7) X1 X2 ... XN) [NLambda NoSpread Function]
|
||
DEFINEQ is the function normally used for defining functions. It takes an indefinite number of arguments which are not evaluated. Each Xi must be a list defining one function, of the form (NAME DEFINITION). For example:
|
||
(DEFINEQ (DOUBLE (LAMBDA (X) (IPLUS X X))))
|
||
The above expression will define the function DOUBLE with the expr definition (LAMBDA (X) (IPLUS X X)). Xi may also have the form (NAME ARGS . DEF-BODY), in which case an appropriate lambda expr definition will be constructed. Therefore, the above expression is exactly the same as:
|
||
(DEFINEQ (DOUBLE (X) (IPLUS X X)))
|
||
Note that this alternate form can only be used for lambda functions. The first form must be used to define an nlambda function.
|
||
DEFINEQ returns a list of the names of the functions defined.ÿÿ |