{Begin SubSec PROG and Associated Control Functions} {Title PROG and Associated Control Functions} {Text {FnDef {FnName PROG1} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD NLAMBDA} {Text Evaluates its arguments in order, and returns the value of its first argument {arg X{sub 1}}. For example, {lisp (PROG1 X (SETQ X Y))} sets {lisp X} to {lisp Y}, and returns {lisp X}'s original value. }} {FnDef {FnName PROG2} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Similar to {fn PROG1}. Evaluates its arguments in order, and returns the value of its second argument {arg X{sub 2}}. {note arg! takes advantage of fact that evaluator evals ALL args given to a spread fn ... even excess ones.} }} {FnDef {FnName PROGN} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD NLAMBDA} {Text {fn PROGN} evaluates each of its arguments in order, and returns the value of its last argument. {fn PROGN} is used to specify more than one computation where the syntax allows only one, e.g., {lisp (SELECTQ {ellipsis} (PROGN {ellipsis}))} allows evaluation of several expressions as the default condition for a {lisp SELECTQ}. }} {FnDef {FnName PROG} {FnArgs VARLST E{SUB 1} E{SUB 2} {ellipsis} E{SUB N}} {Type NOSPREAD NLAMBDA} {Text This function allows the user to write an ALGOL-like program containing Interlisp expressions (forms) to be executed. The first argument, {arg VARLST}, is a list of local variables{index local variables} (must be {lisp NIL} if no variables are used). Each atom in {arg VARLST} is treated as the name of a local variable and bound to {lisp NIL}. {arg VARLST} can also contain lists of the form {lisp ({arg LITATOM} {arg FORM})}. In this case, {arg LITATOM} is the name of the variable and is bound to the value of {arg FORM}. The evaluation takes place before any of the bindings are performed, e.g., {lisp (PROG ((X Y) (Y X)) {ellipsis})} will bind local variable {lisp X} to the value of {lisp Y} (evaluated {it outside} the {fn PROG}) and local variable {lisp Y} to the value of {lisp X} (outside the {fn PROG}). An attempt to use anything other than a litatom as a {fn PROG} variable will cause an error, {index ARG NOT LITATOM Error}{lisp ARG NOT LITATOM}. An attempt to use {lisp NIL} or {lisp T} as a {fn PROG} variable will cause an error, {index ATTEMPT TO BIND NIL OR T Error}{lisp ATTEMPT TO BIND NIL OR T}. The rest of the {fn PROG} is a sequence of non-atomic statements (forms) and litatoms (labels). The forms are evaluated sequentially;{index PROG label} the labels serve only as markers. The two special functions {fn GO} and {fn RETURN} alter this flow of control as described below. The value of the {fn PROG} is usually specified by the function {fn RETURN}. If no {fn RETURN} is executed before the {fn PROG} "falls off the end," the value of the {fn PROG} is {lisp NIL}. {Note Example!!} }} {FnDef {FnName GO} {FnArgs U} {Type NOSPREAD NLAMBDA} {Text {fn GO} is used to cause a transfer in a {fn PROG}. {lisp (GO L)} will cause the {fn PROG} to evaluate forms starting at the label {lisp L} ({fn GO} does not evaluate its argument). A {fn GO} can be used at any level in a {fn PROG}. If the label is not found, {fn GO} will search higher progs {it within the same function,} e.g., {lisp (PROG {ellipsis} A {ellipsis} (PROG {ellipsis} (GO A)))}. If the label is not found in the function in which the {fn PROG} appears, an error is generated, {lisp UNDEFINED OR ILLEGAL GO}.{index UNDEFINED OR ILLEGAL GO Error} }} {FnDef {FnName RETURN} {FnArgs X} {Text A {fn RETURN} is the normal exit for a {fn PROG}. Its argument is evaluated and is immediately returned the value of the {fn PROG} in which it appears. }} Note: If a {fn GO} or {fn RETURN} is executed in an interpreted function which is not a {fn PROG}, the {fn GO} or {fn RETURN} will be executed in the last interpreted {fn PROG} entered if any, otherwise cause an error.{index ILLEGAL RETURN Error}{index UNDEFINED OR ILLEGAL GO Error} {fn GO} or {fn RETURN} inside of a compiled function that is not a {fn PROG} is not allowed, and will cause an error at compile time. As a corollary, {fn GO} or {fn RETURN} in a functional argument, e.g., to {fn SORT}, will not work compiled. Also, since {fn NLSETQ}'s and {fn ERSETQ}'s compile as {it separate} functions, a {fn GO} or {fn RETURN} {it cannot} be used inside of a compiled {index NLSETQ FN}{fn NLSETQ} or {index ERSETQ FN}{fn ERSETQ} if the corresponding {fn PROG} is outside, i.e., above, the {fn NLSETQ} or {fn ERSETQ}. {Note Is the above also true for ERRORSET in general (on which NLSETQ and ERSETQ are based)? ---mjs <-- No! ERRORSET doesn't create a seperate function ... however, it seems that GO and RETURN won't work under a compiled call to ERRORSET anyway (compiles OK, but gives undef or illegal GO error on execution). Heres the story: it seems that GO (and RETURN too) will not work if inside a function called (via fn call) from a compiled function containing a PROG. If the "function" is actually a macro, so that it is compiled open, or is one of the specially-compiled fns (PROG, COND, etc.), then it works. The important thing is the function call from a compiled function containing a PROG. This is not immediately observable by the random user. Should this explaination be documented?? (perhaps in compiler section??)} {Def {Type (Macro)} {Name LET} {PrintName {lisp (LET {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}} {Text {lisp LET} is essentially a {fn PROG} that can't contain {fn GO}'s or {fn RETURN}'s, and whose last form is the returned value. }} {Def {Type (Macro)} {Name LET*} {PrintName {lisp (LET* {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}} } {Def {Type (Macro)} {Name PROG*} {PrintName {lisp (PROG* {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}} {Text {lisp LET*} and {lisp PROG*} differ from {lisp LET} and {fn PROG} only in that the binding of the bound variables is done "sequentially." Thus {lispcode (LET* ((A (LIST 5)) (B (LIST A A))) (EQ A (CADR B)))} would evaluate to {lisp T}; whereas the same form with {lisp LET} might even find {lisp A} an unbound variable when evaluating {lisp (LIST A A)}. }} }{End SubSec PROG and Associated Control Functions}