Page Numbers: Yes X: 310 Y: 10.44" First Page: 1
Margins: Top: 1.0" Bottom: 1.3"
Heading:
CS-370 (FALL 1982)A 2-LISP SAMPLER
————————————————————————————————————————————
Filed on: [phylum]<3-lisp>documentation>2-sampler.bravoLast edited: October 12, 1982 10:03 AM
————————————————————————————————————————————
A 2-LISP SAMPLER
————————————————————————————————————————————
Contents:
1.Truth-values17.Closures
2.Numbers and Arithmetic18.LET and LET*
3.Characters19.Conditionals
4.Sequences20.Input/Ouput
5.Atoms21.Definitions and Recursion
6.Functions and LAMBDA22.SET
7.Strings23.NORMALISE and REDUCE
8.UP () and Handles24.Pattern Matching
9. vs. 25.Macros and Backquote
10.DOWN and 26.l-deferral
11.Pairs27.Continuation-passing Style
12.Rails28.Higher-order Functions
13.Sequences vs. Rails29.Intensional consequence
14.Replace30.Complex Booleans
15.Identity31.Non-spread arguments
16.Typing32.Y-operators
33.BLOCK
————————————————————————————————————————————
General Notes: The prompt ‘I> ’ requests input; output is printed following the prompt ‘=> ’. Input expressions have been printed in italics.
1. Truth-values
I> $T; $T designates truth
=> $T
; and is a normal-form designator.
I> $F; $F is the normal-form designator of falsity.
=> $F
I> $t; Case is unimportant for notating the booleans.
=> $T
I> (TYPE $T); Note that TYPE, like every function, is defined
=> ’TRUTH-VALUE; over the designation of its argument expression.
I> (TYPE $F)
=> ’TRUTH-VALUE
I> (TRUTH-VALUE $T)
=> $T
I> (TRUTH-VALUE 5)
=> $F
I> (= 2 2); Sentences (complex expressions with a predicate in
=> $T; function position) designate truth or falisty, and
I> (= 2 3); therefore normalise to $T or $F.
=> $F
;
I> (NOT $T); Logical negation
=> $F
I> (NOT $F)
=> $T
I> (OR (= 2 2) (= 2 3)); Disjunction.
=> $T
I> (AND (= 2 2) (= 2 3)); Conjunction.
=> $F
I> (AND); AND with no arguments designates Truth, whereas
=> $T
; OR with no arguments designates Falsity.
I>
(OR)
=> $F
I> (IF $T 1 2); Truth-values must be used for conditional selection.
=> 1
I> (IF $F 1 2)
=> 2
2. Numbers and Arithmetic
I> 23; 23 designates the (external) number twenty-three
=> 23; and is a normal-form designator.
I> +4; Numerals are printed out using the simplest lexical
=> 4; notation (no leading "+", no extraneous zeroes, etc.)
I> -26; Internal numerals have no radix; only notations have
=> -26; radix; standard 2-LISP notation is base 10 (decimal).
I> 00000111
=> 111
I> -0; Minus 0 is 0.
=> 0
I> (TYPE 17)
=> ’NUMBER
I> (NUMBER 9)
=> $T
I> (+ 6 7); Base 10 notation
=> 13
I> (LET [[X 3][Y 4]] (+ X Y))
=> 7
I> (* 6 7)
=> 42
I> (= (+ 2 2) (* 2 2))
=> $T
I> (- 5 9)
=> -4
I> (/ 4 2)
=> 2
I> (/ 5 3)
=> 1
I> (/ 1 0)
<ERROR: division by zero>
3. Characters
I> #A; Designates the (external) character capital A
=> #A; and is a normal-form designator.
I> # ; Designates the space character.
=> #
I> #;; Designates semicolon.
=> #;
I> (TYPE #B)
=> ’CHARACTER
I> (CHARACTER #C)
=> $T
I> (= #A #A); Speaking linguisticly, #A designates the character type,
=> $T; not a specific token.
I> (= #A #B)
=> $F
I> (= #A #a); Case is important.
=> $F
4. Sequences
I> [1 2 3]; Designates a sequences of three numbers and is
=> [1 2 3]; a normal-form designator.
I> [(+ 1 2) (+ 3 4)]; Non-normal-form rails are possible too.
=> [3 7]
I> []; Designates the empty sequence.
=> []
I> (EMPTY []); EMPTY is true of sequences of length 0
=> $T
I> (EMPTY [1 2 3])
=> $F
I> (LENGTH [0 0 0])
=> 3
I> (LENGTH [])
=> 0
I> (TYPE [1 2 3])
=> ’SEQUENCE
I> (SEQUENCE [1])
=> $T
I> (SEQUENCE [])
=> $T
I> (NTH 1 [100 200 300]); Indexing of elements starts with 1, not 0
=> 100
I> (NTH 3 [100 200 300])
=> 300
I> (NTH 0 [100 200 300])
<ERROR in NTH>
I> (LET [[X 1][Y 2][Z 3]] [X Y Z])
=> [1 2 3]
I> (TAIL 1 [1 2])
=> [2]
I> (TAIL 2 [1 2])
=> []
I> (TAIL 0 [1 2 3]); The first argument to TAIL can range from 0
=> [1 2 3]
; to the length of the second argument
I> (TAIL 4 [1 2 3])
<ERROR in TAIL>
I> (PREP $T [1 2 3])]; PREP’ is short for ‘prepend’, but is pronounced in a way
=> [$T 1 2 3]
])]; that connotes aligators.
I> (PREP [1] [2 3])
=> [[1] 2 3]
I> (PREP $F [])
=> [$F]
I> (APPEND [1 2 3] [4 5 6])
=> [1 2 3 4 5 6]
I> (APPEND [] [$T $F])
=> [$T $F]
I> (APPEND [1 $T] [])
=> [1 $T]
I> (1ST [100 200 300])
=> 100
I> (2ND [100 200 300])
=> 200
I> (5TH [100 200 300 400 500 600])
=> 500
I> (REST [100 200 300]); (REST X) is equivalent to (TAIL 1 X)
=> [200 300]
I> (UNIT [1 2 3])
=> $F
I> (UNIT [100]); UNIT is true of sequences of length 1
=> $T
I> (DOUBLE [100 200]); DOUBLE is true of sequences of length 2
=> $T
I> (DOUBLE [])
=> $F
I> (= [1 2 3] [1 2 3])
=> $T
I> (= [1 2 3] [1 3 2])
=> $F
I> (= (TAIL 1 [1]) [])
=> $T
I> [1 $T [2 $F]]
=> [1 $T [2 $F]]
I> (SCONS 1 2 3); A rarely-needed operation.
=> [1 2 3]
5. Atoms
I> ’ZAPHOD; Designates an atom.
=> ’ZAPHOD
I> ’nil; Case is not important in atom notation.
=> ’NIL
I> ’1+
=> ’1+
I> (= ’A ’A)
=> $T
I> (= ’A ’B)
=> $F
I> (= ’a ’A)
=> $T
I> (= ’A #A); Atoms are not characters, nor are they charats
=> $F
I> (TYPE ’A)
=> ’ATOM
I> (ATOM ’A)
=> $T
I> (ACONS); Some atoms have no name.
=> <Atom>
I> (= (ACONS) (ACONS)); Newly created atoms are always distinct.
=> $F
I> (LET [[X (ACONS)]] (= X X))
=> $T
6. Functions and Lambda
I> (TYPE +)
=> ’FUNCTION
I> (FUNCTION NTH)
=> $T
I> (= NTH NTH)
<ERROR: = is not defined over functions>
I> (TYPE LET)
=> ’FUNCTION
I> (TYPE IF)
=> ’FUNCTION
I> +; Not printable.
=> <Closure for +>
I> [+ - *]
=> [<Closure for +> <Closure for -> <Closure for *>]
I> (LET [[PLUS +]] (PLUS 2 3))
=> 5
I> (IF (= 1 1) + -)
=> <Closure for +>
I> ((IF (= 1 2) + -) 2 2)
=> 0
I> (TYPE (LAMBDA EXPR [X] X))
=> ’FUNCTION
I> ((LAMBDA EXPR [X] X) 5)
=> 5
7. Strings
I> "String"
=> "String"
I> (LENGTH "Word")
=> 4
I> [#S #t #r #i #n #g]; Currently, strings are nothing more than
=> "String"; character sequences.
I> (TYPE "Hello there")
=> ’SEQUENCE
I> (APPEND "Four" (APPEND "Letter" "Word"))
=> "FourLetterWord"
I> (PREP #( "Balanced)")
=> "(Balanced)"
I> (PREP 1 "Oops"); So-called ‘string’ notation cannot be used if not all
=> [1 #O #o #p #s]; the elements of the sequence are characters
I> (NTH 3 "Arthur")
=> #t
I> (= "xyz" "xyz")
=> $T
I> "The word ""etcetera"" in Latin"; Interior quotation marks must be doubled
=> "The word ""etcetera"" in Latin"
I>
(Print "The name ""John""") The name "John"
=> ’OK
I> """"; The string consisting of just a double quote character
=> """"
I>
(LENGTH """")
=> 1
I> (1ST """")
=> #"
I> (LENGTH "")
=> 0
I> ""; Sadly, the empty string is the same entity as the empty
=> []; sequence; the printer can’t distinguish them
8. Up () and Handles
I> (UP 1); Designates a normal-form designator of the number 1
=> ’1; i.e., the numeral 1.
I>
↑1; Up-arrow is short for UP; we will always use this abbreviation
=> ’1
I> (TYPE 1)
=> ’NUMBER
I> (TYPE ↑1); Numerals designate numbers.
=> ’NUMERAL
I> ↑1
=> ’1
I> ’1
=> ’1
I> (= ’1 ’1)
=> $T
I> (= ’1 ’2)
=> $F
I> (= 1 ’1)
=> $F
I> ↑$T; Booleans designate truth-values.
=> ’$T
I> (TYPE ↑$T)
=> ’BOOLEAN
I> ↑#3; Charats designate characters.
=> ’#3
I> (TYPE ↑#3)
=> ’CHARAT
I> ↑[1 2]; Rails designate sequences.
=> ’[1 2]
I> (TYPE ↑[1 2])
=> ’RAIL
I> ↑+; Closures designate functions.
=> ’<Closure for +>
I> (TYPE ↑+)
=> ’CLOSURE
I> ↑↑1; Handles designate other structures.
=> ’’1
I> (TYPE ↑↑1)
=> ’HANDLE
I> (TYPE ↑’A)
=> ’HANDLE
I> (TYPE ↑’(A . B))
=> ’HANDLE
9. vs
I> ’[1 2 3]
=> ’[1 2 3]
I> ↑[1 2 3]
=> ’[1 2 3]
I> ’[(+ 2 2) 4]; Do not confusewith ↑.
=> ’[(+ 2 2) 4]
I> ↑[(+ 2 2) 4]
=> ’[4 4]
I> ↑’3
=> ’’3
I> ’↑3
=> ’(UP 3)
10. Down ()
I> (DOWN ’1); DOWN is the inverse of UP.
=> 1
I>
’1; Down-arrow (‘’) abbreviates DOWN; we will always use
=> 1; this abbreviation
I> ’#J
=> #J
I> ’$T
=> $T
I> ’[1 2 $T]
=> [1 2 $T]
I> ’’A
=> ’A
I> 1
<ERROR: DOWN expects a structure not a number>
I> ’A
<ERROR: DOWN expects a normal-form structure>
I> ’(1 . 2)
<ERROR: DOWN expects a normal-form structure>
I> ’[A B]
<ERROR: DOWN expects a normal-form structure>
I> ’1; is shorthand for DOWN
=> 1
I> 1
=> ’(DOWN 1)
I> ↑1
=> 1
11. Pairs
I> (PCONS ’1 ’2)
=> ’(1 . 2)
I> ’(1 . 2)
=> ’(1 . 2)
I> (PCONS 1 2)
<ERROR: PCONS expects a structure, not a number>
I> (TYPE (PCONS ’A ’B))
=> ’PAIR
I> (PAIR ’(A . B))
=> $T
I> (PCONS ’+ ’[2 3])
=> ’(+ 2 3)
I> (CAR ’(A . B))
=> ’A
I> (CDR ’(A . B))
=> ’B
I> (CAR ’(+ 2 3))
=> ’+
I> (CDR ’(+ 2 3))
=> ’[2 3]
I> (= ’(1 . 2) ’(1 . 2))
=> $F
I> (= (PCONS ’A ’B) (PCONS ’A ’B))
=> $F
I> (LET [[X (PCONS ’A ’B)]] (= X X))
=> $T
12. Rails
I> (RCONS ’1 ’2 ’3)
=> ’[1 2 3]
I> (RCONS 1 2 3)
<ERROR: RCONS expects structures not a number>
I> (RCONS)
=> ’[]
I> (RCONS (RCONS) ’A ’B)
=> ’[[] A B]
I> (TYPE (RCONS))
=> ’RAIL
I> (RAIL ’[])
=> $T
I> (PCONS ’+ (RCONS ’2 ’3))
=> ’(+ 2 3)
I> (LENGTH ’[])
=> 0
I> (LENGTH ’[A B])
=> 2
I> (NTH 2 ’[A B])
=> ’B
I> (REST ’[A B])
=> ’[B]
I> (PREP ’A ’[B C])
=> ’[A B C]
I> (APPEND ’[A B] ’[C D])
=> ’[A B C D]
I> (= ’[1 2] ’[1 2])
=> $F
I> (= (RCONS ’1 ’2) (RCONS ’1 ’2))
=> $F
I> (LET [[X (RCONS ’1 ’2)]] (= X X))
=> $T
13. Sequences vs. Rails
I> (TYPE [1 2 3])
=> ’SEQUENCE
I> (TYPE ’[1 2 3])
=> ’RAIL
I> (RCONS ’1 ’2 ’3); RCONS always builds rails.
=> ’[1 2 3]
I> (RCONS 1 2 3)
<ERROR: RCONS expects a structure, not a number>
I> (SCONS ’1 ’2 ’3); SCONS always builds sequences.
=> [’1 ’2 ’3]
I> (SCONS 1 2 3)
=> [1 2 3]
I> (= [1 2 3] ’[1 2 3]); Sequences are not rails.
=> $F
I> (= [’1 ’2 ’3] ’[1 2 3])
=> $F
I> (= [1 2 3] ’[1 2 3])
=> $T
14. Replace
I> (SET X ’[1 2 3]); REPLACE is a general-purpose side-effecting operator
=> ’[1 2 3]; defined on rails, pairs, atoms, and closures.
I> (REPLACE (TAIL 2 X) ’[4 8 16])
=> ’[4 8 16]
I>
X
=>
’[1 2 4 8 16]
I> (SET Y ’[A B C]); Note that REPLACE’ing is defined on rails themselves,
=> ’[A B C]; not on their "rests" (as in regular LISPs): we can
I> (REPLACE Y X); therefore replace things at the top level.
=> ’[1 2 4 8 16]
I>
Y
=> ’[1 2 4 8 16]
I>(DEFINE RPLACA; We can define a standard RPLACA in terms of REPLACE
(LAMBDA EXPR [PAIR NEW-CAR]
(REPLACE PAIR (PCONS NEW-CAR (CDR PAIR)))))
=>
RPLACA
I>
(LET [[P1 (PCONS ’A ’B)]]
(BLOCK (RPLACA P1 ’C)
P1)))
=>
’(C . B)
I>(DEFINE RPLACD; Similarly, define RPLACD
(LAMBDA EXPR [PAIR NEW-CDR]
(REPLACE PAIR (PCONS (CAR PAIR) NEW-CDR))))
=>
RPLACD
I>(DEFINE RPLACN; RPLACN and RPLACT are element and tail versions
(LAMBDA EXPR [N RAIL NEW-ELEMENT]; for rails.
(REPLACE (TAIL (- N 1) RAIL)
(PREP NEW-ELEMENT (TAIL N RAIL)))))
=>
RPLACN
I>
(DEFINE RPLACT
(LAMBDA EXPR [N RAIL NEW-TAIL]
(REPLACE (TAIL N RAIL) NEW-TAIL)))
=>
RPLACT
I>(LET [[Z ’[THIS WAS A TEST]]]
(BLOCK (RPLACN 2 Z ’IS)
(RPLACT 4 Z ’[OF THE REPLACING FUNCTIONS])
Z))
=>
’[THIS IS A TEST OF THE REPLACING FUNCTIONS]
I>(LET [[X ’[]]
[Y ’[]]]
(BLOCK (RPLACT 0 X ’[NEW TAIL]); (RPLACT 0 ...) is the same as REPLACE
X))
=>
’[NEW TAIL]; Although we have smashed one null rail,
I>Y; another one was left alone.
=>’[]
I>(LET [[X ’[A B C D E]]]; You can replace atoms, as well as pairs and
(BLOCK (REPLACE ’A ’NEW-ATOM); rails and closures, but it is dangerous. Note
X))); here that not only is the rail X changed, but
=>’[NEW-ATOM B C D E]; the Z of the previous example — and indeed
I>Z; every occurence of A will be changed to an
=>’[THIS IS NEW-ATOM TEST OF THE REPLACING FUNCTIONS] ; occurence of NEW-ATOM.
15. Identity
I> xxx
=> xxx
I> xxx
=> xxx
16. Typing
I> (TYPE 3); TYPE has been illustrated in many of the previous sections.
=> ’NUMBER; It maps elements of the semantic domain onto their representative
I> (TYPE ’3); atoms. Instances of each of the 13 semantic types are given
=> ’NUMERAL; here.
I> (TYPE ’’3)
=> ’HANDLE
I> (TYPE ’HELLO)
=> ’ATOM
I> (TYPE LENGTH)
=> ’FUNCTION
I> (TYPE ’LENGTH)
=> ’ATOM
I> (TYPE ↑LENGTH)
=> ’CLOSURE
I> (TYPE $T)
=> ’TRUTH-VALUE
I> (TYPE ’$F)
=> ’BOOLEAN
I>
(TYPE ’(= 1 2))
=>
’PAIR
I>
(TYPE (= 1 2))
=>
’TRUTH-VALUE
I>
(TYPE ↑(= 1 2))
=>
’BOOLEAN
I> (TYPE #A)
=> ’CHARACTER
I> (TYPE (1ST "Hello out there"))
=> ’CHA
RAT
I> (TYPE [1 2 3])
=> ’SEQUENCE
I> (TYPE ’[$T $F])
=> ’RAIL
I>(ATOM ’A); As well as the primitive TYPE, there are 13 characteristic
=>$T; functions for each of the semantic types, each defined over the
I>(NUMBER 3); whole semantic domain.
=>$T
I>
(NUMBER ’3)
=>
$F
17. Closures
I> LENGTH; Closures are normal-form function designators, but
=> <CLOSURE for LENGTH>
; they are printed using only the escape notation.
I> (TYPE LENGTH)
=> ’FUNCTION
; You typically must use meta-structural access in order
I> (TYPE ↑LENGTH); to mention closures.
=> ’CLOSURE
I> (CENV ↑=); There are three selector functions defined on closures:
=> <GLOBAL ENVIRONMENT>
; CENV, PATTERN, and BODY.
I> (BODY ↑(LAMBDA EXPR [X] (+ X X))); The ingredients in a closure are internal structures.
=> ’(+ X X)
I>
(PATTERN ↑(LAMBDA EXPR [[X] Y] $T))
=>
’[[X] Y]
I> (LET [[X 3] [Y (+ 2 4)]]
(CENV ↑(LAMBDA EXPR [Y] (* X (+ Y Z)))))
=> [[’X ’3] [’Y ’6]
... GLOBAL-ENVIRONMENT]
I> (LET [[TEST (LAMBDA EXPR [Y] (+ Y Y))]]; One reason to access closures is to modify
(BLOCK (REPLACE (BODY ↑TEST) ’(* Y Y)); them.
(TEST 5)))
=> 25
I> (DEFINE ARITY; Another reason is to find out information
(LAMBDA EXPR [FUN]; about the functions they designate.
(LET [[PATTERN (PATTERN ↑FUN)]]
(IF (RAIL PATTERN)
(LENGTH PATTERN)
’INDEFINITE))))
=> ’ARITY
I>
(ARITY +)
=>
2
I>
(ARITY LAMBDA)
=>
3
I>
(ARITY SCONS)
=>’INDEFINITE
18. LET and LET*
I> (LET [[X 2]]; LET facilitates local l-binding. In particular,
(+ X 3)); (LET [[a1 v1] ... [ak vk] body) is entirely equivalent to
=> 5; ((LAMBDA EXPR [a1 ... ak] body) v1 ... vk).
I> (LET [[X 2]; All of the bindings of the LET variables are processed in
[Y 3]]; the enclosing environment; therefore (except for control
(LET [[X Y]; side effects) they could be processed in parallel.
[Y X]]
(+ X Y)))
=> 5
I> (LET [[X 2]; LET*, in contrast, processes the bindings v1 ... vk sequentially.
[Y 3]]; (LET* [[a1 v1] ... [ak vk] body) is entirely equivalent to
(LET* [[X Y]; ((LAMBDA EXPR [a1]
[Y X]]; ...
(+ X Y))); ((LAMBDA EXPR [ak] body) vk)
=> 6
; ...
; v1)
I>(LET [[[A B C] (REST [10 20 30 40])]]; LET and LET* support full pattern matching.
(+ B C))
=>
50
19. Conditionals
I> (IF (= 1 2) ’Worry ’Relax); IF is the primitive conditional; COND and SELECT(Q)
=> ’Relax
; are also standard.
I> (LABEL [[PARITY (LAMBDA EXPR [N]
(COND [(= N 0) ’EVEN]
[(= N 1) ’ODD)]
[$T (PARITY (- N 2))]))]]
(PARITY 123))
=> ’ODD
I>(SELECTQ (TYPE EXP); SELECTQ matches an internal structure against
[RAIL ’MAYBE]; a set of others, processing the set of ...
[[ATOM PAIR] ’NO];
[[CLOSURE CHARAT BOOLEAN NUMERAL HANDLE] ’YES])
20. Input/Output
I> xxx
=> xxx
I> xxx
=> xxx
21. Definitions and Recursion
I> xxx
=> xxx
I> xxx
=> xxx
22. SET
I> (SET X 3); SET is just like 1-LISP’s SETQ; note that, in order to be
=> 3; parellel to the other naming operators (LAMBDA and LET), the
I> X; variable name is not quoted (i.e., we don’t write (SET ’X 3)).
=> 3
; SET, therefore, like LAMBDA and LET, is an IMPR.
I>(DEFINE TEST; SET has a side-effect on variables: it reaches up through
(LAMBDA EXPR [X]; the enclosing environment and smashes the closest binding.
(BLOCK (TRY) X))); Note, however, that since 2-LISP is statically scoped, that
=>TEST; this does not mean that it will affect dynamically closer
I>(DEFINE TRY; contexts.
(LAMBDA EXPR [] (SET X 10)))
=>
TRY
I>
(TEST 4); (TEST 4) returns 4, because the call to TRY did not
=>4; affect the local context within the body of TEST.
I>X; However it will have affected the binding of X in the
=>10; globally enclosing environment.
I>(SET [A B] (REST [10 20 30])); For uniformity, SET will also support full patterns, although
=> [20 30]; this feature will rarely be used.
I> (+ A B)
=>
50
23. NORMALISE and REDUCE
I> (NORMALISE ’3); NORMALISE is defined over expressions, processing
=> ’3
; them in the context in which NORMALISE itself was called.
I> (NORMALISE ’(+ 1 2))
=> ’3
I> (LET [[X (= 1 2)]] (NORMALISE ’X))
=> ’$T
I> (LET [[X (= 1 2)]] (NORMALISE X))
<ERROR: NORMALISE is only defined over internal expressions>
I> (REDUCE ’= ’[2 3]); REDUCE is like NORMALISE but takes procedure and argument
=> ’$F
; expressions separately.
I> (LET [[Y 3] [Z 4]]; Unlike 1-LISP’s APPLY, REDUCE processes not only its own
(REDUCE ’+ (REST ’[X Y Z])); arguments (since REDUCE is of course extensional), but also
=> ’7
; the arguments to the procedure, just in case the procedure
I>
(REDUCE ’IF; is an EXPR.
[(= 1 2)
(PRINT "Yes")
(PRINT "No")]) No
=> ’$T
I> (DEFINE TRY; Because NORMALISE uses the default environment,
(LAMBDA IMPR [VAR] (NORMALISE VAR))); and because IMPRs don’t pass the environment
=> ’TRY
; of the call, NORMALISE cannot be used to process
I> (LET [[X 4]] (TRY X)); an argument that was not processed on calling
<ERROR: X unbound>
; This absurdity is overcome in 3-LISP.
24. Pattern Matching
I> (DEFINE SPREAD; Pattern matching variable binding protocol (used
(LAMBDA EXPR [A1 A2 A3]; uniformly by LAMBDA, LET, and SET) will destructure
[A1 A2 A3]))); the arguments sufficiently to match the pattern.
=> ’SPREAD
; Consequently, you can use a simple atom name as
I> (SPREAD 10 20 30); the pattern if you want a LEXPR/NO-SPREAD.
=> [10 20 30]
I> (DEFINE NO-SPREAD; Pattern matching is designed to honour the following
(LAMBDA EXPR ARGS; mandate: In the context that results from binding the
(LENGTH ARGS))); variables, the pattern expression should designate
=> ’NO-SPREAD
; what the arguments designated in the context of use.
I> (NO-SPREAD 2 4 6)
=> 3
I>(LET [[[[A B] [C D]] (REST [[1 2] [3 4] [5 6]])]]
(+ (* A C) (* B D))); An example of severe destructing.
=>
11
25. Macros and Backquote
I> (DEFINE NOP; MACROs bind their patterns to designators
(LAMBDA MACRO [EXP] EXP)); of expressions, and return an expression
=> ’NOP
; that is processed in place of the original
I> (+ 2 (NOP 3)); call to the MACRO.
=> 5
I> (DEFINE M1; The construction of expressions is greatly
(LAMBDA MACRO [EXP] ̀ [1 ,EXP 3])); facilitated by using backquote — an operator
=> ’M1
; like a quotation operator, except that each
I> (DEFINE M2; sub-expression preceded by a comma is
(LAMBDA MACRO [EXP] ̀ [1 ,↑EXP 3])); normalised, and the referent of that term
=> ’M2
; used at that position. Since the MACRO pattern
I> (M1 2); is bound to a designator of the argument
=> [1 2 3]
; expression, this is usually what is expected;
I> (M2 2); however an explicit up-arrow can be used if
=> [1 ’2 3]
; the result, rather than the referent, of the
I> (DEFINE INCREMENT; comma’ed expression is desired.
(LAMBDA MACRO [EXP]
̀ (+ 1 ,EXP)))
=> ’INCREMENT
I>
(INCREMENT 4)
=>
5
I> (LET [[X 2]] ̀ [1 ,X 3]); This fails because the referent of X — the
<ERROR: Backquote assembles structures>
; number two — is not a structure, and therefore
I> (LET [[X 2]] ̀ [1 ,↑X 3]); cannot be inserted into the rail. An explicit
=> [1 2 3]
; up-arrow is required.
I> (DEFINE INCREMENT; Using backquote is usually simpler than
(LAMBDA MACRO [EXP]; constructing the expression explicitly.
(PCONS ’+ (RCONS ’1 EXP))))
=> ’INCREMENT
26. Lambda Deferral
I> (PRINT "Hello") Hello; Since LAMBDA is an intensional, wrapping
=> $T
; an expression within the body of a LAMBDA
I> (LAMBDA EXPR ? (PRINT "Hello")); defers processing.
=> <CLOSURE
... >
I>(LET [[X (LAMBDA EXPR ? (PRINT "Hello"))]; The processing can always be susbsequently
[Y (PRINT "There")]]; obtained by reducing the closure with no
[(X) Y]) There Hello; arguments (note the ‘There’ is printed before
=>
[$T $T]; the ‘Hello’).
I>(DEFINE DELAY; We can therefore define DELAY and FORCE as
(LAMBDA MACRO [EXP]; MACROs (DELAY must be a MACRO, although
̀ (LAMBDA EXPR [] ,EXP))); FORCE could be an EXPR), to encapsulate these
=>
’DELAY; behaviours (these terms are due to Sussman).
I>
(DEFINE FORCE
(LAMBDA MACRO [EXP]
̀ (,EXP)))
=>
’FORCE
I> (LET [[A1 (PRINT "Now")]
[A2 (PRINT "is")]
[A3 (DELAY (PRINT "the"))]
[A4 (PRINT "Time")]]
[A1 A2 (FORCE A3) A4]) Now is Time the
=> [$T $T $T $T]
I> (DEFINE NEW-IF; With FORCEand DELAY one can define an
(LAMBDA MACRO [PREMISE C1 C2]; normal-order conditional NEW-IF out of an
̀ (FORCE (EF ,PREMISE; applicative-order conditional EF.
(DELAY ,C1)
(DELAY ,C2)))))
=> ’NEW-IF
I> (EF (= 1 2) (Print "Yes") (Print "No)) Yes No
=> $T
I> (NEW-IF (= 1 2) (Print "Yes") (Print "No)) No
=> $T
27. Continuation-passing Style
I> xxx
=> xxx
I> xxx
=> xxx
28. Higher-order Functions
I> xxx
=> xxx
I> xxx
=> xxx
29. Intensional Consequence
I> xxx
=> xxx
I> xxx
=> xxx
30. Complex Booleans
I> xxx
=> xxx
I> xxx
=> xxx
31. Non-spread Arguments
I> xxx
=> xxx
I> xxx
=> xxx
32. Y Operators
I> xxx
=> xxx
I> xxx
=> xxx
33. BLOCK
I> (BLOCK 1 2 3); BLOCK, like 1-LISP’s PROG, designates and returns the
=> 3
; designation and result, respectively, of its last argument.
I> (BLOCK (TERPRI); It is used in order to sequence side-effect operations (its
(PRINT "Hello"); arguments are processed in order); furthermore, it is
(PRINT "there"); considered good programming practice to use side-effect
’OK); primitives (like REPLACE and SET) only within the scope of
Hello there
; a BLOCK.
=> ’OK
I>(COND [(= 1 2) (PRINT "Bad") $T]; COND (and LET and LAMBDA and SELECT and so forth)
[(= 1 1) (PRINT "OK") $T]); do not have implicit BLOCK bodies; you must use
<ERROR: Bad pattern match in COND>
; BLOCK explicitly.
I>(COND [(= 1 2) (BLOCK (PRINT "Bad") $T)]
[(= 1 1) (BLOCK (PRINT "OK") $T)]) OK
=>
$T