Page Numbers: Yes X: 306 Y: 1.0" First Page: 29
Margins: Top: 1.0" Bottom: 1.3"
Heading:
STANDARD PROCEDURE GUIDE3-LISP REFERENCE MANUAL April 16, 1984
————————————————————————————————————————————
2.b.2. CONTROL STRUCTURES
————————————————————————————————————————————
(EF PREMISE C1 C2)
(IF PREMISE C1 C2)
Both (IF PREMISE C1 C2) and (EF PREMISE C1 C2) 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-bye
1= ’OK
1> (IF (= 1 2)
(PRINT ps "Hello ")
(PRINT ps "Good-bye")) 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 ")]
[(= 1 3) (PRINT ps "in a far away city ")]
[(= 1 1) (PRINT ps "lived a tiny little man ")]
[$TRUE (PRINT ps "in a great big house.")]) 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 ")
’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 ’All
1= ’OK
(FOR VAR START END E1 E2 ... Ek)
Binds the variable VAR (which is not normalized) successively to a series of numerals, starting with the result of normalizing START, increasing by 1 each time, and ending with the result of normalizing END (or vice versa, if START designates a number that is greater than the number designated by END), and then normalises the forms E1 through Ek in the resulting environment, finally returning "OK". A very simple numeric counter, useful only for side-effects; FOR is a much simpler form than the more general DO, q.v.
Examples:1> (FOR i 103 107 (print ps i cr))
103
104
105
106
107
1= "ok"
1> (FOR i 10 10 (print ps "this will happen once"))this will happen once
1= "ok"
1> (LET [[X 0]]
(BEGIN (FOR COUNT 100 90 (SET X (+ COUNT X)))
X))
1= 1045
(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= {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)))
1= {simple 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). <<<Currently does not allow sequence as Mi>>>
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] ;;;<<<doesnt do this>>>
...
[$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"]
[STRING "at the edge"]
[$TRUE "outside"])))
1= ’WHERE-IS
1> (WHERE-IS (+ 1 2))
1= "outside"
1> (WHERE-IS ’(+ 1 2))
1= "inside"
1> (WHERE-IS "inside")
1= "at the edge"
1> (DEFINE TEST
(LAMBDA [X]
(SELECT X
[(+ 2 2) "EQUAL 4"]
[$T "NOT EQUAL 4"])))
1= ’TEST
1> (TEST 4)
1= "EQUAL 4"
1> (TEST 5)
1= "NOT EQUAL 4"
(CURRIED-DISPATCH INDEX [P1 C1] ... [Pk Ck])
CURRIED-DISPATCH is like a cross between SELECT and COND. It is like SELECT, in that a specific item or index is tested; it is like COND except that each of the predicates (Pi) must be a pair missing their first argument. In general, if a predicate Pi is of the form (F1 E11 ... E1k1), then the (F-)equivalent CONDwould have a corresponding predicate (F1 INDEX E11 ... E1k1). <<<currently doesn’t work>>>
Properties: Abnormal.
Macro : E.g.(CURRIED-DISPATCH INDEX
[(F1 E11 ... E1k1) C1]
[(F2 E21 ... E2k2) C2]
...
[$TRUE Ck])
W>
(LET [[{Atom 43} INDEX]]
(COND [(F1 {Atom 43} E11 ... E1k) C1]
[(F2 {Atom 43} E21 ... E2k) C2]
...
[$TRUE Ck]))
Example:1> (DEFINE TEST
(LAMBDA [N]
(CURRIED-DISPATCH N
[(> 5) "greater than 5"]
[(= 5) "equal to 5"]
[$T "less than 5"])))
1= ’TEST
1> (TEST 2)
1= "less than 5"
1> (TEST 8)
1= "greater than 5"
(DO [[VAR1 INIT1 NEXT1] ... [VARk INITk NEXTk]]
[[EXIT-TEST1 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 STRING (SUBSTRING 2 (STRING-LENGTH V) V)]
[R "" (STRING-CONS (SUBSTRING 1 1 V) R)]]
[[(= (STRING-LENGTH STRING) 0) 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"