@@ -11,24 +11,242 @@ module NonEmptyList =
1111 let (><) y x = cons y ( singleton x)
1212 let (>-) x xs = cons x xs
1313
14+ // Convert a NonEmptyList to a List
15+ let rec toList xs =
16+ match xs with
17+ | Single x -> [ x]
18+ | Cons ( x, xs') -> List.Cons ( x, toList xs')
19+
20+ // Convert a List to NonEmptyList
1421 let rec ofList x xs =
1522 match xs with
16- | [] -> Single x
17- | x' :: xs' -> x >- ( ofList x' xs' )
23+ | [] -> Single x
24+ | h :: t -> x >- ( ofList h t )
1825
26+ // Combine two NonEmptyLists, putting the first before the second
1927 let rec append xs ys =
2028 match xs with
21- | Single x -> Cons ( x, ys)
22- | Cons ( x, xs') -> Cons ( x, append xs' ys)
29+ | Single x -> Cons ( x, ys)
30+ | Cons ( x, xs') -> Cons ( x, append xs' ys)
2331
32+ // Combine a List and a NonEmptyList, putting the first before the second
33+ // Results in a NonEmptyList
2434 let appendList xs ys =
2535 match xs with
26- | [] -> ys
27- | h :: t -> append ( ofList h t) ys
36+ | [] -> ys
37+ | h :: t -> append ( ofList h t) ys
2838
29- let rec toList xs =
39+ // Combine two NonEmptyLists, putting the second before the first
40+ let rec prepend xs ys =
41+ match ys with
42+ | Single y -> Cons ( y, xs)
43+ | Cons ( y, ys') -> Cons ( y, prepend ys' xs)
44+
45+ // Combine a List and a NonEmptyList, putting the second before the first
46+ // Results in a NonEmptyList
47+ let prependList xs ys =
48+ match xs with
49+ | [] -> ys
50+ | h :: t -> prepend ( ofList h t) ys
51+
52+ // Get the number of items in the NonEmptyList
53+ let rec length xs =
54+ match xs with
55+ | Single _ -> 1
56+ | Cons (_, xs') -> 1 + length xs'
57+
58+ // Get the first item in the NonEmptyList
59+ let head xs =
60+ match xs with
61+ | Single x -> x
62+ | Cons ( x, _) -> x
63+
64+ // Get the last item in the NonEmptyList
65+ let rec last xs =
66+ match xs with
67+ | Single x -> x
68+ | Cons (_, xs') -> last xs'
69+
70+ // Get the first n items in the NonEmptyList
71+ // If n is greater than the count, returns the original NonEmptyList
72+ // n must be greater than zero in order to return a result
73+ let take i xs =
74+ if i < 1 then None
75+ else
76+ match List.truncate i ( toList xs) with
77+ | [] -> None // theoretically impossible
78+ | h :: t -> Some ( ofList h t)
79+
80+ // Get the first items in the NonEmptyList that meet the provided criteria
81+ let takeWhile f xs =
82+ match List.takeWhile f ( toList xs) with
83+ | [] -> None
84+ | h :: t -> Some ( ofList h t)
85+
86+ // Get all items in the NonEmptyList except for the last one
87+ let init xs =
88+ match xs with
89+ | Single _ -> None
90+ | _ -> take ( length xs - 1 ) xs
91+
92+ // Get all items in the NonEmptyList except for the first one
93+ let tail xs =
94+ match xs with
95+ | Single _ -> None
96+ | Cons (_, xs') -> Some xs'
97+
98+ // Remove the first n items in the NonEmptyList
99+ // n must be greater than zero and less than the count in order to return a result
100+ // Technically this function can throw exceptions (List.skip), but the initial checks will avoid that
101+ let skip i xs =
102+ let xs ' = toList xs
103+ if i < 0 then None
104+ elif i >= ( List.length xs') then None
105+ else
106+ match List.skip i xs' with
107+ | [] -> None // theoretically impossible
108+ | h :: t -> Some ( ofList h t)
109+
110+ // Remove the first items in the NonEmptyList that meet the provided criteria
111+ let skipWhile f xs =
112+ match List.skipWhile f ( toList xs) with
113+ | [] -> None
114+ | h :: t -> Some ( ofList h t)
115+
116+ // Apply the provided function to each item in the NonEmptyList
117+ let rec map f xs =
30118 match xs with
31- | Single x -> [ x]
32- | Cons ( x, xs') -> List.Cons ( x, toList xs')
119+ | Single x -> Single ( f x)
120+ | Cons ( x, xs') -> Cons ( f x, map f xs')
121+
122+ // Apply the provided function to each element of the collection, threading an
123+ // accumulator through the computation, returning a final result
124+ let fold f a xs = List.fold f a ( toList xs)
125+
126+ // Determine if the provided item is in the NonEmptyList
127+ let contains x xs = List.contains x ( toList xs)
128+
129+ // Get the provided item from the NonEmptyList if it exists
130+ let rec find x xs =
131+ match xs with
132+ | Single x' -> if x = x' then ( Some x') else None
133+ | Cons ( x', xs') -> if x = x' then ( Some x') else find x xs'
134+
135+ // Determine if any item in the NonEmptyList meets the provided criteria
136+ let exists f xs =
137+ match List.where f ( toList xs) with
138+ | [] -> false
139+ | _ -> true
140+
141+ // Determine if all items in the NonEmptyList meet the provided criteria
142+ let forall f xs = List.forall f ( toList xs)
143+
144+ // Gets the items in the NonEmptyList that meet the provided criteria
145+ let where f xs =
146+ match List.where f ( toList xs) with
147+ | [] -> None
148+ | h :: t -> Some ( ofList h t)
149+
150+ // Get the item at the provided index (index zero) from the NonEmptyList
151+ // If the index is less than zero, get the item at the beginning of the NonEmptyList
152+ // If the index is greater than the (count - 1), get the item at the end of the NonEmptyList
153+ // Technically this function can throw exceptions (List.item), but the initial checks will avoid that
154+ let item i xs =
155+ let e = length xs - 1
156+ let i ' = if i < 0 then 0 elif i > e then e else i
157+ List.item i' ( toList xs)
158+
159+ // Add the provided item to the NonEmptyList at the provided index (index zero)
160+ // If the index is less than zero, the item will go at the beginning of the NonEmptyList
161+ // If the index is greater than the (count - 1), the item will go at the end of the NonEmptyList
162+ // Technically this function can throw exceptions (List.insertAt), but the initial checks will avoid that
163+ let insertAt i x xs =
164+ let e = length xs - 1
165+ let i ' = if i < 0 then 0 elif i > e then e else i
166+ match List.insertAt i' x ( toList xs) with
167+ | [] -> Single x // theoretically impossible
168+ | h :: t -> ofList h t
169+
170+ // Remove the item at the provided index (index zero) from the NonEmptyList
171+ // If the index is less than zero, the item at the beginning of the NonEmptyList will be removed
172+ // If the index is greater than the (count - 1), the item at the end of the NonEmptyList will be removed
173+ // If the NonEmptyList is a singleton, it will be returned as is
174+ // Technically this function can throw exceptions (List.removeAt), but the initial checks will avoid that
175+ let removeAt i xs =
176+ match xs with
177+ | Single _ -> xs
178+ | _ ->
179+ let e = length xs - 1
180+ let i ' = if i < 0 then 0 elif i > e then e else i
181+ match List.removeAt i' ( toList xs) with
182+ | [] -> xs // theoretically impossible
183+ | h :: t -> ofList h t
184+
185+ // Replace the item at the provided index (index zero) in the NonEmptyList
186+ // If the index is less than zero, the item at the beginning of the NonEmptyList will be replaced
187+ // If the index is greater than the (count - 1), the item at the end of the NonEmptyList will be replaced
188+ // If the NonEmptyList is a singleton, the single value will be replaced
189+ // Technically this function can throw exceptions (List.updateAt), but the initial checks will avoid that
190+ let updateAt i x xs =
191+ match xs with
192+ | Single _ -> Single x
193+ | _ ->
194+ let e = length xs - 1
195+ let i ' = if i < 0 then 0 elif i > e then e else i
196+ match List.updateAt i' x ( toList xs) with
197+ | [] -> xs // theoretically impossible
198+ | h :: t -> ofList h t
199+
200+ // Split the NonEmptyList into two NonEmptyLists, the first of which the provided constraint is true and the second is false
201+ // No result signifies that all the items in the NonEmptyList meet the constraint in the same way
202+ let partition f xs =
203+ match List.partition f ( toList xs) with
204+ | ([], _) -> None
205+ | (_, []) -> None
206+ | ( h :: t, h' :: t') -> Some ( ofList h t, ofList h' t')
207+
208+ // Split the NonEmptyList at the provided index (index zero)
209+ // If the index is less than zero, the item at the beginning of the NonEmptyList will become a singleton
210+ // If the index is greater than the (count - 1), the item at the end of the NonEmptyList will become a singleton
211+ // No result signifies that the NonEmptyList is a singleton
212+ // Technically this function can throw exceptions (List.splitAt), but the initial checks will avoid that
213+ let splitAt i xs =
214+ match xs with
215+ | Single _ -> None
216+ | _ ->
217+ let e = length xs - 1
218+ let i ' = if i < 0 then 0 elif i > e then e else i
219+ match List.splitAt i' ( toList xs) with
220+ | ([], _) -> None // theoretically impossible
221+ | (_, []) -> None // theoretically impossible
222+ | ( h :: t, h' :: t') -> Some ( ofList h t, ofList h' t')
223+
224+ // Get the items in the NonEmptyList in reverse order
225+ // Technically this function can throw exceptions (List.head, List.tail), but the source NonEmptyList will avoid that
226+ let reverse xs =
227+ let xs ' = toList xs |> List.rev
228+ ofList ( List.head xs') ( List.tail xs')
229+
230+ // Sort the NonEmptyList with Operators.compare
231+ let sort xs =
232+ match List.sort ( toList xs) with
233+ | [] -> xs // theoretically impossible
234+ | h :: t -> ofList h t
235+
236+ // Sort the NonEmptyList with the keys given in the projection
237+ let sortBy f xs =
238+ match List.sortBy f ( toList xs) with
239+ | [] -> xs // theoretically impossible
240+ | h :: t -> ofList h t
241+
242+ // Removes all duplicate items in the NonEmptyList
243+ let distinct xs =
244+ match List.distinct ( toList xs) with
245+ | [] -> xs // theoretically impossible
246+ | h :: t -> ofList h t
33247
34- //TODO: implement remaining functions.
248+ // Removes all duplicate items in the NonEmptyList, determined by the provided function
249+ let distinctBy f xs =
250+ match List.distinctBy f ( toList xs) with
251+ | [] -> xs // theoretically impossible
252+ | h :: t -> ofList h t
0 commit comments