{Begin SubSec Function Types} {Title Function Types} {Text {index *BEGIN* function types} {Tag FnTypes} Interlisp functions are defined using list expressions called {lisp EXPR}s. An {lisp EXPR} is a list of the form {lisp ({arg LAMBDA-WORD} {arg ARG-LIST} {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}})}. {arg LAMBDA-WORD} determines whether the arguments to this function will be evaluated or not, {arg ARG-LIST}{index argument list} determines the number and names of arguments, and {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}} are a series of forms to be evaluated after the arguments are bound to the local variables in {arg ARG-LIST}. If {arg LAMBDA-WORD} is the litatom {atom LAMBDA},{index *PRIMARY* LAMBDA Litatom} then the arguments to the function are evaluated. If {arg LAMBDA-WORD} is the litatom {atom NLAMBDA},{index *PRIMARY* NLAMBDA Litatom} then the arguments to the function are not evaluated. Functions which evaluate or don't evaluate their arguments are therefore known as "lambda"{index *PRIMARY* lambda functions} or "nlambda"{index *PRIMARY* nlambda functions} functions, respectively. If {arg ARG-LIST} is {lisp NIL} or a list of litatoms, this indicates a function with a fixed number of arguments.{index fixed number of arguments} Each litatom is the name of an argument for the function defined by this expression. The process of binding these litatoms to the individual arguments is called "spreading"{index spreading arguments} the arguments, and the function is called a "spread" function.{index *PRIMARY* spread functions} If the argument list is any litatom other than {lisp NIL}, this indicates a function with a variable number of arguments,{index variable number of arguments} known as a "nospread" function.{index *PRIMARY* nospread functions} If {arg ARG-LIST} is anything other than a litatom or a list of litatoms, such as {lisp (LAMBDA "FOO" {ellipsis})}, attempting to use this {lisp EXPR} will generate an {lisp ARG NOT LITATOM} error.{index ARG NOT LITATOM Error} In addition, if {lisp NIL} or {lisp T} is used as an argument name, the error {lisp ATTEMPT TO BIND NIL OR T} is generated.{index ATTEMPT TO BIND NIL OR T Error} These two parameters (lambda/nlambda and spread/nospread) may be specified independently, so there are four main function types, known as lambda-spread, nlambda-spread, lambda-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. Note: The Lambdatran lispusers package provides facilities for creating new function types which evaluate/spread their arguments in different ways than those provided by Interlisp. See {PageRef Tag LAMBDATRAN}. {Begin SubSec Lambda-Spread Functions} {Title Lambda-Spread Functions} {Text {index *PRIMARY* lambda-spread functions} Lambda-spread functions take a fixed number of evaluated arguments. This is the most common function type. A lambda-spread {lisp EXPR} has the form: {lispcode (LAMBDA ({arg ARG{sub 1}} {ellipsis} {arg ARG{sub M}}) {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}})} The argument list {lisp ({arg ARG{sub 1}} {ellipsis} {arg ARG{sub M}})} is a list of litatoms that gives the number and names of the formal arguments to the function. If the argument list is {lisp ()} or {atom 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 {arg ARG{sub 1}} {ellipsis} {arg ARG{sub M}}. Then, {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}} are evaluated in order, and the value of the function is the value of {arg FORM{sub N}}. {lispcode _ (DEFINEQ (FOO (LAMBDA (X Y) (PRINT X) (PRINT Y))) ) (FOO) _ (FOO 99 (PLUS 3 4)) 99 7 7 _} In the above example, the function {lisp FOO} defined by {lisp (LAMBDA (X Y) (PRINT X) (PRINT Y))} is applied to the arguments {lisp 99} and {lisp (PLUS 3 4)}, these arguments are evaluated (giving 99 and 7), the local variable {lisp X} is bound to 99 and {lisp Y} to 7, {lisp (PRINT X)} is evaluated, printing 99, {lisp (PRINT Y)} is evaluated, printing 7, and 7 (the {it value} of {lisp (PRINT Y)}) 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.{index incorrect number of arguments} If a function is called with too many arguments,{index too many arguments} the extra arguments are evaluated but ignored. If a function is called with too few arguments,{index too few arguments} the unsupplied ones will be delivered as {lisp NIL}. In fact, a spread function cannot distinguish between being given {lisp NIL} as an argument, and not being given that argument, e.g., {lisp (FOO)} and {lisp (FOO NIL)} are {it 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 {fn EVAL} function ({PageRef Fn EVAL}). }{End SubSec Lambda-Spread Functions} {Begin SubSec Nlambda-Spread Functions} {Title Nlambda-Spread Functions} {Text {index *PRIMARY* nlambda-spread functions} Nlambda-spread functions take a fixed number of unevaluated arguments. An nlambda-spread {lisp EXPR} has the form: {lispcode (NLAMBDA ({arg ARG{sub 1}} {ellipsis} {arg ARG{sub M}}) {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}})} Nlambda-spread functions are evaluated similarly to lambda-spread functions, except that the arguments are not evaluated before being bound to the variables {arg ARG{sub 1}} {ellipsis} {arg ARG{sub M}}. {lispcode _ (DEFINEQ (FOO (NLAMBDA (X Y) (PRINT X) (PRINT Y))) ) (FOO) _ (FOO 99 (PLUS 3 4)) 99 (PLUS 3 4) (PLUS 3 4) _} In the above example, the function {lisp FOO} defined by {lisp (NLAMBDA (X Y) (PRINT X) (PRINT Y))} is applied to the arguments {lisp 99} and {lisp (PLUS 3 4)}, these arguments are bound unevaluated to {lisp X} and {lisp Y}, {lisp (PRINT X)} is evaluated, printing {lisp 99}, {lisp (PRINT Y)} is evaluated, printing {lisp (PLUS 3 4)}, and the list {lisp (PLUS 3 4)} is returned as the value of the function. Note: 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 {it some} of its arguments (e.g. {fn SETQ}), the function should be defined as an nlambda, with some arguments explicitly evaluated using the function {fn EVAL} ({PageRef Fn EVAL}). If this is done, the user should put the litatom {lisp EVAL} on the property list of the function under the property {prop INFO}.{index INFO Prop} This informs various system packages such as DWIM, CLISP, and Masterscope that this function in fact {it does} evaluate its arguments, even though it is an nlambda. }{End SubSec Nlambda-Spread Functions} {Begin SubSec Lambda-Nospread Functions} {Title Lambda-Nospread Functions} {Text {index *PRIMARY* lambda-nospread functions} Lambda-nospread functions take a variable number of evaluated arguments. A lambda-nospread {lisp EXPR} has the form: {lispcode (LAMBDA {arg VAR} {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}})} {arg VAR} may be any litatom, except {atom NIL} and {atom T}. When a lambda-nospread function is applied to some arguments, each of these arguments is evaluated and the values stored on the pushdown list.{index pushdown list} {arg VAR} is then bound to the {it number} of arguments which have been evaluated. For example, if {lisp FOO} is defined by {lisp (LAMBDA X {ellipsis})}, when {lisp (FOO A B C)} is evaluated, {lisp A}, {lisp B}, and {lisp C} are evaluated and {lisp X} is bound to 3. {arg VAR} should {it never} be reset. The following functions are used for accessing the arguments of lambda-nospread functions: {FnDef {FnName ARG} {FnArgs VAR M} {Type NLAMBDA} {Text Returns the {arg M}th argument for the lambda-nospread function whose argument list is {arg VAR}. {arg VAR} is the {it name} of the atomic argument list to a lambda-nospread function, and is not evaluated; {arg M} is the number of the desired argument, and is evaluated. The value of {index ARG FN}{fn ARG} is undefined for {arg M} less than or equal to 0 or greater than the {it value} of {arg VAR}. {note {fn ARG} compiles open if {arg VAR} is bound locally in the function in which the call to {fn ARG} appears. Otherwise, {fn ARG} compiles closed and evaluates its first argument on each call. Note that this means that the value of {arg VAR} must be a {lisp SPECVAR}. <<>>} }} {FnDef {FnName SETARG} {FnArgs VAR M X} {Type NLAMBDA} {Text Sets the {arg M}th argument for the lambda-nospread function whose argument list is {arg VAR} to {arg X}. {arg VAR} is not evaluated; {arg M} and {arg X} are evaluated. {arg M} should be between 1 and the value of {arg VAR}. }} In the example below, the function {lisp FOO} is defined to print all of the evaluated arguments it is given, and return {lisp NIL} (the value of the {lisp for} statement). {lispcode _ (DEFINEQ (FOO (LAMBDA X (for ARGNUM from 1 to X do (PRINT (ARG X ARGNUM))))) ) (FOO) _ (FOO 99 (PLUS 3 4)) 99 7 NIL _ (FOO 99 (PLUS 3 4) (TIMES 3 4)) 99 7 12 NIL _} }{End SubSec Lambda-Nospread Functions} {Begin SubSec Nlambda-Nospread Functions} {Title Nlambda-Nospread Functions} {Text {index *PRIMARY* nlambda-nospread functions} Nlambda-nospread functions take a variable number of unevaluated arguments. An nlambda-nospread {lisp EXPR} has the form: {lispcode (NLAMBDA {arg VAR} {arg FORM{sub 1}} {ellipsis} {arg FORM{sub N}})} {arg VAR} may be any litatom, except {atom NIL} and {atom T}. Though similar in form to lambda-nospread {lisp EXPR}s, an nlambda-nospread is evaluated quite differently. When an nlambda-nospread function is applied to some arguments, {arg 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, {lisp FOO} is defined to print (and then return) the reverse of list of arguments it is given (unevaluated): {lispcode _ (DEFINEQ (FOO (NLAMBDA X (REVERSE X)))) (FOO) _ (FOO 99 (PLUS 3 4)) ((PLUS 3 4) 99) ((PLUS 3 4) 99) _ (FOO 99 (PLUS 3 4) (TIMES 3 4)) ((TIMES 3 4) (PLUS 3 4) 99) ((TIMES 3 4) (PLUS 3 4) 99) _} }{End SubSec Nlambda-Nospread Functions} {Begin SubSec Compiled Functions} {Title Compiled Functions} {Text {index compiled functions} Functions defined by {lisp EXPR}s can be compiled by the Interlisp compiler ({PageRef Tag COMPILER}), which produces compiled code objects, which execute more quickly than the corresponding {lisp EXPR} code. Functions defined by compiled code objects may have the same four types as {lisp EXPR}s (lambda/nolambda, spread/nospread). Functions created by the compiler are referred to as compiled functions. }{End SubSec Compiled Functions} {Begin SubSec Function Type Functions} {Title Function Type Functions} {Text There are a variety of functions used for examining the type, argument list, etc. of functions. These functions may be given either a litatom, in which case they obtain the function definition from the litatom's definition cell, or a function definition itself. {FnDef {FnName FNTYP} {FnArgs FN} {Text Returns {lisp NIL} if {arg FN} is not a function definition or the name of a defined function. Otherwise {fn FNTYP} returns one of the following twelve litatoms: {Begin Table FNTYP returns} {COLUMN 30percent} {COLUMN} {COLUMN} {COLUMN} {First} {Next Expressions} {next Compiled} {next Built-In} {First Lambda-Spread} {Next {atom EXPR}} {next {atom CEXPR}} {next {atom SUBR}} {First Nlambda-Spread} {Next {atom FEXPR}} {next {atom CFEXPR}} {next {atom FSUBR}} {First Lambda-Nospread} {Next {atom EXPR*}} {next {atom CEXPR*}} {next {atom SUBR*}} {First Nlambda-Nospread} {Next {atom FEXPR*}} {next {atom CFEXPR*}} {next {atom FSUBR*}} {End Table FNTYP returns} {index *PRIMARY* EXPR Litatom}{index *PRIMARY* CEXPR Litatom}{index *PRIMARY* SUBR Litatom}{index *PRIMARY* FEXPR Litatom}{index *PRIMARY* CFEXPR Litatom}{index *PRIMARY* FSUBR Litatom}{index *PRIMARY* EXPR* Litatom}{index *PRIMARY* CEXPR* Litatom}{index *PRIMARY* SUBR* Litatom}{index *PRIMARY* FEXPR* Litatom}{index *PRIMARY* CFEXPR* Litatom}{index *PRIMARY* FSUBR* Litatom} The types in the first column are all defined by {lisp EXPR}s. The types in the second column are compiled versions of the types in the first column, as indicated by the prefix {lisp C}. In Interlisp-10, there are additional entries for hand-coded assembly language routines in the third column, called {lisp SUBR}s, (see "Interlisp-10 specifics"). Functions of types in the first two rows have a fixed number of arguments, i.e., are spread functions. Functions in the third and fourth rows have an indefinite number of arguments, as indicated by the suffix {lisp *}. The prefix {lisp F} indicates unevaluated arguments. Thus, for example, a {lisp CFEXPR*} is a compiled nospread-nlambda function. {fn FNTYP} returns the litatom {atom FUNARG}{index FUNARG Litatom} if {arg FN} is a {lisp FUNARG} expression. See {PageRef Fn FUNCTION}. }} {FnDef {FnName EXPRP} {FnArgs FN} {Text Returns {lisp T} if {lisp (FNTYP {arg FN})} is either {lisp EXPR}, {lisp FEXPR}, {lisp EXPR*}, or {lisp FEXPR*}, i.e., first column of {fn FNTYP}s; {lisp NIL} otherwise.{index EXPR Litatom}{index FEXPR Litatom}{index EXPR* Litatom}{index FEXPR* Litatom} However, {lisp (EXPRP {arg FN})} is also true if {arg FN} is (has) a list definition, even if it does not begin with {atom LAMBDA} or {atom NLAMBDA}. In other words, {fn EXPRP} is not quite as selective as {fn FNTYP}. }} {FnDef {FnName CCODEP} {FnArgs FN} {Text Returns {lisp T} if {index FNTYP FN}{lisp (FNTYP {arg FN})} is either {lisp CEXPR}, {lisp CFEXPR}, {lisp CEXPR*}, or {lisp CFEXPR*}, i.e., second column of {fn FNTYP}s; {lisp NIL} otherwise.{index CEXPR Litatom}{index CFEXPR Litatom}{index CEXPR* Litatom}{index CFEXPR* Litatom} }} {FnDef {FnName ARGTYPE} {FnArgs FN} {Text {arg FN} is the name of a function or its definition. {fn ARGTYPE} returns 0, 1, 2, or 3, or {lisp NIL} if {arg FN} is not a function. The interpretation of this value is: {Begin LabeledList interpretation of ARGTYPE} {INDENT 10percent} {Name 0} {text lambda-spread functions ({lisp EXPR}, {lisp CEXPR}){index EXPR Litatom}{index CEXPR Litatom} } {Name 1} {text nlambda-spread functions ({lisp FEXPR}, {lisp CFEXPR}) {index FEXPR Litatom}{index CFEXPR Litatom} } {Name 2} {text lambda-nospread functions ({lisp EXPR*}, {lisp CEXPR*}) {index EXPR* Litatom}{index CEXPR* Litatom} } {Name 3} {text nlambda-nospread functions ({lisp FEXPR*}, {lisp CFEXPR*}) {index FEXPR* Litatom}{index CFEXPR* Litatom} } {End LabeledList interpretation of ARGTYPE} i.e., {fn ARGTYPE} corresponds to the {it rows} of {fn FNTYP}'s. }} {FnDef {FnName NARGS} {FnArgs FN} {Text Returns the number of arguments of {arg FN}, or {lisp NIL} if {arg FN} is not a function. If {arg FN} is a nospread function, the value of {fn NARGS} is 1. {note why doesn't NARGS check LAMBDASPLST, to be consistant with ARGLIST??} {Begin Note} untrue! {fn NARGS} uses {fn EXPRP}, not {fn FNTYP}, so it accepts list definitions even if they don't begin with {atom LAMBDA} or {atom NLAMBDA}. For instance, {lisp (NARGS '(A (B C) D)) => 2}. {End Note} }} {FnDef {FnName ARGLIST} {FnArgs FN} {Text Returns the "argument list" for {arg FN}. Note that the "argument list" is a litatom for nospread functions. Since {lisp NIL} is a possible value for {fn ARGLIST}, an error is generated, {lisp ARGS NOT AVAILABLE},{index ARGS NOT AVAILABLE Error} if {arg FN} is not a function. If {arg FN} is a compiled function, the argument list is constructed, i.e., each call to {fn ARGLIST} requires making a new list. For {lisp EXPR}s, whose definitions are lists beginning with {atom LAMBDA} or {atom NLAMBDA}, the argument list is simply {fn CADR} of {fn GETD}. If {arg FN} has a list definition, and {fn CAR} of the definition is not {lisp LAMBDA} or {lisp NLAMBDA}, {fn ARGLIST} will check to see if {fn CAR} of the definition is a member of {index LAMBDASPLST Var}{var LAMBDASPLST} ({PageRef Var LAMBDASPLST}). If it is, {fn ARGLIST} presumes this is a function object the user is defining via {var DWIMUSERFORMS} ({PageRef Var DWIMUSERFORMS}), and simply returns {fn CADR} of the definition as its argument list. Otherwise {fn ARGLIST} generates an error as described above. }} {Begin Note} Date: 11 AUG 1981 2233-PDT From: MASINTER.PA Subject: ARGLIST of functions with (LOCALVARS . T) The way the system works now is "right" in that ARGLIST returns the names as given in the original function even though the names don't appear on the "stack" and aren't really bound, the idea is that ARGLIST is a little bit of documentation. {End Note} {FnDef {FnName SMARTARGLIST} {FnArgs FN EXPLAINFLG TAIL} {Text A "smart" version of {fn ARGLIST} that tries various strategies to get the arglist of {arg FN}. {fn SMARTARGLIST} is used by {fn BREAK} ({PageRef Fn BREAK}) and {fn ADVISE} ({PageRef Fn ADVISE}) with {arg EXPLAINFLG}={lisp NIL} for constructing equivalent {lisp EXPR} definitions, and by the programmer's assistant command {PAcom ?=} ({PageRef PAcom ?=}), with {arg EXPLAINFLG}={lisp T}. In order to provide the user with an override, {fn SMARTARGLIST} first checks the property list of {arg FN} under the property {lisp ARGNAMES}{index ARGNAMES Prop}. For spread functions, the argument list itself is stored. For nospread, the form is {lisp (NIL {arg ARGLIST{sub 1}} . {arg ARGLIST{sub 2}})} where {arg ARGLIST{sub 1}} is the value of {fn SMARTARGLIST} when {arg EXPLAINFLG}={lisp T}, and {arg ARGLIST{sub 2}} the value when {arg EXPLAINFLG}={lisp NIL}. For example, {lisp (GETPROP 'DEFINEQ 'ARGNAMES)} = {lisp (NIL (X1 XI ... XN) . X)}. }} Secondly, if {arg FN} is not defined as a function, {fn SMARTARGLIST} attempts spelling correction on {arg FN} by calling {fn FNCHECK}{index FNCHECK FN} ({PageRef Fn FNCHECK}), passing {arg TAIL} to be used for the call to {fn FIXSPELL}. If unsuccessful, an error will be generated, {lisp {arg FN} NOT A FUNCTION}.{index NOT A FUNCTION Error} If {arg FN} is known to the file package ({PageRef Tag FilePkg}) but not loaded in, {fn SMARTARGLIST} will obtain the arglist information from the file. For all other cases, {fn SMARTARGLIST} simply returns {lisp (ARGLIST {arg FN})}. }{End SubSec Function Type Functions} {index *END* function types} }{End SubSec Function Types} IXGACHA IXz¸