File Coverage

blib/lib/fp/lambda.pm
Criterion Covered Total %
statement 118 118 100.0
branch n/a
condition n/a
subroutine 50 56 89.2
pod n/a
total 168 174 96.5


line stmt bran cond sub pod time code
1              
2             package fp::lambda;
3              
4 4     4   3615 use strict;
  4         7  
  4         152  
5 4     4   21 use warnings;
  4         8  
  4         308  
6              
7             our $VERSION = '0.01';
8              
9             BEGIN {
10 4     4   2736 require fp;
11 4         7533 *import = \&fp::import;
12             }
13              
14             ## Church Booleans
15              
16             # TRUE := λ x. λ y. x
17             *TRUE = sub {
18 455     455   511 my $x = shift;
19 455     455   1401 sub { $x }
20 455         1493 };
21              
22             # FALSE := λ x. λ y. x
23             *FALSE = sub {
24 1515     1515   1605 my $x = shift;
25 1515     1515   3751 sub { shift }
26 1515         5046 };
27              
28             # AND := λ p. λ q. p q FALSE
29             *AND = sub {
30 49     49   534 my $p = shift;
31             sub {
32 49     49   62 my $q = shift;
33 49         94 $p->($q)->(\&FALSE);
34             }
35 49         204 };
36              
37             # OR := λ p. λ q. p TRUE q
38             *OR = sub {
39 2     2   5 my $p = shift;
40             sub {
41 2     2   9 my $q = shift;
42 2         8 $p->(\&TRUE)->($q);
43             }
44 2         13 };
45              
46             # NOT := λ p. p FALSE TRUE
47             *NOT = sub {
48 25     25   28 my $p = shift;
49 25         54 $p->(\&FALSE)->(\&TRUE);
50             };
51              
52             # cond := λ p. λ x. λ y. p x y
53             *cond = sub {
54 138     138   166 my $p = shift;
55             sub {
56 138     138   161 my $x = shift;
57             sub {
58 138         159 my $y = shift;
59 138         218 $p->($x)->($y);
60             }
61 138         549 }
62 138         494 };
63              
64             ## Church Numeral
65              
66             # 0 := λ f. λ x. x
67             *zero = sub {
68 1012     1012   1104 my $f = shift;
69 1012     1012   2013 sub { shift }
70 1012         3333 };
71              
72             # succ := λ n. λ f. λ x. f (n f x)
73             *succ = sub {
74 53     53   68 my $n = shift;
75             sub {
76 1230     1230   1411 my $f = shift;
77             sub {
78 1230     1230   1378 my $x = shift;
79 1230         1831 $f->( $n->($f)->($x) )
80             }
81 1230         4322 }
82 53         221 };
83              
84             # pred := λ m. first (m (λ p. pair (second p) (plus one (second p))) (pair zero zero))
85             *pred = sub {
86 198     198   218 my $m = shift;
87             sub {
88             first($m->(sub {
89 564         650 my $p = shift;
90 564         941 pair(second($p))->(plus(\&one)->(second($p)))
91 198     198   397 })->(pair(\&zero)->(\&zero)))
92 198         740 }->()
93             };
94              
95             # plus := λ m. λ n. λ f. λ x. m f (n f x)
96             *plus = sub {
97 579     579   656 my $m = shift;
98             sub {
99 602     602   680 my $n = shift;
100             sub {
101 559         610 my $f = shift;
102             sub {
103 559         665 my $x = shift;
104 559         896 $m->( $f )->( $n->($f)->($x) )
105             }
106 559         1937 }
107 602         2130 }
108 579         1901 };
109              
110             # subtract := λ m. λ n. n pred m
111             *subtract = sub {
112 3     3   6 my $m = shift;
113             sub {
114 3     3   5 my $n = shift;
115 3         8 $n->(\&pred)->($m);
116             }
117 3         16 };
118              
119             # multiply := λ m. λ n. m (plus n) zero
120             *multiply = sub {
121 7     7   26 my $m = shift;
122             sub {
123 7     7   10 my $n = shift;
124 7         21 $m->(plus($n))->(\&zero);
125             }
126 7         34 };
127              
128             # now make 1 .. 10
129              
130             *one = succ(\&zero);
131             *two = succ(\&one);
132             *three = succ(\&two);
133             *four = succ(\&three);
134             *five = succ(\&four);
135             *six = succ(\&five);
136             *seven = succ(\&six);
137             *eight = succ(\&seven);
138             *nine = succ(\&eight);
139             *ten = succ(\&nine);
140              
141             ## Predicates
142              
143             # is_zero := λ n. n (λ x. FALSE) TRUE
144             *is_zero = sub {
145 100     100   638 my $n = shift;
146 100     72   324 $n->(sub { \&FALSE })->(\&TRUE);
  72         182  
147             };
148              
149             # is_equal := λ m. λ n. and (is_zero (m pred n)) (is_zero (n pred m))
150             *is_equal = sub {
151 48     48   61 my $m = shift;
152             sub {
153 48     48   56 my $n = shift;
154 48         98 AND(
155             is_zero($m->(\&pred)->($n))
156             )->(
157             is_zero($n->(\&pred)->($m))
158             )
159             }
160 48         193 };
161              
162             ## Data Structures
163              
164             ## Pairs
165              
166             # pair := λ f. λ s. λ b. b f s
167             *pair = sub {
168 860     860   1835 my $f = shift;
169             sub {
170 860     860   981 my $s = shift;
171             sub {
172 1754     1754   1941 my $b = shift;
173 1754         2838 $b->($f)->($s);
174             }
175 860         3607 }
176 860         2864 };
177              
178             # first := λ p p TRUE
179             *first = sub {
180 357     357   441 my $p = shift;
181 357         656 $p->(\&TRUE)
182             };
183              
184             # second := λ p p FALSE
185             *second = sub {
186 1401     1401   1553 my $p = shift;
187 1401         2518 $p->(\&FALSE)
188             };
189              
190             # List functions
191              
192             # NIL := pair TRUE TRUE
193             *NIL = pair(\&TRUE)->(\&TRUE);
194              
195             # cons := λ h. λ t. pair FALSE (pair h t)
196             *cons = sub {
197 45     45   667 my $h = shift;
198             sub {
199 45     45   58 my $t = shift;
200 45         80 pair(\&FALSE)->(pair($h)->($t));
201             }
202 45         240 };
203              
204             # head := λ z. first (second z)
205             *head = sub {
206 59     59   366 my $z = shift;
207 59         98 first(second($z));
208             };
209              
210             # tail := λ z. second (second z)
211             *tail = sub {
212 106     106   159 my $z = shift;
213 106         165 second(second($z));
214             };
215              
216             # is_NIL := first
217             *is_NIL = \&first;
218              
219             # is_not_NIL := λ x. NOT is_NIL
220             *is_not_NIL = sub {
221 25     25   32 my $x = shift;
222 25         41 NOT(is_NIL($x))
223             };
224              
225             # size := λ l. cond (is_not_NIL l) (λ x. succ (size (tail l))) (λ l. zero)
226             *size = sub {
227 12     12   18 my $l = shift;
228             cond(is_not_NIL($l))->(
229             # have to wrap this to get lazy evaluation
230 9     0   16 sub { succ(size(tail($l))) }
231             )->(
232 3     0   15 sub { \&zero }
233 12         62 )->();
234             };
235              
236             # sum := λ l. cond (is_not_NIL l) (λ x. plus (head l) (sum (tail l))) (λ l. zero)
237             *sum = sub {
238 6     6   9 my $l = shift;
239             cond(is_not_NIL($l))->(
240 5     0   11 sub { plus(head($l))->(sum(tail($l))) }
241             )->(
242 1     0   5 sub { \&zero }
243 6         31 )->()
244             };
245              
246             # append := λ l1. λ l2. cond (is_NIL l1) (l2) (cons (head l1) (append (tail l1) l2))
247             *append = sub {
248 20     20   24 my $l1 = shift;
249             sub {
250 20     20   23 my $l2 = shift;
251             cond(is_NIL($l1))->(
252 7         18 sub { $l2 }
253             )->(
254 13         29 sub { cons(head($l1))->(append(tail($l1))->($l2)) }
255 20         109 )->();
256             }
257 20         108 };
258              
259             # rev := λ l. cond (is_not_NIL) (NIL) (append rev(tail l) cons((head l) NIL))
260             *rev = sub {
261 6     6   10 my $l = shift;
262             cond(is_not_NIL($l))->(
263 5     0   13 sub { append(rev(tail($l)))->(cons(head($l))->(\&NIL)) }
264             )->(
265 1     0   5 sub { \&NIL }
266 6         35 )->()
267             };
268              
269              
270             # nth := λ n. λ l. cond (is_NIL l) (NIL) (cond (is_equal n zero) (head l) (nth (pred n)) (tail l)) )
271             *nth = sub {
272 42     42   153 my $n = shift;
273             sub {
274 42     42   53 my $l = shift;
275             cond(is_NIL($l))->(
276 2         11 sub { \&NIL }
277             )->(
278             cond(is_equal($n)->(\&zero))->(
279 10         20 sub { head($l) }
280             )->(
281 30         48 sub { nth(pred($n))->(tail($l)) }
282             )
283 42         203 )->()
284             }
285 42         198 };
286              
287             # apply := λ f. λ l. cond (is_NIL l) (NIL) (cons (f (head l)) (apply f (tail l)))
288             *apply = sub {
289 6     6   13 my $f = shift;
290             sub {
291 6     6   10 my $l = shift;
292             cond(is_NIL($l))->(
293 1         6 sub { \&NIL }
294             )->(
295 5         10 sub { cons($f->(head($l)))->(apply($f)->(tail($l))) }
296 6         43 )->()
297             }
298 6         74 };
299              
300             1;
301              
302             __END__