Skip to content

Commit c858c33

Browse files
committed
Add Set module (thin wrapper around 'Map')
1 parent b30114c commit c858c33

File tree

4 files changed

+532
-0
lines changed

4 files changed

+532
-0
lines changed

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ build:
1010
$(COMPILER) ./Hash.trp -l
1111
$(COMPILER) ./Unit.trp -l
1212
$(COMPILER) ./Map.trp -l
13+
$(COMPILER) ./Set.trp -l
1314
$(COMPILER) ./StencilVector.trp -l
1415
$(COMPILER) ./HashMap.trp -l
1516
$(COMPILER) ./HashSet.trp -l

lib/Set.trp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import List
2+
import Map
3+
4+
let (*--- Set Construction ---*)
5+
6+
(** Returns an empty set using the comparator, `cmp`. *)
7+
val empty = Map.empty
8+
9+
(** Returns a set using the comparator function, `cmp` with the single value `x` pair. *)
10+
fun singleton cmp x = Map.singleton cmp x ()
11+
12+
(** Returns the set with the given value, `x`, inserted. *)
13+
fun insert s x = Map.insert s x ()
14+
15+
(*--- Set Queries ---*)
16+
17+
(** Returns `true` if the set is empty. *)
18+
val null = Map.null
19+
20+
(** Returns `true` if the value `x` is in the set. *)
21+
val mem = Map.mem
22+
23+
(** Number of elements stored in the set. *)
24+
val size = Map.size
25+
26+
(** Depth of the tree representation of the set. *)
27+
val depth = Map.depth
28+
29+
(*--- Priority Queue ---*)
30+
31+
(** The smallest element in the set, if it exists. Otherwise, `[]`. *)
32+
fun minOpt s = case Map.minOpt s of [] => []
33+
| [(k,_)] => [k]
34+
35+
(** The smallest element in the non-empty set. *)
36+
fun min s = case minOpt s of [k] => k
37+
38+
(** The smallest element (if any) together with an updated set that does not include it. If the
39+
* tree is empty, then `[]` is returned. *)
40+
fun extractMinOpt s = case Map.extractMinOpt s of ([], m') => ([], m')
41+
| ([(k,_)], m') => ([k], m')
42+
43+
(** The smallest element together with an updated set that does not include said value. *)
44+
fun extractMin s = case extractMinOpt s of ([k], m') => (k, m')
45+
46+
(*--- Set Destruction ---*)
47+
48+
(** Returns the set with the given value `x` removed. *)
49+
fun remove s x = Map.remove s x
50+
51+
(*--- Manipulation ---*)
52+
53+
(** Fold function `f` over all elements in the set in-order. Not tail-recursive. *)
54+
fun foldl f y s =
55+
let fun f' ((k,_), y') = f (k,y')
56+
in Map.foldl f' y s end
57+
58+
(** Fold function `f` over all elements in the set in reverse order. Not tail-recursive. *)
59+
fun foldr f y s =
60+
let fun f' ((k,_), y') = f (k,y')
61+
in Map.foldr f' y s end
62+
63+
(** Map function `f` onto all elements in the set. The new set uses the comparator `cmp`.
64+
* Not tail-recursive. *)
65+
fun map cmp f s =
66+
let fun f' (k,_) = (f k, ())
67+
in Map.map cmp f' s end
68+
69+
(** Filters key-value pairs in the given map. Not tail-recursive. *)
70+
fun filter f s =
71+
let fun f' (k,_) = f k
72+
in Map.filter f' s end
73+
74+
(*--- Comparison ---*)
75+
76+
(* TODO *)
77+
78+
(*--- List Conversion ---*)
79+
80+
(** A list of elements stored in the given set in descending order. *)
81+
fun toDescList m = foldl (fn (x,xs) => x::xs) [] m
82+
83+
(** A list of elements stored in the given map in ascending order. *)
84+
fun toAscList m = foldr (fn (x,xs) => x::xs) [] m
85+
86+
(** Alias for `toAscList`. *)
87+
val toList = toAscList
88+
89+
(** Returns the set (using the provided comparator function, `cmp`) that contains all key-value
90+
pairs in the given list. Tail-recursive. *)
91+
fun fromList cmp xs = List.foldl (fn (k, s) => insert s k) (empty cmp) xs
92+
93+
(*--- Module ---*)
94+
val Set = {
95+
empty,
96+
singleton,
97+
insert,
98+
null,
99+
mem,
100+
size,
101+
depth,
102+
minOpt,
103+
min,
104+
extractMinOpt,
105+
extractMin,
106+
remove,
107+
foldl,
108+
foldr,
109+
map,
110+
filter,
111+
toDescList,
112+
toAscList,
113+
toList,
114+
fromList
115+
}
116+
117+
in [ ("Set", Set) ]
118+
end

tests/lib/Set.golden

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
2025-10-24T13:05:01.367Z [RTM] info: Skipping network creation. Observe that all external IO operations will yield a runtime error.
2+
begin Set
3+
begin empty
4+
[ TEST ] it is null [ PASS ] it is null
5+
[ TEST ] it has size 0 [ PASS ] it has size 0
6+
[ TEST ] it has depth 0 [ PASS ] it has depth 0
7+
[ TEST ] it does not contain 0 [ PASS ] it does not contain 0
8+
[ TEST ] it does not contain 1 [ PASS ] it does not contain 1
9+
[ TEST ] it is not equal to 'empty >' [ PASS ] it is not equal to 'empty >'
10+
[ TEST ] it returns [] for minOpt [ PASS ] it returns [] for minOpt
11+
[ TEST ] it returns [], � for extractMinOpt [ PASS ] it returns [], � for extractMinOpt
12+
end 
13+
begin insert (empty) 0
14+
[ TEST ] it is not null [ PASS ] it is not null
15+
[ TEST ] it has size 1 [ PASS ] it has size 1
16+
[ TEST ] it has depth 1 [ PASS ] it has depth 1
17+
[ TEST ] it contains 0 [ PASS ] it contains 0
18+
[ TEST ] it does not contain 1 [ PASS ] it does not contain 1
19+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
20+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
21+
[ TEST ] it returns [0], � for extractMinOpt [ PASS ] it returns [0], � for extractMinOpt
22+
[ TEST ] it returns 0, � for extractMin [ PASS ] it returns 0, � for extractMin
23+
end 
24+
begin singleton 0 42
25+
[ TEST ] it is equivalent to 'insert (empty) 0' [ PASS ] it is equivalent to 'insert (empty) 0'
26+
end 
27+
begin fromList [(0,42)]
28+
[ TEST ] it is equivalent to 'insert (empty) 0' [ PASS ] it is equivalent to 'insert (empty) 0'
29+
end 
30+
begin fromList [1]
31+
[ TEST ] it is not null [ PASS ] it is not null
32+
[ TEST ] it has size 1 [ PASS ] it has size 1
33+
[ TEST ] it has depth 1 [ PASS ] it has depth 1
34+
[ TEST ] it does not contain 0 [ PASS ] it does not contain 0
35+
[ TEST ] it contains 1 [ PASS ] it contains 1
36+
[ TEST ] it returns [1] for minOpt [ PASS ] it returns [1] for minOpt
37+
[ TEST ] it returns 1 for minOpt [ PASS ] it returns 1 for minOpt
38+
[ TEST ] it returns [1], � for extractMinOpt [ PASS ] it returns [1], � for extractMinOpt
39+
[ TEST ] it returns 1, � for extractMin [ PASS ] it returns 1, � for extractMin
40+
end 
41+
begin insert (fromList [0]) 0
42+
[ TEST ] it is equivalent to 'insert (empty) 0' [ PASS ] it is equivalent to 'insert (empty) 0'
43+
end 
44+
begin fromList [1,0]
45+
[ TEST ] it is not null [ PASS ] it is not null
46+
[ TEST ] it has size 2 [ PASS ] it has size 2
47+
[ TEST ] it has depth 2 [ PASS ] it has depth 2
48+
[ TEST ] it contains 0 [ PASS ] it contains 0
49+
[ TEST ] it contains 1 [ PASS ] it contains 1
50+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
51+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
52+
[ TEST ] it returns [0], .. for extractMinOpt [ PASS ] it returns [0], .. for extractMinOpt
53+
[ TEST ] it returns 0, .. for extractMin [ PASS ] it returns 0, .. for extractMin
54+
end 
55+
begin fromList [0,1]
56+
[ TEST ] it is not null [ PASS ] it is not null
57+
[ TEST ] it has size 2 [ PASS ] it has size 2
58+
[ TEST ] it has depth 2 [ PASS ] it has depth 2
59+
[ TEST ] it contains 0 [ PASS ] it contains 0
60+
[ TEST ] it contains 1 [ PASS ] it contains 1
61+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
62+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
63+
[ TEST ] it returns [0], .. for extractMinOpt [ PASS ] it returns [0], .. for extractMinOpt
64+
[ TEST ] it returns 0, .. for extractMin [ PASS ] it returns 0, .. for extractMin
65+
end 
66+
begin insert (fromList [1,2]) 1
67+
[ TEST ] it is equivalent to 'fromList [1,2]' [ PASS ] it is equivalent to 'fromList [1,2]'
68+
end 
69+
begin insert (fromList [1,2]) 2
70+
[ TEST ] it is equivalent to 'fromList [1,2]' [ PASS ] it is equivalent to 'fromList [1,2]'
71+
end 
72+
begin fromList [1,0,2]
73+
[ TEST ] it is not null [ PASS ] it is not null
74+
[ TEST ] it has size 3 [ PASS ] it has size 3
75+
[ TEST ] it has depth 2 [ PASS ] it has depth 2
76+
[ TEST ] it contains 0 [ PASS ] it contains 0
77+
[ TEST ] it contains 1 [ PASS ] it contains 1
78+
[ TEST ] it contains 2 [ PASS ] it contains 2
79+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
80+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
81+
[ TEST ] it returns [0], .. for extractMinOpt [ PASS ] it returns [0], .. for extractMinOpt
82+
[ TEST ] it returns 0, .. for extractMin [ PASS ] it returns 0, .. for extractMin
83+
end 
84+
begin fromList [0,1,2]
85+
[ TEST ] it is not null [ PASS ] it is not null
86+
[ TEST ] it has size 3 [ PASS ] it has size 3
87+
[ TEST ] it has depth 3 [ PASS ] it has depth 3
88+
[ TEST ] it contains 0 [ PASS ] it contains 0
89+
[ TEST ] it contains 1 [ PASS ] it contains 1
90+
[ TEST ] it contains 2 [ PASS ] it contains 2
91+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
92+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
93+
[ TEST ] it returns [0], .. for extractMinOpt [ PASS ] it returns [0], .. for extractMinOpt
94+
[ TEST ] it returns 0, .. for extractMin [ PASS ] it returns 0, .. for extractMin
95+
end 
96+
begin fromList [2,1,0]
97+
[ TEST ] it is not null [ PASS ] it is not null
98+
[ TEST ] it has size 3 [ PASS ] it has size 3
99+
[ TEST ] it has depth 3 [ PASS ] it has depth 3
100+
[ TEST ] it contains 0 [ PASS ] it contains 0
101+
[ TEST ] it contains 1 [ PASS ] it contains 1
102+
[ TEST ] it contains 2 [ PASS ] it contains 2
103+
[ TEST ] it returns [0] for minOpt [ PASS ] it returns [0] for minOpt
104+
[ TEST ] it returns 0 for min [ PASS ] it returns 0 for min
105+
[ TEST ] it returns [0], .. for extractMinOpt [ PASS ] it returns [0], .. for extractMinOpt
106+
[ TEST ] it returns 0, .. for extractMin [ PASS ] it returns 0, .. for extractMin
107+
end 
108+
begin remove (fromList [0]) 0
109+
[ TEST ] it is equivalent to 'empty' [ PASS ] it is equivalent to 'empty'
110+
end 
111+
begin remove (fromList [1]) 0
112+
[ TEST ] it is equivalent to itself [ PASS ] it is equivalent to itself
113+
end 
114+
begin remove (fromList [1]) 2
115+
[ TEST ] it is equivalent to itself [ PASS ] it is equivalent to itself
116+
end 
117+
begin remove (fromList [1,0,2]) 0
118+
[ TEST ] it is equivalent to 'fromList [1,2]' [ PASS ] it is equivalent to 'fromList [1,2]'
119+
end 
120+
begin remove (fromList [1,0,2]) 1
121+
[ TEST ] it is equivalent to 'fromList [2,0]' [ PASS ] it is equivalent to 'fromList [2,0]'
122+
end 
123+
begin remove (fromList [1,0,2]) 2
124+
[ TEST ] it is equivalent to 'fromList [1,0]' [ PASS ] it is equivalent to 'fromList [1,0]'
125+
end 
126+
begin foldl
127+
[ TEST ] it folds fromList [] [ PASS ] it folds fromList []
128+
[ TEST ] it folds fromList [1] [ PASS ] it folds fromList [1]
129+
[ TEST ] it folds fromList [2,1] [ PASS ] it folds fromList [2,1]
130+
[ TEST ] it folds fromList [2,1,3] [ PASS ] it folds fromList [2,1,3]
131+
end 
132+
begin foldr
133+
[ TEST ] it folds fromList [] [ PASS ] it folds fromList []
134+
[ TEST ] it folds fromList [1] [ PASS ] it folds fromList [1]
135+
[ TEST ] it folds fromList [2,1] [ PASS ] it folds fromList [2,1]
136+
[ TEST ] it folds fromList [2,1,3] [ PASS ] it folds fromList [2,1,3]
137+
end 
138+
begin map
139+
[ TEST ] it mirrors > (x -> x) (fromList [2,1]) [ PASS ] it mirrors > (x -> x) (fromList [2,1])
140+
[ TEST ] it maps keys > (x -> -x) (fromList [2,1]) [ PASS ] it maps keys > (x -> -x) (fromList [2,1])
141+
end 
142+
begin keys, values, and toList
143+
[ TEST ] it converts [] [ PASS ] it converts []
144+
[ TEST ] it converts [0] [ PASS ] it converts [0]
145+
[ TEST ] it converts [1,0] [ PASS ] it converts [1,0]
146+
[ TEST ] it converts [1,0,2] [ PASS ] it converts [1,0,2]
147+
end 
148+
end 
149+
150+
Total: 99
151+
Passes: 99
152+
>>> Main thread finished with value: true@{}%{}

0 commit comments

Comments
 (0)