1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# Lab 9 optional exercise #5
 
# cons pairs AND the empty list will be implemented as one-argument
# lambdas (closures). There are 3 special arguments (messages):
# the ISCONS argument returns true/false depending on whether the
# closure actually represents a cons pair or "null",
# the GETCAR argument returns the car of a pair, and GETCDR
# returns the cdr of a pair.
# These special argument names are defined as global variables
# so they can be easily referenced.
 
new ISCONS := 1000;
new GETCAR := 2001;
new GETCDR := 2002;
 
# null is a function that just returns the fact that it's not
# a cons pair!
 
new null := lambda msg {
  ifelse msg = ISCONS 
    { ret := false; }
    { "ERROR: illegal argument to null" }
};
 
# cons is a curried 2-argument function that returns a lambda
# for the pair.
new cons := lambda a {
  ret := lambda b {
    # Now we have the 2 parts of the cons, a and b.
    # Time to return a lambda which will retrieve them.
    ret := lambda msg {
      ifelse msg = ISCONS { ret := true; }
      { ifelse msg = GETCAR { ret := a; }
        { ifelse msg = GETCDR { ret := b; }
          { "ERROR: illegal message to cons pair" }}}
    };
  };
};
 
# shortcut methods for coar and cdr
new car := lambda P { ret := P@GETCAR; };
new cdr := lambda P { ret := P@GETCDR; };
 
# predicate to test whether something is a cons pair or null
new is_cons := lambda P { ret := P@ISCONS; };
 
# Now we can do something with these: let's make a list
new L1 := cons@1 @ (cons@2 @ (cons@3 @ (cons@4@null) ) );
 
write car@L1; # prints 1
write car@(cdr@L1); # prints 2
 
# Function to sum the numbers in a list
new sum := lambda L {
  ifelse is_cons@L 
    { ret := car@L + sum@(cdr@L); }
    { ret := 0; }
};
 
write sum@L1; # prints 1+2+3+4 = 10