-
Notifications
You must be signed in to change notification settings - Fork 0
/
pair.py
94 lines (75 loc) · 2.48 KB
/
pair.py
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class Pair:
"""Python data structure for Scheme input: first and rest. rest must be a Pair or nil
>>> s = Pair(1, Pair(2, nil))
>>> s
Pair(1, Pair(2, nil))
>>> print(s)
(1 2)
>>> print(s.map(lambda x: x+4))
(5 6)
"""
def __init__(self, first, rest):
self.first = first
self.rest = rest
def __repr__(self):
return 'Pair({0}, {1})'.format(repr(self.first), repr(self.rest))
def __str__(self):
s = '(' + repl_str(self.first)
rest = self.rest
while isinstance(rest, Pair):
s += ' ' + repl_str(rest.first)
rest = rest.rest
if rest is not nil:
s += ' . ' + repl_str(rest)
return s + ')'
def __len__(self):
n, rest = 1, self.rest
while isinstance(rest, Pair):
n += 1
rest = rest.rest
if rest is not nil:
raise TypeError('length attempted on improper list')
return n
def __eq__(self, p):
if not isinstance(p, Pair):
return False
return self.first == p.first and self.rest == p.rest
def map(self, fn):
"""Return a Scheme list after mapping Python function FN to SELF."""
mapped = fn(self.first)
if self.rest is nil or isinstance(self.rest, Pair):
return Pair(mapped, self.rest.map(fn))
else:
raise TypeError('ill-formed list (cdr is a promise)')
def flatmap(self, fn):
"""Return a Scheme list after flatmapping Python function FN to SELF."""
from scheme_builtins import scheme_append
mapped = fn(self.first)
if self.rest is nil or isinstance(self.rest, Pair):
return scheme_append(mapped, self.rest.flatmap(fn))
else:
raise TypeError('ill-formed list (cdr is a promise)')
class nil:
"""The empty list"""
def __repr__(self):
return 'nil'
def __str__(self):
return '()'
def __len__(self):
return 0
def map(self, fn):
return self
def flatmap(self, fn):
return self
nil = nil() # Assignment hides the nil class; there is only one instance
def repl_str(val):
"""Should largely match str(val), except for booleans and undefined."""
if val is True:
return "#t"
if val is False:
return "#f"
if val is None:
return "undefined"
if isinstance(val, str) and val and val[0] == "\"":
return "\"" + repr(val[1:-1])[1:-1] + "\""
return str(val)