Skip to content

Commit 6d6842e

Browse files
author
Johan Wiltink
committed
add scott-list reference implementation and testing
1 parent f969066 commit 6d6842e

File tree

3 files changed

+273
-0
lines changed

3 files changed

+273
-0
lines changed

tests/run-tests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const examples = [ "basics-binary-scott"
1010
, "is-prime"
1111
, "is-prime-scott"
1212
, "prime-sieve"
13+
, "scott-lists"
1314
, "multiply"
1415
];
1516

tests/scott-lists/solution.txt

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# scott-lists.lc
2+
3+
#import combinators.lc
4+
B = \ f g x . f (g x)
5+
BB = \ f g x y . f (g x y)
6+
CB = \ f g x . g (f x)
7+
C = \ f x y . f y x
8+
I = \ x . x
9+
K = \ x _ . x
10+
KI = \ _ x . x
11+
KK = \ x _ _ . x
12+
M = \ x . x x
13+
S = \ f g x . f x (g x)
14+
T = \ x fn . fn x
15+
V = \ x y fn . fn x y
16+
W = \ f x . f x x
17+
#import scott-booleans.ls
18+
False = K
19+
True = KI
20+
not = \ p . p True False
21+
and = M
22+
or = W C
23+
#import scott-ordering.lc
24+
LT = KK
25+
EQ = K K
26+
GT = K KI
27+
#import scott-numbers.lc
28+
zero = K
29+
succ = \ n . \ _zero succ . succ n
30+
pred = \ n . n zero I
31+
add = \ m n . m n (B succ (add n))
32+
sub = \ m n . m m (B (n m) sub)
33+
mul = \ m n . m m (B (add n) (mul n))
34+
is-zero = \ n . n True (K False)
35+
one = succ zero
36+
#import scott-pair.lc
37+
Pair = V
38+
fst = T K
39+
snd = T KI
40+
first = \ fn xy . xy \ x . Pair (fn x)
41+
second = \ fn xy . xy \ x y . Pair x (fn y)
42+
both = \ fn xy . xy \ x y . Pair (fn x) (fn y)
43+
bimap = \ f g xy . xy \ x y . Pair (f x) (g y)
44+
curry fn x y = fn (Pair x y)
45+
uncurry = T
46+
#import scott-option.lc
47+
None = K # = zero
48+
Some = \ x . \ _none some . some x # = succ
49+
option = V
50+
is-none = \ x . x True (K False) # = is-zero
51+
is-some = \ x . x False (K True)
52+
from-option = \ z x . x z I
53+
from-some = \ x . x () I
54+
list-to-option = \ xs . xs None \ x _xs . Some x
55+
option-to-list = \ x . x nil singleton
56+
map-option = \ fn xs . xs nil \ x xs . fn x (map-options fn xs) (C cons (map-options fn xs))
57+
cat-options = map-options I
58+
59+
# data List a = Nil | Cons a (List a)
60+
61+
# nil :: List a
62+
nil = K
63+
64+
# cons :: a -> List a -> List a
65+
cons = \ x xs . \ _nil cons . cons x xs
66+
67+
# singleton :: a -> List a
68+
singleton = \ x . cons x nil
69+
70+
# foldr :: (a -> z -> z) -> z -> List a -> z
71+
foldr = \ fn z xs . xs z ( \ x xs . fn x (foldr fn z xs) )
72+
73+
# null :: List a -> Boolean
74+
null = \ xs . xs True (KK False)
75+
76+
# take :: Number -> List a -> List a
77+
take = \ n xs . is-zero n (xs nil \ x xs . cons x (take (pred n) xs)) nil
78+
79+
# append :: List a -> List a -> List a
80+
append = C (foldr cons)
81+
82+
# concat :: List (List a) -> List a
83+
concat = \ xss . foldr xss append nil
84+
85+
# sum,product :: List Number -> Number
86+
sum = foldr add zero
87+
product = foldr mul one
88+
89+
# iterate :: (a -> a) -> a -> List a
90+
iterate = \ fn x . cons x (iterate fn (fn x))
91+
92+
# repeat :: a -> List a
93+
repeat = \ x . cons x (repeat x) # repeat = Y (S cons)
94+
95+
# cycle :: List a -> List a
96+
cycle = \ xs . null xs (concat (repeat xs)) ()
97+
98+
# replicate :: Number -> a -> List a
99+
replicate = \ n . B (take n) repeat
100+
101+
# head :: List a -> a
102+
head = \ xs . xs () K
103+
104+
# tail :: List a -> List a
105+
tail = \ xs . xs () KI
106+
107+
# length :: List a -> Number
108+
length = foldr (K succ) zero
109+
110+
# snoc :: List a -> a -> List a
111+
snoc = C (B (foldr cons) singleton)
112+
113+
# map :: (a -> b) -> List a -> List b
114+
map = \ fn . foldr (B cons fn) nil
115+
116+
# concat-map :: (a -> List b) -> List a -> List b
117+
concat-map = BB concat map
118+
119+
# filter :: () -> List a -> List a
120+
filter = \ p . foldr ( \ x z . p x z (cons x z) ) nil
121+
filter = \ p . foldr ( \ x . S (p x) (cons x) ) nil
122+
filter = \ p . foldr (S (B S p) cons) nil
123+
124+
# drop :: Number -> List a -> List a
125+
drop = \ n xs . is-zero n ( \ _x xs . drop (pred n) xs ) xs
126+
drop = \ n . is-zero n (K (drop (pred n)))
127+
128+
# split-at :: Number -> List a -> Pair (List a) (List a)
129+
split-at = \ i xs . is-zero i (xs (Pair nil nil) \ x xs . first (cons x) (split-at (pred i) xs)) (Pair nil xs)
130+
131+
# get :: Number -> List a -> a
132+
get = \ i xs . is-zero i ( \ x xs . xs () (get (pred i) xs) ) (head xs)
133+
134+
# set :: Number -> a -> List a -> List a
135+
set = \ i x xs . uncurry append (second (B (cons x) tail) (split-at i xs))
136+
set = \ i x xs . is-zero i (xs nil \ y ys . cons y (set (pred i) x ys)) (xs nil (K (cons x)))
137+
138+
# any :: (a -> Boolean) -> List a -> Boolean
139+
any = \ p . foldr (B or p) False
140+
141+
# all :: (a -> Boolean) -> List a -> Boolean
142+
all = \ p . foldr (B and p) True
143+
144+
# find :: (a -> Boolean) -> List a -> Option a
145+
find = \ p . foldr ( \ x z . p x z (Some x) ) None
146+
147+
# find-index :: (a -> Boolean) -> List a -> Option Number
148+
find-index p = B list-to-option (find-indices p)
149+
150+
# find-indices :: (a -> Boolean) -> List a -> List Number
151+
find-indices p = foldr ( \ x k i . p x I (cons i) (k (succ i)) ) (K nil) zero
152+
153+
# partition :: (a -> Boolean) -> List a -> Pair (List a) (List a)
154+
partition = \ p . foldr ( \ x . p x second first (cons x) ) (Pair nil nil)
155+
156+
# span :: (a -> Boolean) -> List a -> Pair (List a) (List a)
157+
span = \ p xs . xs (Pair nil nil) \ y ys . p y (Pair nil xs) (first (cons y) (span p ys))
158+
159+
# minimum-by :: (a -> a -> Boolean) -> List a -> a # cmp ~ le
160+
minimum-by = \ cmp xs . xs () (foldr \ x z . cmp x z z x)
161+
162+
# maximum-by :: (a -> a -> Boolean) -> List a -> a # cmp ~ le
163+
maximum-by = \ cmp xs . xs () (foldr \ x z . cmp x z x z)
164+
165+
# insert-by :: (a-> a -> Boolean) -> a -> List a -> List a # cmp ~ le
166+
insert-by = \ cmp x xs . uncurry append (second (cons x) (span (C cmp x) xs))
167+
168+
# sort-by :: (a -> a -> Boolean) -> List a -> List a # cmp ~ le
169+
sort-by = \ cmp . foldr (insert-by cmp) nil
170+
171+
# foldl :: (z -> a -> z) -> z -> List a -> z
172+
foldl = \ fn z xs . xs z (B (foldl fn) (fn z))
173+
174+
# scanl :: (z -> a -> z) -> z -> List a -> List z
175+
scanl = \ fn z xs . cons z (xs nil (B (scanl fn) (fn z)))
176+
177+
# scanr :: (a -> z -> z) -> z -> List a -> List z
178+
scanr = \ fn z xs . xs (singleton z) \ x xs . ( \ zs . zs \ z _zs . cons (fn x z) zs ) (scanr fn z xs)
179+
180+
# reverse :: List a -> List a
181+
reverse = foldl (C cons) nil
182+
183+
# init :: List a -> List a
184+
init = \ xs . xs () (S (zip-with K) tail xs)
185+
186+
# last :: List a -> a
187+
last = foldl KI ()
188+
189+
# unzip :: List (Pair a b) -> Pair (List a) (List b)
190+
unzip = foldr ( \ xy xys . xy \ x y . bimap (cons x) (cons y) xys ) (Pair nil nil)
191+
unzip = foldr (CB \ x y . bimap (cons x) (cons y)) (Pair nil nil)
192+
193+
# zip-with :: (a -> b -> z) -> List a -> List b -> List z
194+
zip-with = \ fn xs ys . xs nil \ x xs . ys nil \ y ys . cons (fn x y) (zip-with fn xs ys)
195+
196+
# zip :: List a -> List b -> List (Pair a b)
197+
zip = zip-with Pair
198+
199+
# slice :: Number -> Number -> List a -> List a
200+
slice = \ i j xs . gt j i nil (take (sub j i) (drop i xs))
201+
202+
# uncons :: List a -> Option (Pair (a) (List a))
203+
uncons = \ xs . xs None (B Some Pair)
204+
205+
# transpose :: List (List a) -> List (List a)
206+
transpose = \ xss . xss nil
207+
\ ys yss . ys (transpose yss)
208+
(unzip (map-option uncons xss) \ xs xxs . cons xs (transpose xss))
209+
210+
# unfold :: (a -> Option (Pair z a)) -> a -> List z
211+
unfold = \ fn x . fn x nil (T \ z x . cons z (unfold fn x))
212+
213+
# take-while :: (a -> Boolean) -> List a -> List a
214+
take-while = \ p xs . xs nil \ x xs . p x nil (cons x (take-while p xs))
215+
216+
# drop-while :: (a -> Boolean) -> List a -> List a
217+
drop-while = \ p xs . xs nil \ x xs . p x xs (drop-while p xs)
218+
219+
# drop-while-end :: (a -> Boolean) -> List a -> List a
220+
drop-while-end = \ p . foldr ( \ x z . and (null z) (p x) (cons x z) nil ) nil
221+
222+
# group-by :: (a -> a -> Bool) -> List a -> List (List a)
223+
group-by = \ eq xs . xs nil \ x xs . span (eq x) xs \ left right . cons (cons x left) (group-by eq right)
224+
group-by = \ eq xs . xs nil \ x xs . uncurry cons (bimap (cons x) (group-by eq) (span (eq x) xs))
225+
226+
# inits
227+
228+
# tails :: List a -> List (List a)
229+
tails = \ xs . cons xs (xs nil (K tails))
230+
231+
# lookup-by :: (a -> Boolean) -> List (Pair a b) -> Option b
232+
lookup-by = \ eq xys . xys None \ xy xys . xy \ x y . eq x (lookup-by eq xys) (Some y)
233+
234+
# nub-by
235+
# delete-by
236+
# delete-firsts-by
237+
# sort-on

