-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathlambda.js
More file actions
211 lines (159 loc) · 5.96 KB
/
lambda.js
File metadata and controls
211 lines (159 loc) · 5.96 KB
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Arithmetics -----------------------------------------------------------------
IDENTITY = x => x
SUCCESSOR = n => f => x => f(n(f)(x))
PREDECESSOR = n => f => x => n(g => h => h(g(f)))(_ => x)(u => u)
ADDITION = m => n => n(SUCCESSOR)(m)
SUBTRACTION = m => n => n(PREDECESSOR)(m)
MULTIPLICATION = m => n => f => m(n(f))
POWER = x => y => y(x)
ABS_DIFFERENCE = x => y => ADDITION(SUBTRACTION(x)(y))(SUBTRACTION(y)(x))
// Logic -----------------------------------------------------------------------
TRUE = t => f => t
FALSE = t => f => f
AND = p => q => p(q)(p)
OR = p => q => p(p)(q)
XOR = p => q => p(NOT(q))(q)
NOT = c => c(FALSE)(TRUE)
IF = c => t => f => c(t)(f)
// Comparison ------------------------------------------------------------------
IS_ZERO = n => n(_ => FALSE)(TRUE)
IS_LESS_THAN = m => n => NOT(IS_LESS_THAN_EQUAL(n)(m))
IS_LESS_THAN_EQUAL = m => n => IS_ZERO(SUBTRACTION(m)(n))
IS_EQUAL = m => n => AND(IS_LESS_THAN_EQUAL(m)(n))(IS_LESS_THAN_EQUAL(n)(m))
IS_NOT_EQUAL = m => n => OR(NOT(IS_LESS_THAN_EQUAL(m)(n)))(NOT(IS_LESS_THAN_EQUAL(n)(m)))
IS_GREATER_THAN_EQUAL = m => n => IS_LESS_THAN_EQUAL(n)(m)
IS_GREATER_THAN = m => n => NOT(IS_LESS_THAN_EQUAL(m)(n))
IS_NULL = p => p(x => y => FALSE)
NIL = x => TRUE
// Combinators -----------------------------------------------------------------
Y = f => (x => f(y => (x(x))(y)))(x => f(y => (x(x))(y)))
// Lists -----------------------------------------------------------------------
CONS = x => y => f => f(x)(y)
CAR = p => p(TRUE)
CDR = p => p(FALSE)
RANGE = m => n => Y(f => m => IF(IS_EQUAL(m)(n))
(_ => CONS(m)(NIL))
(_ => CONS(m)(f(SUCCESSOR(m))))
())(m)
MAP = x => g => Y(f => x => IF(IS_NULL(x))
(_ => x)
(_ => CONS(g(CAR(x)))(f(CDR(x))))
())(x)
// Test "Framework" ------------------------------------------------------------
ASSERT = truth => IF(truth)
(description => `[\x1b[32m✓\x1b[0m] ${description}`)
(description => `[\x1b[31m✗\x1b[0m] ${description}`)
REFUTE = truth => ASSERT(NOT(truth))
TEST = description => assertion => console.log(assertion(description))
// Church Numerals -------------------------------------------------------------
$zero = f => IDENTITY
$one = SUCCESSOR($zero)
$two = SUCCESSOR($one)
$three = SUCCESSOR($two)
$four = MULTIPLICATION($two)($two)
$five = SUCCESSOR($four)
$eight = MULTIPLICATION($two)($four)
$nine = SUCCESSOR($eight)
$ten = MULTIPLICATION($two)($five)
// Tests -----------------------------------------------------------------------
TEST('TRUE')
(ASSERT(TRUE))
TEST('FALSE')
(REFUTE(FALSE))
TEST('AND')
(ASSERT(AND(TRUE)(TRUE)))
TEST('OR')(ASSERT(AND
(AND(OR(TRUE)(FALSE))(OR(FALSE)(TRUE)))
(NOT(OR(FALSE)(FALSE)))))
TEST('XOR')(ASSERT(AND
(AND(XOR(TRUE)(FALSE))(XOR(FALSE)(TRUE)))
(NOT(XOR(TRUE)(TRUE)))))
TEST('NOT')
(REFUTE(NOT(TRUE)))
TEST('IF')(ASSERT(AND
(IF(TRUE)(TRUE)(FALSE))
(NOT(IF(FALSE)(TRUE)(FALSE)))))
TEST('IDENTITY')
(ASSERT(IS_EQUAL(IDENTITY)(x => x)))
TEST('SUCCESSOR')
(ASSERT(IS_EQUAL(SUCCESSOR($zero))($one)))
TEST('PREDECESSOR')
(ASSERT(IS_EQUAL($zero)(PREDECESSOR($one))))
TEST('ADDITION')
(ASSERT(IS_EQUAL(SUCCESSOR($one))(ADDITION($one)($one))))
TEST('SUBTRACTION')
(ASSERT(IS_EQUAL($zero)(SUBTRACTION($one)($one))))
TEST('MULTIPLICATION')
(ASSERT(IS_EQUAL($four)(MULTIPLICATION($two)($two))))
TEST('POWER')(ASSERT(AND
(IS_EQUAL($nine)(POWER($three)($two)))
(IS_EQUAL($eight)(POWER($two)($three)))))
TEST('ABS_DIFFERENCE')(ASSERT(AND
(IS_EQUAL($one)(ABS_DIFFERENCE($three)($two)))
(IS_EQUAL($one)(ABS_DIFFERENCE($two)($three)))))
TEST('IS_ZERO')
(ASSERT(IS_ZERO($zero)))
TEST('IS_LESS_THAN')
(ASSERT(IS_LESS_THAN($zero)($one)))
TEST('IS_LESS_THAN_EQUAL')(ASSERT(AND
(IS_LESS_THAN_EQUAL($one)($one))
(IS_LESS_THAN_EQUAL($zero)($one))))
TEST('IS_EQUAL')(ASSERT(AND
(IS_EQUAL($zero)($zero))
(IS_EQUAL($one)($one))))
TEST('IS_NOT_EQUAL')
(ASSERT(IS_NOT_EQUAL($zero)($one)))
TEST('IS_GREATER_THAN_EQUAL')(ASSERT(AND
(IS_GREATER_THAN_EQUAL($one)($one))
(IS_GREATER_THAN_EQUAL($one)($zero))))
TEST('IS_GREATER_THAN')
(ASSERT(IS_GREATER_THAN($one)($zero)))
TEST('IS_NULL')
(ASSERT(IS_NULL(NIL)))
TEST('CAR')(ASSERT(AND
(IS_EQUAL(CAR(CONS($five)($one)))($five))
(IS_EQUAL(CAR(CONS($two)(CONS($one)($three))))($two))))
TEST('CDR')(ASSERT(AND
(IS_EQUAL(CDR(CONS($five)($one)))($one))
(IS_EQUAL(CAR(CDR(CONS($two)(CONS($one)($three)))))($one))))
TEST('CONS')(ASSERT(AND
(IS_EQUAL(CDR(CDR(CONS($two)(CONS($one)($three)))))($three))
(IS_EQUAL(CAR(CDR(CONS($five)(CONS($two)(CONS($one)($three))))))($two))))
TEST('RANGE')(ASSERT(AND(
AND
(IS_EQUAL(CAR(RANGE($three)($five)))($three))
(IS_EQUAL(CAR(CDR(RANGE($three)($five))))($four)))(
AND
(IS_EQUAL(CAR(CDR(CDR(RANGE($three)($five)))))($five))
(IS_NULL(CDR(CDR(CDR(RANGE($three)($five)))))))))
TEST('MAP')(ASSERT(AND(
AND
(IS_EQUAL
(CAR(MAP(RANGE($three)($five))(v => POWER(v)($two))))
(POWER($three)($two)))
(IS_EQUAL
(CAR(CDR(MAP(RANGE($three)($five))(v => POWER(v)($two)))))
(POWER($four)($two))))(
AND
(IS_EQUAL
(CAR(CDR(CDR(MAP(RANGE($three)($five))(v => POWER(v)($two))))))
(POWER($five)($two)))
(IS_NULL(CDR(CDR(CDR(MAP(RANGE($three)($five))(v => POWER(v)($two))))))))))
// Examples --------------------------------------------------------------------
console.log('\n--- Examples ---\n')
FACTORIAL = Y(f => n => IF(IS_ZERO(n))
(_ => SUCCESSOR(n))
(_ => MULTIPLICATION(n)(f(PREDECESSOR(n))))
())
FIBONACCI = Y(f => n => IF(IS_LESS_THAN_EQUAL(n)(SUCCESSOR(f => IDENTITY)))
(_ => n)
(_ => ADDITION
(f(PREDECESSOR(n)))
(f(PREDECESSOR(PREDECESSOR(n)))))
())
TEST('FACTORIAL: 5! = 120')(ASSERT(IS_EQUAL
(FACTORIAL($five))
(ADDITION(MULTIPLICATION($ten)($ten))(ADDITION($ten)($ten)))))
TEST('FIBONACCI: 10 = 55')(ASSERT(IS_EQUAL
(FIBONACCI($ten))
(ADDITION(MULTIPLICATION($five)($ten))($five))))