Page Numbers: Yes X: 306 Y: 1.0" First Page: 27
Margins: Top: 1.0" Bottom: 1.3"
Heading:
STANDARD PROCEDURE GUIDE3-LISP REFERENCE MANUAL April 10, 1984
————————————————————————————————————————————
2.b. FUNCTIONS, DEFINITIONS, and CONTROL STRUCTURE
————————————————————————————————————————————
2.b.1. DEFINITIONS, FUNCTIONS, and VARIABLES
————————————————————————————————————————————
(FUNCTION E)
True just in case E designates a function.
F-Type: [ OBJECTS ] TRUTH-VALUESProperties: Primitive; kernel.
Examples:(FUNCTION (LAMBDA [N] (* N N)))g$TRUE
(FUNCTION ↑(LAMBDA [N] (* N N)))
g$FALSE
(FUNCTION 3)
g$FALSE
(DEFINE LABEL FUN)
Establishes a binding of the atom LABEL (not the designation of that atom — i.e., LABEL is in an intensional context) to the function designator (closure) that results from normalising FUN. Unlike SET, DEFINE normalises FUN in an environment in which LABEL will ultimately be bound to the result of the normalisation, to facilitate recursion. (DEFINELABELFUN) is usually used both to establish LABEL as the public name for the function designated by FUN, and to enables FUN to use LABEL as its own internal name for itself. Returns a handle to LABEL Puts the string "LABEL" into the comment field of the closure to which FUN normalises.
Properties:Smash-env; abnormal.
Macro:(DEFINE LABEL FUN)
W> (BEGIN (SET LABEL FUN)
(SET-COMMENT ↑LABEL (ATOM-NOTATION ↑LABEL))
LABEL)
Examples:1> (DEFINE SQUARE (LAMBDA SIMPLE [N] (* N N)))
1=
’SQUARE
1> (DEFINE FACTORIAL
(LAMBDA SIMPLE [N]
(IF (= N 0) 1 (* N (FACTORIAL (1- N))))))
1=
’FACTORIAL
1> (FACTORIAL 6)
1=
720
(LAMBDA PATTERN BODY1 ... BODYk)
Informally, (LAMBDAPATTERNBODY1 ... BODYk) designates the function that is signified by the lambda abstraction of the formal parameters in pattern PATTERN over the BODY structures. LAMBDA is intensional in all its argument positions: neither PATTERN nor any of the BODY is normalised. More formally, (LAMBDAPATTERNBODY) normalises to the closure consisting of a designator of the current environment, and the non-normalised structures PATTERN and BODY. If k>2, the BODYi are wrapped in a (BEGIN ... ) block.
Properties:Kernel; cons; abnormal.
Examples:(LAMBDA [A B] (* A B))g{simple closure: ...}
((LAMBDA [N] (+ N N)) 4)
g8
1> ((LAMBDA [N] (PRINT PS "Hello") N) 4)
Hello1= 4
(RLAMBDA PATTERN BODY1 ... BODYk)
RLAMBDA is used to define reflective procedures; its arguments are exactly as for LAMBDA, but the closure returned is reflectified.
Examples:1> (DEFINE BOUND
(RLAMBDA [CALL ENV ESC CONT]
(CONT (IF (= "unbound variable"
(BINDING
(DOWN (NORMALIZE (1ST (PARGS CALL))
ENV ESC ID))
ENV))
’$FALSE
’$TRUE))))
1= ’BOUND
1> (BOUND (ACONS))
1= $FALSE
1> (LET [[X 3]] (BOUND ’X))
1= $TRUE
(MLAMBDA PATTERN BODY1 ... BODYk)
MLAMBDA is used to define macro procedures; its arguments are exactly as for LAMBDA, but the closure returned is macroified. When a procedure call (FOO.ARGS) is normalised and FOO designates a macro procedure, the sequence of events will be as follows: the arguments to the procedure will not be normalised; the defining environment will be extended by matching the pattern against a designator of the unnormalised arguments; the body will be normalised in this new environment; finally, the result of this normalisation will be re-normalised in the original environment.
F-Type:[ RAILS X STRUCTURES X STRUCTURES ] FUNCTIONS Properties: Cons.
Examples:1> (DEFINE INCREMENT
(MLAMBDA [CALL]
̀ (+ ,(FIRST (PARGS CALL)) 1)))
1=
’INCREMENT
1> (INCREMENT 5)
1=
6
(SET VAR BINDING)
SET alters the current environment’s binding of the atom VAR to be the result of normalising BINDING (in the current environment). Note that the first argument, VAR, is not normalised. Returns the result of normalising BINDING, and therefore designates the designation of BINDING.
Properties: Smash-env; abnormal.
Examples:1> (SET X (+ 2 2))
1=
4
1> X
1=
4
1> (SET X (+ X X))
1=
8
(LET [[A1 E1] ... [Ak Ek]] BODY1 ... BODYk)
Designates the designation that BODY has in an environment which is like the current environment except extended by binding the atoms Ai to the results of normalizing the expressions Ei in environment the current environment. In other words all of the Ei are normalised in the same environment. It can be determined that the Ei will be normalised sequentially, but it is considered bad programming practice to depend on this fact (BEGIN should be used for explicit sequential processing). <<<NOTE: doesn’t hack patterns because lambda only takes a sequence of atoms>>>
Properties:Kernel; env; abnormal.
Macro:(LET [[P1 E1] ... [Pk Ek]] BODY)
W> ((LAMBDA [P1 ... Pk] BODY) E1 ... Ek)
Examples:(LET [[X 3] [Y 4]] (+ X Y))g7
(LET [[X 3]]
(LET [[X 4] [Y X]] (+ X Y)))
g7
(LETSEQ [[P1 E1] ... [Pk Ek]] BODY1 ... BODYk)
LETSEQ is like LET except that each expression Ei+1 is normalised in the environment that results from extending the previous environment with the results of matching pattern Pi against the normalisation of Ei.
Properties:Env; abnormal.
Macro:(LETSEQ [[P1 E1][P2 E2] ... [Pk Ek]] BODY1 ... BODYk)
W> (LET [[P1 E1]]
(LETSEQ [[
P2 E2] ... [Pk Ek]] BODY1 ... BODYk))
Examples:(LET [[X 3]]
(LETSEQ [[X 4] [Y X]] (+ X Y)))
g8
(LETREC [[V1 E1] ... [Vk Ek]] BODY1 ... BODYk)
Like LET and LETSEQ except that each expression Ei is normalised in the environment that results from extending the original environment with the results of binding all of the variables Vi against the normalisations of their Ei. The Ei are all normalised, in other words, in the environment of the overall expression; they should not depend on the bindings of any of the Vi.
Properties:Env; abnormal.
Macro:(LETREC [[V1 E1][V2 E2] ... [Vk Ek]] BODY1 ... BODYk)
W> (LET [[V1 "unbound"][P2 "unbound"] ... [Vk "unbound"]]
(BEGIN (SET
V1 E1)
(SET
V2 E2)
...
(SET
Vk Ek)
BODY1
...
BODYk)))
Examples:(LETREC [[EVEN (LAMBDA [N]
(IF (= N 0) $T (ODD (1- N))))]
[ODD (LAMBDA [N]
(IF (= N 0) $F (NOT (EVEN N))))]]
[(EVEN 2) (ODD 2)])
g[$TRUE $FALSE]
————————————————————————————————————————————
2.b.2. CONTROL STRUCTURES
————————————————————————————————————————————
(EF PREMISE C1 C2)
(IF
PREMISE C1 C2)
Both (IFPREMISEC1C2) and (EFPREMISEC1C2) designate the referent of C1 or C2 depending on whether PREMISE designates true or false, respectively. In the case of IF, C1 (C2) is normalised only if PREMISE designates true (false), whereas EF is fully (procedurally) extensional, in the sense that all three arguments are normalised.
F-Type: [ TRUTH-VALUES X OBJECTS X OBJECTS ] OBJECTS
Properties: Primitive (EF only); kernel; abnormal (IF only).
Examples:1> (IF (= 1 1) ’A ’B)
1=
’A
1> (IF (= 1 2) ’A ’B)
1=
’B
1> (EF (= 1 2)
(PRINT ps "Hello ")
(PRINT ps "Good-bye"))

