{Begin SubSec Function Evaluation} {Title Function Evaluation} {Text {note it seems that forms like ( (LAMBDA (X) (IPLUS X X)) 5) evaluate, at top level or in a program (this is what EXPANDMACRO of a LAMBDA macro gives). is this handled by the error correction mechanism, or is the evaluation of "function objects" just a regular part of the interpreter? If so, this should be documented.} Usually, function application is done automatically by the Interlisp interpreter. If a form is typed into Interlisp whose {fn CAR} is a function, this function is applied to the arguments in the {fn CDR} of the form. These arguments are evaluated or not, and bound to the function parameters, as determined by the type of the function, and the body of the function is evaluated. This sequence is repeated as each form in the body of the function is evaluated. There are some situations where it is necessary to explicitly call the evaluator, and Interlisp supplies a number of functions that will do this. These functions take "functional arguments", which may either be litatoms with function definitions, or {lisp EXPR} forms such as {lisp (LAMBDA (X) {ellipsis})}, or {lisp FUNARG} expressions (see {PageRef Tag FUNARG}). The following functions are useful when one wants to supply a functional argument which will always return {lisp NIL}, {lisp T}, or 0. {FnDef {FnName NILL} {FnArgs} {Type NOSPREAD} {Text Returns {lisp NIL}. }} {FnDef {FnName TRUE} {FnArgs} {Type NOSPREAD} {Text Returns {lisp T}. }} {FnDef {FnName ZERO} {FnArgs} {Type NOSPREAD} {Text Returns 0. }} Note: When using {lisp EXPR} expressions as functional arguments, they should be enclosed within the function {fn FUNCTION} ({PageRef Fn FUNCTION}) rather than {fn QUOTE}, so that they will be compiled as separate functions. {fn FUNCTION} can also be used to create {lisp FUNARG} expressions, which can be used to solve some problems with referencing free variables, or to create functional arguments which carry "state" along with them. {FnDef {FnName EVAL} {FnArgs X {anonarg}} {Text {fn EVAL} evaluates the expression {arg X} and returns this value, i.e., {fn EVAL} provides a way of calling the Interlisp interpreter.{index interpreter} Note that {fn EVAL} is itself a lambda function, so {it its} argument is first evaluated, e.g., {lispcode ←(SETQ FOO '(ADD1 3)) (ADD1 3) ←(EVAL FOO) 4 ←(EVAL 'FOO) (ADD1 3)} }} {FnDef {FnName EVALHOOK} {FnArgs FORM EVALHOOKFN}} {Text {fn EVALHOOK} evaluates the expression {arg FORM} in a special way. While evaluating {arg FORM}, {fn EVAL} behaves in a special way. The argument {arg EVALHOOKFN} should be a function of one argument. The first time a list is to be evaluated (except for {arg FORM} itself), whether implicitly or via an explicit call to {fn EVAL}, no attempt is made to evaluate the form. Instead, {arg EVALHOOKFN} is invoked, and passed the form to be evaluated as its argument. {arg EVALHOOKFN} is then responsible for evaluating the form; whatever is returned is assumed to be the result of evaluating the form. (Note: {fn EVALHOOK} is not implemented in Interlisp-10.) Here is an example of a simple tracing routine that uses the {fn EVALHOOK} feature: {lispcode ←(DEFINEQ (PRINTHOOK (FORM) (printout T "eval: " FORM T) (EVALHOOK FORM (FUNCTION PRINTHOOK] (PRINTHOOK) } Using {lisp PRINTHOOK}, one might see the following interaction: {lispcode ←(EVALHOOK '(LIST (CONS 1 2) (CONS 3 4)) 'PRINTHOOK) eval: (CONS 1 2) eval: (CONS 3 4) ((1 . 2) (3 . 4)) }} {FnDef {FnName QUOTE} {FnArgs X} {Type NOSPREAD NLAMBDA} {Text Interlisp functions can either evaluate or not evaluate these arguments. For those cases where it is desirable to specify arguments unevaluated, one may use the {fn QUOTE} function. {fn QUOTE} prevents its arguments from being evaluated. Its value is {arg X} itself, e.g., {lisp (QUOTE FOO)} is {lisp FOO}. Note: Since giving {fn QUOTE} more than one argument is almost always a parentheses error, and one that would otherwise go undetected, {fn QUOTE} itself generates an error in this case, {lisp PARENTHESIS ERROR}.{index PARENTHESIS ERROR Error} }} {FnDef {FnName KWOTE} {FnArgs X} {Text Value is an expression which when evaluated yields {arg X}. If {arg X} is {lisp NIL} or a number, this is {arg X} itself. Otherwise, {lisp (LIST (QUOTE QUOTE) {arg X})}. For example, if the value of {lisp X} is {lisp A} and the value of {lisp Y} is {lisp B}, then {lisp (KWOTE (CONS X Y))} = {lisp (QUOTE (A . B))}. }} {FnDef {FnName DEFEVAL} {FnArgs TYPE FN} {Text Specifies how a datum of a particular type is to be evaluated.{foot {var COMPILETYPELST} ({PageRef Var COMPILETYPELST}) {index COMPILETYPELST Var} permits the user to specify how a datum of a particular type is to be compiled. }{comment endfootnote} Intended primarily for user defined data types, but works for all data types except lists, literal atoms, and numbers. {arg TYPE} is a type name. {arg FN} is a function object, i.e. name of a function or a lambda expression. Whenever the interpreter encounters a datum of the indicated type, {arg FN} is applied to the datum and its value returned as the result of the evaluation. {fn DEFEVAL} returns the previous evaling function for this type. If {arg FN}={lisp NIL}, {fn DEFEVAL} returns the current evaling function without changing it. If {arg FN}={lisp T}, the evaling function is set back to the system default (which for all data types except lists is to return the datum itself). }} {FnDef {FnName APPLY} {FnArgs FN ARGLIST {anonarg}} {Text Applies the function {arg FN} to the arguments in the list {arg ARGLIST}, and returns its value. {fn APPLY} is a lambda function, so its arguments are evaluated, but the individual elements of {arg ARGLIST} are not evaluated. Therefore, lambda and nlambda functions are treated the same by {fn APPLY}; lambda functions take their arguments from {arg ARGLIST} without evaluating them. Note that {arg FN} may still explicitly evaluate one or more of its arguments itself, as {fn SETQ} does. Thus, {lisp (APPLY 'SETQ '(FOO (ADD1 3)))} will set {lisp FOO} to 4, whereas {lisp (APPLY 'SET '(FOO (ADD1 3)))} will set {lisp FOO} to the expression {lisp (ADD1 3)}. {fn APPLY} can be used for manipulating {lisp EXPR}s, for example: {lispcode ←(APPLY '(LAMBDA (X Y) (ITIMES X Y)) '(3 4)) 12} }} {FnDef {FnName APPLY*} {FnArgs FN ARG{SUB 1} ARG{SUB 2} {ellipsis} ARG{SUB N}} {Type NOSPREAD} {Text Nospread version of {fn APPLY}, equivalent to {lisp (APPLY {arg FN} (LIST {arg ARG{SUB 1}} {arg ARG{SUB 2}} {ellipsis} {arg ARG{SUB N}}))}. }} {Begin Note} Say something here about max number of args. is the bad error message ILLEGAL CDR ARG LIST fixed yet???? ---> Yes, now is TOO MANY ARGS Date: 9 Dec. 1980 3:45 pm PST (Tuesday) From: Masinter.PA You now cannot call a function with > 85 args (EVAL, APPLY, compiler complain "ILLEGAL CDR ARG LIST"). {End Note} {FnDef {FnName EVALA} {FnArgs X A} {Text Simulates a-list{index a-lists (in EVALA) Term} evaluation as in LISP 1.5. {arg X} is a form, {arg A} is a list of the form: {lispcode ( ({arg NAME{sub 1}} . {arg VAL{sub 1}}) ({arg NAME{sub 2}} . {arg VAL{sub 2}}) {ellipsis} ({arg NAME{sub N}} . {arg VAL{sub N}}) )} The variable names and values in {arg A} are "spread" on the stack, and then {arg X} is evaluated. Therefore, any variables appearing free in {arg X}, that also appears as {fn CAR} of an element of {arg A} will be given the value in the {fn CDR} of that element. {Begin Note} in Interlisp-10, ABC, evala(foo ((foo . a) (foo . b)) -> B in Interlisp-D, evala(foo ((foo . a) (foo . b)) -> A doc?? {End Note} }} The functions below are used to evaluate a form or apply a function repeatedly. {fn RPT}, {fn RPTQ}, and {fn FRPTQ} evaluate a given form a specified number of times. {fn MAP}, {fn MAPCAR}, {fn MAPLIST}, etc. apply a given function repeatedly to different elements of a list, possibly constructing another list. These functions allow efficient iterative computations, but they are difficult to use. For programming iterative computations, it is usually better to use the CLISP Iterative Statement facility ({PageRef Tag IterativeStatement}), which provides a more general and complete facility for expressing iterative statements. Whenever possible, CLISP translates iterative statements into expressions using the functions below, so there is no efficiency loss. {FnDef {FnName RPT} {FnArgs N FORM} {Text Evaluates the expression {arg FORM}, {arg N} times. Returns the value of the last evaluation. If {arg N} {le} 0, {arg FORM} is not evaluated, and {fn RPT} returns {lisp NIL}. Before each evaluation, the local variable {lisp RPTN} is bound to the number of evaluations yet to take place. This variable can be referenced within {arg FORM}. For example, {lisp (RPT 10 '(PRINT RPTN))} will print the numbers 10, 9, {ellipsis} 1, and return 1. {note RTPN can also be set within the form, changing the number of iterations} }} {FnDef {FnName RPTQ} {FnArgs N FORM{SUB 1} FORM{SUB 2} {ellipsis} FORM{SUB N}} {Type NOSPREAD NLAMBDA} {Text Nlambda-nospread version of {fn RPT}: {arg N} is evaluated, {arg FORM{SUB i}} are not. Returns the value of the last evaluation of {arg FORM{SUB N}}. }} {FnDef {FnName FRPTQ} {FnArgs N FORM{SUB 1} FORM{SUB 2} {ellipsis} FORM{SUB N}} {Type NOSPREAD NLAMBDA} {Text Faster version of {fn RPTQ}. Does not bind {lisp RPTN}. }} {FnDef {FnName MAP} {FnArgs MAPX MAPFN1 MAPFN2} {Text If {arg MAPFN2} is {lisp NIL}, {fn MAP} applies the function {arg MAPFN1} to successive tails of the list {arg MAPX}. That is, first it computes {lisp ({arg MAPFN1} {arg MAPX})}, and then {lisp ({arg MAPFN1} (CDR {arg MAPX}))}, etc., until {arg MAPX} becomes a non-list. If {arg MAPFN2} is provided, {lisp ({arg MAPFN2} {arg MAPX})} is used instead of {lisp (CDR {arg MAPX})} for the next call for {arg MAPFN1}, e.g., if {arg MAPFN2} were {fn CDDR}, alternate elements of the list would be skipped. {fn MAP} returns {lisp NIL}. }} {FnDef {FnName MAPC} {FnArgs MAPX MAPFN1 MAPFN2} {Text Identical to {fn MAP}, except that {lisp ({arg MAPFN1} (CAR {arg MAPX}))} is computed at each iteration instead of {lisp ({arg MAPFN1} {arg MAPX})}, i.e., {fn MAPC} works on elements, {fn MAP} on tails. {fn MAPC} returns {lisp NIL}. }} {FnDef {FnName MAPLIST} {FnArgs MAPX MAPFN1 MAPFN2} {Text Successively computes the same values that {fn MAP} would compute, and returns a list consisting of those values. }} {FnDef {FnName MAPCAR} {FnArgs MAPX MAPFN1 MAPFN2} {Text Computes the same values that {fn MAPC} would compute, and returns a list consisting of those values, e.g., {lisp (MAPCAR X 'FNTYP)} is a list of {fn FNTYP}s for each element on {lisp X}. }} {FnDef {FnName MAPCON} {FnArgs MAPX MAPFN1 MAPFN2} {Text Computes the same values as {fn MAP} and {fn MAPLIST} but {fn NCONC}s these values to form a list which it returns. }} {FnDef {FnName MAPCONC} {FnArgs MAPX MAPFN1 MAPFN2} {Text Computes the same values as {fn MAPC} and {fn MAPCAR}, but {fn NCONC}s the values to form a list which it returns. }} Note that {fn MAPCAR} creates a new list which is a mapping of the old list in that each element of the new list is the result of applying a function to the corresponding element on the original list. {fn MAPCONC} is used when there are a {it variable} number of elements (including none) to be inserted at each iteration. Examples: {lispcode (MAPCONC '(A B C NIL D NIL) '(LAMBDA (Y) (if (NULL Y) then NIL else (LIST Y)))) ==> (A B C D)} This {fn MAPCONC} returns a list consisting of {arg MAPX} with all {lisp NIL}s removed. {lispcode (MAPCONC '((A B) C (D E F) (G) H I) '(LAMBDA (Y) (if (LISTP Y) then Y else NIL))) ==> (A B D E F G)} This {fn MAPCONC} returns a linear list consisting of all the lists on {arg MAPX}. Since {fn MAPCONC} uses {fn NCONC} to string the corresponding lists together, in this example the original list will be altered to be {lisp ((A B D E F G) C (D E F G) (G) H I)}. If this is an undesirable side effect, the functional argument to {fn MAPCONC} should return instead a top level copy of the lists, i.e. {lisp (LAMBDA (Y) (if (LISTP Y) then (APPEND Y) else NIL)))}. {FnDef {FnName MAP2C} {FnArgs MAPX MAPY MAPFN1 MAPFN2} {Text Identical to {fn MAPC} except {arg MAPFN1} is a function of two arguments, and {lisp ({arg MAPFN1} (CAR {arg MAPX}) (CAR {arg MAPY}))} is computed at each iteration. Terminates when either {arg MAPX} or {arg MAPY} is a non-list. {arg MAPFN2} is still a function of one argument, and is applied twice on each iteration; {lisp ({arg MAPFN2} {arg MAPX})} gives the new {arg MAPX}, {lisp ({arg MAPFN2} {arg MAPY})} the new {arg MAPY}. {fn CDR} is used if {arg MAPFN2} is not supplied, i.e., is {lisp NIL}. }} {FnDef {FnName MAP2CAR} {FnArgs MAPX MAPY MAPFN1 MAPFN2} {Text Identical to {fn MAPCAR} except {arg MAPFN1} is a function of two arguments and {lisp ({arg MAPFN1} (CAR {arg MAPX}) (CAR {arg MAPY}))} is used to assemble the new list. Terminates when either {arg MAPX} or {arg MAPY} is a non-list. }} {FnDef {FnName SUBSET} {FnArgs MAPX MAPFN1 MAPFN2} {Text Applies {arg MAPFN1} to elements of {arg MAPX} and returns a list of those elements for which this application is non-{lisp NIL}, e.g., {lisp (SUBSET '(A B 3 C 4) 'NUMBERP)} = {lisp (3 4)}. {arg MAPFN2} plays the same role as with {fn MAP}, {fn MAPC}, et al. }} {FnDef {FnName EVERY} {FnArgs EVERYX EVERYFN1 EVERYFN2} {Text Returns {lisp T} if the result of applying {arg EVERYFN1} to each element in {arg EVERYX} is true, otherwise {lisp NIL}. For example, {lisp (EVERY '(X Y Z) 'ATOM) => T}. {fn EVERY} operates by evaluating {lisp ({arg EVERYFN1} (CAR {arg EVERYX}) {arg EVERYX})}. The second argument is passed to {arg EVERYFN1} so that it can look at the next element on {arg EVERYX} if necessary. If {arg EVERYFN1} yields {lisp NIL}, {fn EVERY} immediately returns {lisp NIL}. Otherwise, {fn EVERY} computes {lisp ({arg EVERYFN2} {arg EVERYX})}, or {lisp (CDR {arg EVERYX})} if {arg EVERYFN2}={lisp NIL}, and uses this as the "new" {arg EVERYX}, and the process continues. For example, {lisp (EVERY {arg X} 'ATOM 'CDDR)} is true if every {it other} element of {arg X} is atomic. }} {FnDef {FnName SOME} {FnArgs SOMEX SOMEFN1 SOMEFN2} {Text Returns the tail of {arg SOMEX} beginning with the first element that satisfies {arg SOMEFN1}, i.e., for which {arg SOMEFN1} applied to that element is true. Value is {lisp NIL} if no such element exists. {lisp (SOME X '(LAMBDA (Z) (EQUAL Z Y)))} is equivalent to {lisp (MEMBER Y X)}. {fn SOME} operates analogously to {fn EVERY}. At each stage, {lisp ({arg SOMEFN1} (CAR {arg SOMEX}) {arg SOMEX})} is computed, and if this is not {lisp NIL}, {arg SOMEX} is returned as the value of {fn SOME}. Otherwise, {lisp ({arg SOMEFN2} {arg SOMEX})} is computed, or {lisp (CDR {arg SOMEX})} if {arg SOMEFN2}={lisp NIL}, and used for the next {arg SOMEX}. }} {FnDef {FnName NOTANY} {FnArgs SOMEX SOMEFN1 SOMEFN2} {Text {lisp (NOT (SOME {arg SOMEX} {arg SOMEFN1} {arg SOMEFN2}))} }} {FnDef {FnName NOTEVERY} {FnArgs EVERYX EVERYFN1 EVERYFN2} {Text {lisp (NOT (EVERY {arg EVERYX} {arg EVERYFN1} {arg EVERYFN2}))} }} {FnDef {FnName MAPRINT} {FnArgs LST FILE LEFT RIGHT SEP PFN LISPXPRINTFLG} {Text A general printing function. It cycles through {arg LST} applying {arg PFN} (or {fn PRIN1} if {arg PFN} not given) to each element of {arg LST}. Between each application, {fn MAPRINT} performs {fn PRIN1} of {arg SEP} (or " " if {arg SEP}={lisp NIL}). If {arg LEFT} is given, it is printed (using {fn PRIN1}) initially; if {arg RIGHT} is given it is printed (using {fn PRIN1}) at the end. For example, {lisp (MAPRINT X NIL '%( '%))} is equivalent to {fn PRIN1} for lists. To print a list with commas between each element and a final "." one could use {lisp (MAPRINT X T NIL '%. '%,)}. If {arg LISPXPRINTFLG}={lisp T}, {fn LISPXPRIN1} ({PageRef Fn LISPXPRIN1}) is used instead of {fn PRIN1}. {note move MAPRINT to i/o section?? where??} }} }{End SubSec Function Evaluation} {Begin SubSec Functional Arguments} {Title Functional Arguments} {Text When using functional arguments, the following function is very useful: {FnDef {FnName FUNCTION} {FnArgs FN ENV} {Type NLAMBDA} {Text If {arg ENV}={lisp NIL}, {fn FUNCTION} is the same as {fn QUOTE}, except that it is treated differently when compiled. Consider the function definition: {lispcode (DEFINEQ (FOO {ellipsis} (FIE LST (FUNCTION (LAMBDA (Z) (ITIMES Z Z)))) ) )} {lisp FOO} calls the function {lisp FIE} with the value of {lisp LST} and the {lisp EXPR} expression {lisp (LAMBDA (Z) (LIST (CAR Z)))}. If {lisp FOO} is run interpreted, it doesn't make any difference whether {fn FUNCTION} or {fn QUOTE} is used. However, when {lisp FOO} is compiled, if {fn FUNCTION} is used the compiler will define and compile the {lisp EXPR} as an auxiliary function (See {PageRef Tag CompilingFUNCTION}). The compiled {lisp EXPR} will run considerably faster, which can make a big difference if it is applied repeatedly. Note: Compiling {fn FUNCTION} will {it not} create an auxiliary function if it is a functional argument to a function that compiles open, such as most of the mapping functions ({fn MAPCAR}, {fn MAPLIST}, etc.). If {arg ENV} is not {lisp NIL}, it can be a list of variables that are (presumably) used freely by {arg FN}. In this case, the value of {fn FUNCTION} is an expression of the form {lisp (FUNARG {arg FN} {arg POS})}, where {arg POS} is a stack pointer to a frame that contains the variable bindings for those variables on {arg ENV}. {arg ENV} can also be a stack pointer itself, in which case the value of {fn FUNCTION} is {lisp (FUNARG {arg FN} {arg ENV})}. Finally, {arg ENV} can be an atom, in which case it is evaluated, and the value interpreted as described above. }} {Tag FUNARG} {index *BEGIN* *PRIMARY* FUNARG Litatom} {index *BEGIN* variable bindings} As explained above, one of the possible values that {fn FUNCTION} can return is the form {lisp (FUNARG {arg FN} {arg POS})}, where {arg FN} is a function and {arg POS} is a stack pointer. {lisp FUNARG} is not a function itself. Like {lisp LAMBDA} and {lisp NLAMBDA}, it has meaning and is specially recognized by Interlisp only in the context of applying a function to arguments. In other words, the expression {lisp (FUNARG {arg FN} {arg POS})} is used exactly like a function. When a {lisp FUNARG} expression is applied or is {fn CAR} of a form being {fn EVAL}'ed, the {fn APPLY} or {fn EVAL} takes place in the access environment specified by {arg ENV} (see {PageRef Tag STACK}). Consider the following example: {lispcode ← (DEFINEQ (DO.TWICE (FN VAL) (APPLY* FN (APPLY* FN VAL))) ) (DO.TWICE) ← (DO.TWICE [FUNCTION (LAMBDA (X) (IPLUS X X))] 5) 20 ← (SETQ VAL 1) 1 ← (DO.TWICE [FUNCTION (LAMBDA (X) (IPLUS X VAL))] 5) 20 ← (DO.TWICE [FUNCTION (LAMBDA (X) (IPLUS X VAL)) (VAL)] 5) 7} {lisp DO.TWICE} is defined to apply a function {lisp FN} to a value {lisp VAL}, and apply {lisp FN} again to the value returned; in other words it calculates {lisp (FN (FN VAL))}. Given the {lisp EXPR} expression {lisp (LAMBDA (X) (IPLUS X X))}, which doubles a given value, it correctly calculates {lisp (FN (FN 5))} = {lisp (FN 10)} = 20. However, when given {lisp (LAMBDA (X) (IPLUS X VAL))}, which should add the value of the global variable {lisp VAL} to the argument {lisp X}, it does something unexpected, returning 20 again, rather than 5+1+1 = 7. The problem is that when the {lisp EXPR} is evaluated, it is evaluated in the context of {lisp DO.TWICE}, where {lisp VAL} is bound to the second argument of {lisp DO.TWICE}, namely 5. In this case, one solution is to use the {arg ENV} argument to {fn FUNCTION} to construct a {lisp FUNARG} expression which contains the value of {lisp VAL} at the time that the {fn FUNCTION} is executed. Now, when {lisp (LAMBDA (X) (IPLUS X VAL))} is evaluated, it is evaluated in an environment where the global value of {lisp VAL} is accessable. Admittedly, this is a somewhat contrived example (it would be easy enough to change the argument names to {lisp DO.TWICE} so there would be no conflict), but this situation arises occasionally with large systems of programs that construct functions, and pass them around. Note: System functions with functional arguments ({fn APPLY}, {fn MAPCAR}, etc.) are compiled so that their arguments are local, and not accessable (see {PageRef Tag LOCALVARS}). This reduces problems with conflicts with free variables used in functional arguments. {lisp FUNARG} expressions can be used for more than just circumventing the clashing of variables. For example, a {lisp FUNARG} expression can be returned as the value of a computation, and then used "higher up". Furthermore, if the function in a {lisp FUNARG} expression {it sets} any of the variables contained in the frame, only the frame would be changed. For example, consider the following function: {lispcode (MAKECOUNTER (CNT) (FUNCTION [LAMBDA NIL (PROG1 CNT (SETQ CNT (ADD1 CNT] (CNT)))} The function {lisp MAKECOUNTER} returns a {lisp FUNARG} that increments and returns the previous value of the counter {lisp CNT}. However, this is done within the environment of the call to {lisp MAKECOUNTER} where {fn FUNCTION} was executed, which the {lisp FUNARG} expression "carries around" with it, even after {lisp MAKECOUNTER} has finished executing. Note that each call to {lisp MAKECOUNTER} creates a {lisp FUNARG} expression with a new, independent environment, so that multiple counters can be generated and used: {lispcode ← (SETQ C1 (MAKECOUNTER 1)) (FUNARG (LAMBDA NIL (PROG1 CNT (SETQ CNT (ADD1 CNT)))) #1,13724/*FUNARG) ← (APPLY C1) 1 ← (APPLY C1) 2 ← (SETQ C2 (MAKECOUNTER 17)) (FUNARG (LAMBDA NIL (PROG1 CNT (SETQ CNT (ADD1 CNT)))) #1,13736/*FUNARG) ← (APPLY C2) 17 ← (APPLY C2) 18 ← (APPLY C1) 3 ← (APPLY C2) 19} By creating a {lisp FUNARG} expression with {fn FUNCTION}, a program can create a function object which has updateable binding(s) associated with the object which last {it between} calls to it, but are only accessible through that instance of the function. For example, using the {lisp FUNARG} device, a program could maintain two different instances of the same random number generator in different states, and run them independently. Note: In Interlisp-10, environment switching is expensive because it is a shallow-binding system (see {PageRef Tag STACK}), so this may restrict the applications of {lisp FUNARG} expressions. {Note We need better examples of the use of FUNARG, using (and pointing out the differences between) both upward and downward funargs} {note is there any way for a fn definition to be a funarg (perhaps a DEFINE with an ENV argument)? It doesn't work to PUTD a FUNARG expression into a fn --- applying the function produces an U.D.F. error. Perhaps the evaluator should recognize FUNARG expressions as function definitions.} {note what happens if you reference free variables within a funcarg that are not in the var list that the funarg was created with??} {Begin Note} Date: 26 MAY 1982 2333-PDT From: MASINTER.PA The last editdate on the code for generating FUNARGs from variable lists was 1980. The code has a fatal flaw which causes an ILLEGAL STACK ARG error. Prior to 1980, I don't believe there was any code there at all. We just got a bug-report about it! Does anyone remember this ever working? (p.s.: I note in investigating that Interlisp-10 incorrectly retains the access chain of the entire computation, i.e., if you say (FUNCTION & (A B)) you will get (FUNARG & stackp) where "stackp" contains the entire ALINK chain at the time of the FUNCTION. {End Note} {index *END* variable bindings} {index *END* *PRIMARY* FUNARG Litatom} }{End SubSec Functional Arguments}