tests/scott-lists/test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const {assert} = require("chai");
2+
3+
const LC = require("../../src/lambda-calculus.js");
4+
LC.config.purity = "LetRec";
5+
LC.config.numEncoding = "Scott";
6+
LC.config.verbosity = "Concise";
7+
8+
const solution = LC.compile();
9+
const fromInt = LC.fromIntWith(LC.config);
10+
const toInt = LC.toIntWith(LC.config);
11+
12+
const {nil,cons,singleton} = solution;
13+
const {foldr,head,tail,take} = solution;
14+
const {iterate,repeat,cycle,replicate} = solution;
15+
const {foldl,reverse} = solution;
16+
17+
const fromList = foldl ( z => x => [...z,x] ) ([]) ;
18+
19+
describe("Scott Lists",function(){
20+
it("example tests",()=>{
21+
assert.deepEqual( fromList( nil ), [] );
22+
assert.deepEqual( fromList( singleton ("0") ), ["0"] );
23+
assert.deepEqual( fromList( cons ("0") (singleton ("1")) ), ["0","1"] );
24+
assert.deepEqual( fromList( replicate (fromInt(0)) ("0") ), [] );
25+
assert.deepEqual( fromList( replicate (fromInt(1)) ("0") ), ["0"] );
26+
assert.deepEqual( fromList( replicate (fromInt(2)) ("0") ), ["0","0"] );
27+
});
28+
it("random tests",()=>{
29+
const rnd = (m,n=0) => Math.random() * (n-m) + m | 0 ;
30+
for ( let i=1; i<=100; i++ ) {
31+
const m = rnd(i), n = rnd(i);
32+
assert.deepEqual( fromList( replicate (fromInt(m)) (String(n)) ), [], `after ${ i } tests` );
33+
}
34+
});
35+
});

0 commit comments

Comments
 (0)