Hello Good-bye1= ’OK
1> (IF (= 1 2)
(PRINT ps "Hello ")
(PRINT ps "Good-bye" cr))’
Good-bye
1=
’OK
1> (EF [] ’A ’B)
{Error: Truth value expected}
(COND [P1 C11 ... C1k1] ... [Pk Cn1 ... Cnkn])
Designates Ciki for the least i such that Pi designates truth. Only P1, P2, ... , Pi and the Ci are normalised. Error if no Pi designates truth, or some Pi doesn’t designate a truth value.
Properties: Kernel; abnormal.
Examples:1> (COND [(= 1 2) 10]
[(= 1 3) 20]
[(= 1 1) 30]
[$TRUE 40])
1=
30
1> (COND [(= 1 2) (PRINT ps "Once upon a time " cr)]
[(= 1 3) (PRINT ps "in a far away city " cr)]
[(= 1 1) (PRINT ps "lived a tiny little man " cr)]
[$TRUE (PRINT ps "in a great big house." cr)])
lived a tiny little man
1=
’OK
(BEGIN E1 ... Ek)
The results of normalising E1 through Ek-1 are discarded, and the result of normalising Ek is returned. Note that Ek is normalised tail-recursively with respect to the BEGIN.
F-Type: [ {OBJECTS}* X OBJECTS ] OBJECTS
Examples:1> (BEGIN 1 2 3)
1=
3
1> (BEGIN (PRINT ps "Once upon a time ")
(PRINT ps "in a far away city ")
(PRINT ps "lived a tiny little man " cr)
’DONE)
Once upon a time in a far away city lived a tiny little man
1=
’DONE
(MAP FUN S1 S2 ... Sk)
Designates the sequence obtained by applying the function designated by FUN (of arity k) to successive elements of the sequences designated by S1 through Sk. The sequences S1 through Sk should be of equal length. Also works on rails.
F-Type: [ FUNCTIONS X {SEQUENCES}* ] SEQUENCES Properties: Kernel; cons.
[ FUNCTIONS
X {RAILS}* ] RAILS
Examples:(MAP 1+ [2 3 4])g[3 4 5]
(MAP * [1 2 3] [1 2 3])
g[1 4 9]
(MAP EF [$TRUE $FALSE] [1 2] [3 4])
g[1 4]
(MAP PARGS [])
g[]
(MAP UP ’[1 A $TRUE])
g’[’1 ’A ’$TRUE]
(MAP 1+ [1 2 3] [4 5 6])
g{ERROR: Too many arguments.}
(MAP 1 [1 2 3])
g{ERROR: Not a function.}
(MAP 1+ 100)
g{ERROR: Sequence or rail expected.}
(ITERATE FUNCTION SEQ)
Iteratively applies the function designated by FUNCTION to the elements of the sequence (or rail) designated by SEQ, returning the result of the last application (which is processed tail-recursively). Returns an empty rail if the SEQ is null. Used primarily for side-effects; it is definable in terms of, but much simpler than, the DO macro.
F-Type:[ FUNCTIONS X {SEQUENCES U RAILS} ] OBJECTS
Examples:1> (ITERATE (LAMBDA [N] (PRINT PS N))
(REVERSE ’[All That Was]))
’Was ’That ’All1= ’OK
(IGNORE E1 E2 ... Ek)
IGNORE does not process its arguments at all; it returns ’OK. Provided solely for programmer convenience, IGNORE is useful for temporarily blanking out parts of a program, embedding commentary structure to be of use during the program execution, etc. The arguments, however, must be structurally well-formed.
Examples:1> (IGNORE (PRINT PS "HELLO"))
1=
’OK
1> (IGNORE)
1=
’OK
1> (IGNORE These arguments completely and utterly)
1=
’OK
1> (IGNORE These arguments completely, utterly, and totally.)
{Notation error: comma discovered not within the scope of a lexical quotation}
(CATCH TAG BODY)
Normalising (CATCH TAG BODY) normalises BODY in the current environment extended by binding the atom TAG to a procedure which, if called, returns its argument as the result of BODY.
F-Type: [ OBJECTS ] OBJECTS
Examples:1> (CATCH FOO (+ 2 2))
1=
4
1> (CATCH TOSS (+ 2 (TOSS 3)))
1=
3
1> (CATCH TOSS
(BEGIN (TOSS (+ 3 3))
100))
1=
6
1> (CATCH THROW
(BEGIN (NEWLINE PS)
(PRINT ps "Once upon a time ")
(PRINT ps "in a far away city ")
(THROW ’BLAST-OFF)
(PRINT ps "lived a tiny little man ")
(PRINT ps "in a great big house.")))
Once upon a time in a far away city
1=
’BLAST-OFF
1> (CATCH Tag1 (+ 100 (CATCH Tag2 (* 5 (Tag2 3)))))
1=
103
1> (CATCH Tag1 (+ 100 (CATCH Tag2 (* 5 (Tag1 3)))))
1=
3
1> (CATCH Tag1
(+ 100
(CATCH Tag2
(* (Tag2 (* 6 (Tag1 4)))))))
1=
4
1> (CATCH Tag1
(+ 100
(CATCH Tag2
(* (Tag1 (* 6 (Tag2 4)))))))
2=
104
Definition:(DEFINE CATCH
(RLAMBDA [CALL CATCH-ENV CATCH-ESC CATCH-CONT]
(LET [[TAG (ARG 1 CALL)]
[BODY (ARG 2 CALL)]]
(NORMALISE BODY
(BIND TAG
↑(RLAMBDA [THROW-CALL THROW-ENV THROW-ESC THROW-CONT]
(NORMALISE (ARG 1 THROW-CALL)
THROW-ENV
THROW-ESC
CATCH-CONT))
CATCH-ENV)
CATCH-ESC
CATCH-CONT))))
(DELAY C)
Defers the normalisation of C by embedding it in a LAMBDA expression.
Properties: Abnormal.
Macro:(DELAY C)W>(LAMBDA [] C)
Examples:1> (SET X (DELAY (* Y Y)))
1=
{simple closure ...}
1> (SET Y 7)
1=
7
1> (FORCE X)
1=
49
1> (SET Y 9)
1=
9
1> (FORCE X)
1=
81
1> (DEFINE IF-EQUIVALENT
(MLAMBDA [P C1 C2]
’(FORCE (EF ,P (DELAY ,C1) (DELAY ,C2)))))
1=
’IF-EQUIVALENT
1> (IF-EQUIVALENT (= (+ 2 2) 4)
(PRINT ps "Once upon a time ")
(PRINT ps "in a far away city "))
Once upon a time
1=
’OK
(FORCE C)
Causes the normalisation of the DELAYed expression designated by C.
Examples:1> (SET X (DELAY (PRINT ps GREETING cr)))
1=
{Closure}
1> (SET GREETING "Hi there")
1=
"Hi there"
1> (FORCE X)
Hi there
1= ’OK
1> (SET GREETING "Goodbye")
1=
"Goodbye"
1> (FORCE X)
Goodbye
1= ’OK
(DISPATCH INDEX [M1 C1] ... [Mk Ck])
(SELECT INDEX [M1 C1] ... [Mk Ck])
DISPATCH and SELECT allows one of several clauses (the Ci) to be processed based upon the designation of INDEX. The Mi are tested from left to right, stopping as soon as a clause is selected. In the case of DISPATCH, INDEX should designate an atom. If Mi is an atom (not if it designates an atom — the Mi are not normalised), the I’th clause will be selected if the designation of INDEX designates this atom; if Mi is a rail, the I’th clause will be selected if the designation of INDEX is a member of this rail; otherwise, Mi should be the boolean $TRUE which will always be selected. Error if no clause is selected. SELECT is similar except that the selection is based on the designation of Mi instead of the unnormalised structure (i.e., the Mi are normalised). <<<NOTE: niether hack mulitple matches>>>
Properties: Abnormal.
Macro : E.g.(DISPATCH INDEX
[A
C1]
[[A1
... AN] C2]
...
[$TRUE
Ck])
W>
(LET [[{Atom 103}
INDEX]]
(COND [(= {Atom 103} ’A)
C1]
[(MEMBER {Atom 103} ’[A1
... AN]) C2] ;;;<<<bug here>>>
...
[$TRUE
Ck]))
Example:1> (DEFINE ACTIVITY
(LAMBDA [DAY]
(DISPATCH DAY
[SUNDAY ’SLEEP]
[MONDAY ’WORK]
[$TRUE ’RUMINATE])))
1=
’ACTIVITY
1> (ACTIVITY ’SUNDAY)
1=
’SLEEP
1> (DEFINE WHERE-IS
(LAMBDA [S]
(DISPATCH (TYPE S)
[NUMERAL]
’INSIDE
[$TRUE ’OUTSIDE])))
1=
’WHERE-IS
1> (WHERE-IS (+ 1 2))
1=
’OUTSIDE
1> (WHERE-IS ’(+ 1 2))
1= ’
INSIDE
1> (DEFINE CURIO
(LAMBDA [VALUE]
(SELECT (* VALUE VALUE)
[(+ VALUE VALUE) ’ZERO-OR-TWO]
[$TRUE ’SOMETHING-ELSE])))
1=
’CURIO
1> (CURIO (LENGTH [1 2 3]))
1=
’SOMETHING-ELSE
(CURRIED-DISPATCH INDEX [M1 C1] ... [Mk Ck])
<<< To be described >>>
(DO [[VAR1 INIT1 NEXT1] ... [VARk INITk NEXTk]]
[[EXIT-TEST
1 RETURN1] ... [EXIT-TESTj RETURNj]]
BODY
)
DO is a general-purpose iteration operator (taken from SCHEME, and generalised from MACLISP and ZETALISP). The variables VAR1 through VARk are initially bound to the results of normalising the expressions INIT1 through INITk (these "initialising" expressions are normalised sequentially, but all of them are normalised before any of the bindings are established). Then each of the EXIT-TESTi are processed in order; if any is true, the corresponding expression RETURNi is processed, with the result of that RETURNi being returned as the result of the entire DO form. If none of the tests are true, BODY is processed (result ignored), and the variables VAR1 through VARk are bound to the results of processing NEXT1 through NEXTk, and the process repeats. The NEXTi are normalised in an environment in which all of the VARi remain bound to their previous bindings. BODY may be omitted.
Properties: Abnormal; env.
Macro:(DO [[VAR1 INIT1 NEXT1] ... [VARk INITk NEXTk]]
[[EXIT-TEST1 RETURN1] ... [EXIT-TESTj RETURNj]]
BODY
)
W>
(LETREC
[[{loop}
(LAMBDA [
VAR1 ... VARk]
(COND [
EXIT-TEST1 RETURN1]
...
[
EXIT-TESTj RETURNj]
[$TRUE (BEGIN
BODY ({loop} NEXT1 ... NEXTk))]))]]
({loop}
INIT1 ... INITk))
Example:1> (DEFINE STRING-REVERSE
(LAMBDA [STRING]
(DO [[V VEC (STRING-REST V)]
[R "" (STRING-CONS (1ST V) R)]]
[[(STRING-EMPTY V) R]])))
1=
’STRING-REVERSE
1> (STRING-REVERSE "This is a Test")
1= "tseT a si sihT"
1> (STRING-REVERSE "Able was I ere I saw Elba")
1= "ablE was I ere I saw elbA"