@grain/stdlib 0.4.6 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/array.gr +18 -18
- package/array.md +18 -18
- package/bigint.gr +497 -0
- package/bigint.md +811 -0
- package/buffer.gr +59 -223
- package/buffer.md +24 -17
- package/bytes.gr +100 -202
- package/bytes.md +19 -0
- package/char.gr +63 -133
- package/exception.gr +28 -2
- package/exception.md +43 -0
- package/float32.gr +76 -95
- package/float32.md +69 -30
- package/float64.gr +81 -95
- package/float64.md +69 -30
- package/hash.gr +37 -37
- package/int32.gr +152 -198
- package/int32.md +104 -0
- package/int64.gr +151 -197
- package/int64.md +104 -0
- package/list.gr +467 -70
- package/list.md +1141 -0
- package/map.gr +192 -7
- package/map.md +525 -0
- package/number.gr +111 -54
- package/number.md +100 -3
- package/option.md +1 -1
- package/package.json +3 -3
- package/pervasives.gr +499 -59
- package/pervasives.md +1116 -0
- package/queue.gr +4 -0
- package/queue.md +10 -0
- package/random.gr +196 -0
- package/random.md +179 -0
- package/regex.gr +1833 -842
- package/regex.md +11 -11
- package/result.md +1 -1
- package/runtime/bigint.gr +2045 -0
- package/runtime/bigint.md +326 -0
- package/runtime/dataStructures.gr +99 -278
- package/runtime/dataStructures.md +391 -0
- package/runtime/debug.md +6 -0
- package/runtime/equal.gr +5 -23
- package/runtime/equal.md +6 -0
- package/runtime/exception.md +30 -0
- package/runtime/gc.gr +20 -3
- package/runtime/gc.md +36 -0
- package/runtime/malloc.gr +13 -11
- package/runtime/malloc.md +55 -0
- package/runtime/numberUtils.gr +91 -41
- package/runtime/numberUtils.md +54 -0
- package/runtime/numbers.gr +1049 -391
- package/runtime/numbers.md +300 -0
- package/runtime/string.gr +136 -230
- package/runtime/string.md +24 -0
- package/runtime/stringUtils.gr +58 -38
- package/runtime/stringUtils.md +6 -0
- package/runtime/unsafe/constants.gr +17 -0
- package/runtime/unsafe/constants.md +72 -0
- package/runtime/unsafe/conv.md +71 -0
- package/runtime/unsafe/errors.md +204 -0
- package/runtime/unsafe/memory.md +54 -0
- package/runtime/unsafe/printWasm.md +24 -0
- package/runtime/unsafe/tags.gr +9 -8
- package/runtime/unsafe/tags.md +120 -0
- package/runtime/unsafe/wasmf32.md +168 -0
- package/runtime/unsafe/wasmf64.md +168 -0
- package/runtime/unsafe/wasmi32.md +282 -0
- package/runtime/unsafe/wasmi64.md +300 -0
- package/runtime/utils/printing.gr +62 -0
- package/runtime/utils/printing.md +18 -0
- package/runtime/wasi.gr +1 -1
- package/runtime/wasi.md +839 -0
- package/set.gr +17 -8
- package/set.md +24 -21
- package/stack.gr +3 -3
- package/stack.md +4 -6
- package/string.gr +194 -329
- package/string.md +3 -3
- package/sys/file.gr +245 -429
- package/sys/process.gr +27 -45
- package/sys/random.gr +47 -16
- package/sys/random.md +38 -0
- package/sys/time.gr +11 -27
package/list.gr
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module List: Utilities for working with lists.
|
|
3
|
+
*
|
|
4
|
+
* @example import List from "list"
|
|
5
|
+
*
|
|
6
|
+
* @since v0.2.0
|
|
7
|
+
* @history v0.1.0: Originally named `lists`
|
|
8
|
+
* @history v0.2.0: Renamed to `list`
|
|
9
|
+
*/
|
|
2
10
|
|
|
3
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @section Values: Functions for working with the List data type.
|
|
13
|
+
*/
|
|
4
14
|
|
|
5
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new list of the specified length where each element is
|
|
17
|
+
* initialized with the result of an initializer function. The initializer
|
|
18
|
+
* is called with the index of each list element.
|
|
19
|
+
*
|
|
20
|
+
* @param length: The length of the new list
|
|
21
|
+
* @param fn: The initializer function to call with each index, where the value returned will be used to initialize the element
|
|
22
|
+
* @returns The new list
|
|
23
|
+
*
|
|
24
|
+
* @example List.init(5, n => n + 3) // [3, 4, 5, 6, 7]
|
|
25
|
+
*
|
|
26
|
+
* @since v0.3.0
|
|
27
|
+
*/
|
|
28
|
+
export let init = (length, fn) => {
|
|
6
29
|
// This method can be further improved by checking the length against a specific size
|
|
7
30
|
// and determining if it can be made tail-recursive, then use List.reverse on it.
|
|
8
31
|
// Which would be the same as OCaml does it in https://github.com/ocaml/ocaml/blob/03839754f46319aa36d9dad56940a6f3c3bcb48a/stdlib/list.ml#L79
|
|
@@ -16,7 +39,16 @@ let init = (length, fn) => {
|
|
|
16
39
|
iter(0, length)
|
|
17
40
|
}
|
|
18
41
|
|
|
19
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Computes the length of the input list.
|
|
44
|
+
*
|
|
45
|
+
* @param list: The list to inspect
|
|
46
|
+
* @returns The number of elements in the list
|
|
47
|
+
*
|
|
48
|
+
* @since v0.1.0
|
|
49
|
+
* @history v0.2.0: Made the function tail-recursive
|
|
50
|
+
*/
|
|
51
|
+
export let length = list => {
|
|
20
52
|
let rec iter = (len, list) => {
|
|
21
53
|
match (list) {
|
|
22
54
|
[] => len,
|
|
@@ -26,17 +58,15 @@ let length = list => {
|
|
|
26
58
|
iter(0, list)
|
|
27
59
|
}
|
|
28
60
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let reverse = list => {
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new list with all elements in reverse order.
|
|
63
|
+
*
|
|
64
|
+
* @param list: The list to reverse
|
|
65
|
+
* @returns The new list
|
|
66
|
+
*
|
|
67
|
+
* @since v0.1.0
|
|
68
|
+
*/
|
|
69
|
+
export let reverse = list => {
|
|
40
70
|
let rec iter = (list, acc) => {
|
|
41
71
|
match (list) {
|
|
42
72
|
[] => acc,
|
|
@@ -46,42 +76,122 @@ let reverse = list => {
|
|
|
46
76
|
iter(list, [])
|
|
47
77
|
}
|
|
48
78
|
|
|
49
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Creates a new list with the elements of the first list followed by
|
|
81
|
+
* the elements of the second list.
|
|
82
|
+
*
|
|
83
|
+
* @param list1: The list containing elements to appear first
|
|
84
|
+
* @param list2: The list containing elements to appear second
|
|
85
|
+
* @returns The new list containing elements from `list1` followed by elements from `list2`
|
|
86
|
+
*
|
|
87
|
+
* @since v0.1.0
|
|
88
|
+
*/
|
|
89
|
+
export let rec append = (list1, list2) => {
|
|
50
90
|
match (list1) {
|
|
51
91
|
[] => list2,
|
|
52
92
|
[first, ...rest] => [first, ...append(rest, list2)],
|
|
53
93
|
}
|
|
54
94
|
}
|
|
55
95
|
|
|
56
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Checks if the value is an element of the input list.
|
|
98
|
+
* Uses the generic `==` structural equality operator.
|
|
99
|
+
*
|
|
100
|
+
* @param search: The value to compare
|
|
101
|
+
* @param list: The list to inspect
|
|
102
|
+
* @returns `true` if the value exists in the list or `false` otherwise
|
|
103
|
+
*
|
|
104
|
+
* @since v0.1.0
|
|
105
|
+
*/
|
|
106
|
+
export let rec contains = (search, list) => {
|
|
57
107
|
match (list) {
|
|
58
108
|
[] => false,
|
|
59
|
-
[first, ...rest] => first ==
|
|
109
|
+
[first, ...rest] => first == search || contains(search, rest),
|
|
60
110
|
}
|
|
61
111
|
}
|
|
62
112
|
|
|
63
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Combines all elements of a list using a reducer function,
|
|
115
|
+
* starting from the "head", or left side, of the list.
|
|
116
|
+
*
|
|
117
|
+
* In `List.reduce(fn, initial, list)`, `fn` is called with
|
|
118
|
+
* an accumulator and each element of the list, and returns
|
|
119
|
+
* a new accumulator. The final value is the last accumulator
|
|
120
|
+
* returned. The accumulator starts with value `initial`.
|
|
121
|
+
*
|
|
122
|
+
* @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
|
|
123
|
+
* @param initial: The initial value to use for the accumulator on the first iteration
|
|
124
|
+
* @param list: The list to iterate
|
|
125
|
+
* @returns The final accumulator returned from `fn`
|
|
126
|
+
*
|
|
127
|
+
* @example List.reduce((a, b) => a + b, 0, [1, 2, 3]) // 6
|
|
128
|
+
*
|
|
129
|
+
* @since v0.2.0
|
|
130
|
+
* @history v0.1.0: Originally named `foldLeft`
|
|
131
|
+
* @history v0.2.0: Renamed to `reduce`
|
|
132
|
+
*/
|
|
133
|
+
export let rec reduce = (fn, initial, list) => {
|
|
64
134
|
match (list) {
|
|
65
|
-
[] =>
|
|
66
|
-
[first, ...rest] => reduce(fn, fn(
|
|
135
|
+
[] => initial,
|
|
136
|
+
[first, ...rest] => reduce(fn, fn(initial, first), rest),
|
|
67
137
|
}
|
|
68
138
|
}
|
|
69
139
|
|
|
70
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Combines all elements of a list using a reducer function,
|
|
142
|
+
* starting from the "end", or right side, of the list.
|
|
143
|
+
*
|
|
144
|
+
* In `List.reduceRight(fn, initial, list)`, `fn` is called with
|
|
145
|
+
* each element of the list and an accumulator, and returns
|
|
146
|
+
* a new accumulator. The final value is the last accumulator
|
|
147
|
+
* returned. The accumulator starts with value `initial`.
|
|
148
|
+
*
|
|
149
|
+
* @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
|
|
150
|
+
* @param initial: The initial value to use for the accumulator on the first iteration
|
|
151
|
+
* @param list: The list to iterate
|
|
152
|
+
* @returns The final accumulator returned from `fn`
|
|
153
|
+
*
|
|
154
|
+
* @example List.reduceRight((a, b) => b ++ a, "", ["baz", "bar", "foo"]) // "foobarbaz"
|
|
155
|
+
*
|
|
156
|
+
* @since v0.2.0
|
|
157
|
+
* @history v0.1.0: Originally named `foldRight`
|
|
158
|
+
* @history v0.2.0: Renamed to `reduceRight`
|
|
159
|
+
*/
|
|
160
|
+
export let rec reduceRight = (fn, initial, list) => {
|
|
71
161
|
match (list) {
|
|
72
|
-
[] =>
|
|
73
|
-
[first, ...rest] => fn(first, reduceRight(fn,
|
|
162
|
+
[] => initial,
|
|
163
|
+
[first, ...rest] => fn(first, reduceRight(fn, initial, rest)),
|
|
74
164
|
}
|
|
75
165
|
}
|
|
76
166
|
|
|
77
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Produces a new list initialized with the results of a mapper function
|
|
169
|
+
* called on each element of the input list.
|
|
170
|
+
*
|
|
171
|
+
* @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
|
|
172
|
+
* @param list: The list to iterate
|
|
173
|
+
* @returns The new list with mapped values
|
|
174
|
+
*
|
|
175
|
+
* @since v0.1.0
|
|
176
|
+
*/
|
|
177
|
+
export let rec map = (fn, list) => {
|
|
78
178
|
match (list) {
|
|
79
179
|
[] => [],
|
|
80
180
|
[first, ...rest] => [fn(first), ...map(fn, rest)],
|
|
81
181
|
}
|
|
82
182
|
}
|
|
83
183
|
|
|
84
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Produces a new list initialized with the results of a mapper function
|
|
186
|
+
* called on each element of the input list and its index.
|
|
187
|
+
*
|
|
188
|
+
* @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
|
|
189
|
+
* @param list: The list to iterate
|
|
190
|
+
* @returns The new list with mapped values
|
|
191
|
+
*
|
|
192
|
+
* @since v0.1.0
|
|
193
|
+
*/
|
|
194
|
+
export let mapi = (fn, list) => {
|
|
85
195
|
let rec iter = (fn, list, index) => {
|
|
86
196
|
match (list) {
|
|
87
197
|
[] => [],
|
|
@@ -91,41 +201,90 @@ let mapi = (fn, list) => {
|
|
|
91
201
|
iter(fn, list, 0)
|
|
92
202
|
}
|
|
93
203
|
|
|
94
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Produces a new list by calling a function on each element
|
|
206
|
+
* of the input list. Each iteration produces an intermediate
|
|
207
|
+
* list, which are all appended to produce a "flattened" list
|
|
208
|
+
* of all results.
|
|
209
|
+
*
|
|
210
|
+
* @param fn: The function to be called on each element, where the value returned will be a list that gets appended to the new list
|
|
211
|
+
* @param list: The list to iterate
|
|
212
|
+
* @returns The new list
|
|
213
|
+
*
|
|
214
|
+
* @since v0.2.0
|
|
215
|
+
*/
|
|
216
|
+
export let rec flatMap = (fn, list) => {
|
|
95
217
|
match (list) {
|
|
96
218
|
[] => [],
|
|
97
219
|
[first, ...rest] => append(fn(first), flatMap(fn, rest)),
|
|
98
220
|
}
|
|
99
221
|
}
|
|
100
222
|
|
|
101
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Checks that the given condition is satisfied for all
|
|
225
|
+
* elements in the input list.
|
|
226
|
+
*
|
|
227
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
228
|
+
* @param list: The list to check
|
|
229
|
+
* @returns `true` if all elements satify the condition or `false` otherwise
|
|
230
|
+
*
|
|
231
|
+
* @since v0.1.0
|
|
232
|
+
*/
|
|
233
|
+
export let every = (fn, list) => {
|
|
102
234
|
reduce((acc, value) => {
|
|
103
235
|
acc && fn(value)
|
|
104
236
|
}, true, list)
|
|
105
237
|
}
|
|
106
238
|
|
|
107
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Checks that the given condition is satisfied **at least
|
|
241
|
+
* once** by an element in the input list.
|
|
242
|
+
*
|
|
243
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
244
|
+
* @param list: The list to iterate
|
|
245
|
+
* @returns `true` if one or more elements satify the condition or `false` otherwise
|
|
246
|
+
*
|
|
247
|
+
* @since v0.1.0
|
|
248
|
+
*/
|
|
249
|
+
export let some = (fn, list) => {
|
|
108
250
|
reduce((acc, value) => {
|
|
109
251
|
acc || fn(value)
|
|
110
252
|
}, false, list)
|
|
111
253
|
}
|
|
112
254
|
|
|
113
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Iterates a list, calling an iterator function on each element.
|
|
257
|
+
*
|
|
258
|
+
* @param fn: The iterator function to call with each element
|
|
259
|
+
* @param list: The list to iterate
|
|
260
|
+
*
|
|
261
|
+
* @since v0.1.0
|
|
262
|
+
*/
|
|
263
|
+
export let rec forEach = (fn, list) => {
|
|
114
264
|
match (list) {
|
|
115
265
|
[] => void,
|
|
116
266
|
[first, ...rest] => {
|
|
117
|
-
fn(first)
|
|
267
|
+
fn(first): Void
|
|
118
268
|
forEach(fn, rest)
|
|
119
269
|
},
|
|
120
270
|
}
|
|
121
271
|
}
|
|
122
272
|
|
|
123
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Iterates a list, calling an iterator function on each element.
|
|
275
|
+
* Also passes the index as the second argument to the function.
|
|
276
|
+
*
|
|
277
|
+
* @param fn: The iterator function to call with each element
|
|
278
|
+
* @param list: The list to iterate
|
|
279
|
+
*
|
|
280
|
+
* @since v0.1.0
|
|
281
|
+
*/
|
|
282
|
+
export let forEachi = (fn, list) => {
|
|
124
283
|
let rec iter = (fn, list, index) => {
|
|
125
284
|
match (list) {
|
|
126
285
|
[] => void,
|
|
127
286
|
[first, ...rest] => {
|
|
128
|
-
fn(first, index)
|
|
287
|
+
fn(first, index): Void
|
|
129
288
|
iter(fn, rest, index + 1)
|
|
130
289
|
},
|
|
131
290
|
}
|
|
@@ -133,7 +292,18 @@ let forEachi = (fn, list) => {
|
|
|
133
292
|
iter(fn, list, 0)
|
|
134
293
|
}
|
|
135
294
|
|
|
136
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Produces a new list by calling a function on each element of
|
|
297
|
+
* the input list and only including it in the result list if the element satisfies
|
|
298
|
+
* the condition.
|
|
299
|
+
*
|
|
300
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
301
|
+
* @param list: The list to iterate
|
|
302
|
+
* @returns The new list containing elements where `fn` returned `true`
|
|
303
|
+
*
|
|
304
|
+
* @since v0.1.0
|
|
305
|
+
*/
|
|
306
|
+
export let rec filter = (fn, list) => {
|
|
137
307
|
match (list) {
|
|
138
308
|
[] => [],
|
|
139
309
|
[first, ...rest] =>
|
|
@@ -141,7 +311,18 @@ let rec filter = (fn, list) => {
|
|
|
141
311
|
}
|
|
142
312
|
}
|
|
143
313
|
|
|
144
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Produces a new list by calling a function on each element of
|
|
316
|
+
* the input list and only including it in the result list if the element satisfies
|
|
317
|
+
* the condition. Also passes the index to the function.
|
|
318
|
+
*
|
|
319
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
320
|
+
* @param list: The list to iterate
|
|
321
|
+
* @returns The new list containing elements where `fn` returned `true`
|
|
322
|
+
*
|
|
323
|
+
* @since v0.3.0
|
|
324
|
+
*/
|
|
325
|
+
export let filteri = (fn, list) => {
|
|
145
326
|
let rec iter = (fn, list, index) => {
|
|
146
327
|
match (list) {
|
|
147
328
|
[] => [],
|
|
@@ -153,7 +334,18 @@ let filteri = (fn, list) => {
|
|
|
153
334
|
iter(fn, list, 0)
|
|
154
335
|
}
|
|
155
336
|
|
|
156
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Produces a new list by calling a function on each element of
|
|
339
|
+
* the input list and excluding it from the result list if the element satisfies
|
|
340
|
+
* the condition.
|
|
341
|
+
*
|
|
342
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
343
|
+
* @param list: The list to iterate
|
|
344
|
+
* @returns The new list containing elements where `fn` returned `false`
|
|
345
|
+
*
|
|
346
|
+
* @since v0.1.0
|
|
347
|
+
*/
|
|
348
|
+
export let rec reject = (fn, list) => {
|
|
157
349
|
match (list) {
|
|
158
350
|
[] => [],
|
|
159
351
|
[first, ...rest] =>
|
|
@@ -161,21 +353,57 @@ let rec reject = (fn, list) => {
|
|
|
161
353
|
}
|
|
162
354
|
}
|
|
163
355
|
|
|
164
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Provides `Some(element)` containing the first element, or "head", of
|
|
358
|
+
* the input list or `None` if the list is empty.
|
|
359
|
+
*
|
|
360
|
+
* @param list: The list to access
|
|
361
|
+
* @returns `Some(firstElement)` if the list has elements or `None` otherwise
|
|
362
|
+
*
|
|
363
|
+
* @since v0.2.0
|
|
364
|
+
* @history v0.1.0: Originally named `hd`
|
|
365
|
+
* @history v0.2.0: Renamed to `head`
|
|
366
|
+
* @history v0.3.0: Return type converted to `Option` type
|
|
367
|
+
*/
|
|
368
|
+
export let head = list => {
|
|
165
369
|
match (list) {
|
|
166
370
|
[] => None,
|
|
167
371
|
[first, ..._] => Some(first),
|
|
168
372
|
}
|
|
169
373
|
}
|
|
170
374
|
|
|
171
|
-
|
|
375
|
+
/**
|
|
376
|
+
* Provides `Some(tail)` containing all list items except the first element, or "tail", of
|
|
377
|
+
* the input list or `None` if the list is empty.
|
|
378
|
+
*
|
|
379
|
+
* @param list: The list to access
|
|
380
|
+
* @returns `Some(tail)` if the list has elements or `None` otherwise
|
|
381
|
+
*
|
|
382
|
+
* @since v0.2.0
|
|
383
|
+
* @history v0.1.0: Originally named `tl`
|
|
384
|
+
* @history v0.2.0: Renamed to `tail`
|
|
385
|
+
* @history v0.3.0: Return type converted to `Option` type
|
|
386
|
+
*/
|
|
387
|
+
export let tail = list => {
|
|
172
388
|
match (list) {
|
|
173
389
|
[] => None,
|
|
174
390
|
[_, ...rest] => Some(rest),
|
|
175
391
|
}
|
|
176
392
|
}
|
|
177
393
|
|
|
178
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Provides `Some(element)` containing the element in the list at the specified index
|
|
396
|
+
* or `None` if the index is out-of-bounds or the list is empty.
|
|
397
|
+
*
|
|
398
|
+
* @param index: The index to access
|
|
399
|
+
* @param list: The list to access
|
|
400
|
+
* @returns `Some(element)` if the list contains an element at the index or `None` otherwise
|
|
401
|
+
*
|
|
402
|
+
* @since v0.1.0
|
|
403
|
+
* @history v0.1.0: Originally failed for index out-of-bounds or list empty
|
|
404
|
+
* @history v0.3.0: Return type converted to `Option` type
|
|
405
|
+
*/
|
|
406
|
+
export let rec nth = (index, list) => {
|
|
179
407
|
if (index < 0) {
|
|
180
408
|
None
|
|
181
409
|
} else {
|
|
@@ -186,14 +414,35 @@ let rec nth = (index, list) => {
|
|
|
186
414
|
}
|
|
187
415
|
}
|
|
188
416
|
|
|
189
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Flattens nested lists.
|
|
419
|
+
*
|
|
420
|
+
* @param list: The list to flatten
|
|
421
|
+
* @returns A new list containing all nested list elements combined
|
|
422
|
+
*
|
|
423
|
+
* @example List.flatten([[1, 2], [3, 4]]) // [1, 2, 3, 4]
|
|
424
|
+
*
|
|
425
|
+
* @since v0.1.0
|
|
426
|
+
*/
|
|
427
|
+
export let rec flatten = list => {
|
|
190
428
|
match (list) {
|
|
191
429
|
[] => [],
|
|
192
430
|
[first, ...rest] => append(first, flatten(rest)),
|
|
193
431
|
}
|
|
194
432
|
}
|
|
195
433
|
|
|
196
|
-
|
|
434
|
+
/**
|
|
435
|
+
* Inserts a new value into a list at the specified index.
|
|
436
|
+
* Fails if the index is out-of-bounds.
|
|
437
|
+
*
|
|
438
|
+
* @param value: The value to insert
|
|
439
|
+
* @param index: The index to update
|
|
440
|
+
* @param list: The list to update
|
|
441
|
+
* @returns The new list
|
|
442
|
+
*
|
|
443
|
+
* @since v0.1.0
|
|
444
|
+
*/
|
|
445
|
+
export let rec insert = (value, index, list) => {
|
|
197
446
|
if (index < 0) {
|
|
198
447
|
fail "insert index cannot be a negative number"
|
|
199
448
|
} else {
|
|
@@ -206,7 +455,17 @@ let rec insert = (value, index, list) => {
|
|
|
206
455
|
}
|
|
207
456
|
}
|
|
208
457
|
|
|
209
|
-
|
|
458
|
+
/**
|
|
459
|
+
* Counts the number of elements in a list that satisfy the given condition.
|
|
460
|
+
*
|
|
461
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
462
|
+
* @param list: The list to iterate
|
|
463
|
+
* @returns The total number of elements that satisfy the condition
|
|
464
|
+
*
|
|
465
|
+
* @since v0.1.0
|
|
466
|
+
* @history v0.2.0: Made the function tail-recursive
|
|
467
|
+
*/
|
|
468
|
+
export let count = (fn, list) => {
|
|
210
469
|
let rec iter = (n, list) => {
|
|
211
470
|
match (list) {
|
|
212
471
|
[] => n,
|
|
@@ -216,7 +475,17 @@ let count = (fn, list) => {
|
|
|
216
475
|
iter(0, list)
|
|
217
476
|
}
|
|
218
477
|
|
|
219
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Split a list into two, with the first list containing the required number of elements.
|
|
480
|
+
* Fails if the input list doesn't contain at least the required amount of elements.
|
|
481
|
+
*
|
|
482
|
+
* @param count: The number of elements required
|
|
483
|
+
* @param list: The list to split
|
|
484
|
+
* @returns Two lists where the first contains exactly the required amount of elements and the second contains any remaining elements
|
|
485
|
+
*
|
|
486
|
+
* @since v0.1.0
|
|
487
|
+
*/
|
|
488
|
+
export let part = (count, list) => {
|
|
220
489
|
if (count < 0) {
|
|
221
490
|
fail "part count cannot be a negative number"
|
|
222
491
|
} else {
|
|
@@ -234,13 +503,40 @@ let part = (count, list) => {
|
|
|
234
503
|
}
|
|
235
504
|
}
|
|
236
505
|
|
|
237
|
-
|
|
506
|
+
/**
|
|
507
|
+
* Rotates list elements by the specified amount to the left.
|
|
508
|
+
*
|
|
509
|
+
* If value is negative, list elements will be rotated by the
|
|
510
|
+
* specified amount to the right. See examples.
|
|
511
|
+
*
|
|
512
|
+
* Fails if the input list doesn't contain at least the required amount of elements.
|
|
513
|
+
*
|
|
514
|
+
* @param count: The number of elements to rotate by
|
|
515
|
+
* @param list: The list to be rotated
|
|
516
|
+
*
|
|
517
|
+
* @example List.rotate(2, [1, 2, 3, 4, 5]) // [3, 4, 5, 1, 2]
|
|
518
|
+
* @example List.rotate(-1, [1, 2, 3, 4, 5]) // [5, 1, 2, 3, 4]
|
|
519
|
+
*
|
|
520
|
+
* @since v0.1.0
|
|
521
|
+
*/
|
|
522
|
+
export let rotate = (count, list) => {
|
|
238
523
|
let (beginning, end) = if (count >= 0) part(count, list)
|
|
239
524
|
else part(length(list) + count, list)
|
|
240
525
|
append(end, beginning)
|
|
241
526
|
}
|
|
242
527
|
|
|
243
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Produces a new list with any duplicates removed.
|
|
530
|
+
* Uses the generic `==` structural equality operator.
|
|
531
|
+
*
|
|
532
|
+
* @param list: The list to filter
|
|
533
|
+
* @returns The new list with only unique values
|
|
534
|
+
*
|
|
535
|
+
* @since v0.2.0
|
|
536
|
+
* @history v0.1.0: Originally named `uniq`
|
|
537
|
+
* @history v0.2.0: Renamed to `unique`
|
|
538
|
+
*/
|
|
539
|
+
export let unique = list => {
|
|
244
540
|
let rec iter = (list, acc) => {
|
|
245
541
|
match (list) {
|
|
246
542
|
[] => reverse(acc),
|
|
@@ -252,11 +548,23 @@ let unique = list => {
|
|
|
252
548
|
iter(list, [])
|
|
253
549
|
}
|
|
254
550
|
|
|
255
|
-
|
|
256
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Produces a new list with the specified number of elements removed from
|
|
553
|
+
* the beginning of the input list.
|
|
554
|
+
*
|
|
555
|
+
* Fails if the specified amount is a negative number.
|
|
556
|
+
*
|
|
557
|
+
* @param count: The amount of elements to remove
|
|
558
|
+
* @param list: The input list
|
|
559
|
+
* @returns The new list without the dropped elements
|
|
560
|
+
*
|
|
561
|
+
* @since v0.2.0
|
|
562
|
+
*/
|
|
563
|
+
export let rec drop = (count, list) => {
|
|
564
|
+
if (count < 0) {
|
|
257
565
|
fail "number of items to drop cannot be a negative number"
|
|
258
566
|
} else {
|
|
259
|
-
match ((
|
|
567
|
+
match ((count, list)) {
|
|
260
568
|
(_, []) => [],
|
|
261
569
|
(n, _) when n == 0 => list,
|
|
262
570
|
(n, [first, ...rest]) => drop(n - 1, rest),
|
|
@@ -264,18 +572,41 @@ let rec drop = (n, list) => {
|
|
|
264
572
|
}
|
|
265
573
|
}
|
|
266
574
|
|
|
267
|
-
|
|
575
|
+
/**
|
|
576
|
+
* Produces a new list with the elements removed from the beginning
|
|
577
|
+
* of the input list until they no longer satisfy the given condition.
|
|
578
|
+
* Stops when the predicate function returns `false`.
|
|
579
|
+
*
|
|
580
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
581
|
+
* @param list: The input list
|
|
582
|
+
* @returns The new list without the dropped elements
|
|
583
|
+
*
|
|
584
|
+
* @since v0.2.0
|
|
585
|
+
*/
|
|
586
|
+
export let rec dropWhile = (fn, list) => {
|
|
268
587
|
match (list) {
|
|
269
588
|
[] => list,
|
|
270
589
|
[first, ...rest] => if (fn(first)) dropWhile(fn, rest) else list,
|
|
271
590
|
}
|
|
272
591
|
}
|
|
273
592
|
|
|
274
|
-
|
|
275
|
-
|
|
593
|
+
/**
|
|
594
|
+
* Produces a new list with–at most—the specified amount elements from
|
|
595
|
+
* the beginning of the input list.
|
|
596
|
+
*
|
|
597
|
+
* Fails if the specified amount is a negative number.
|
|
598
|
+
*
|
|
599
|
+
* @param count: The amount of elements to keep
|
|
600
|
+
* @param list: The input list
|
|
601
|
+
* @returns The new list containing the taken elements
|
|
602
|
+
*
|
|
603
|
+
* @since v0.2.0
|
|
604
|
+
*/
|
|
605
|
+
export let rec take = (count, list) => {
|
|
606
|
+
if (count < 0) {
|
|
276
607
|
fail "number of items to take cannot be a negative number"
|
|
277
608
|
} else {
|
|
278
|
-
match ((
|
|
609
|
+
match ((count, list)) {
|
|
279
610
|
(_, []) => list,
|
|
280
611
|
(n, _) when n == 0 => [],
|
|
281
612
|
(n, [first, ...rest]) => [first, ...take(n - 1, rest)],
|
|
@@ -283,21 +614,54 @@ let rec take = (n, list) => {
|
|
|
283
614
|
}
|
|
284
615
|
}
|
|
285
616
|
|
|
286
|
-
|
|
617
|
+
/**
|
|
618
|
+
* Produces a new list with elements from the beginning of the input list
|
|
619
|
+
* as long as they satisfy the given condition.
|
|
620
|
+
* Stops when the predicate function returns `false`.
|
|
621
|
+
*
|
|
622
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
623
|
+
* @param list: The input list
|
|
624
|
+
* @returns The new list containing the taken elements
|
|
625
|
+
*
|
|
626
|
+
* @since v0.2.0
|
|
627
|
+
*/
|
|
628
|
+
export let rec takeWhile = (fn, list) => {
|
|
287
629
|
match (list) {
|
|
288
630
|
[] => [],
|
|
289
|
-
[first, ...rest] => if (
|
|
631
|
+
[first, ...rest] => if (fn(first)) [first, ...takeWhile(fn, rest)] else [],
|
|
290
632
|
}
|
|
291
633
|
}
|
|
292
634
|
|
|
293
|
-
|
|
635
|
+
/**
|
|
636
|
+
* Finds the first element in a list that satifies the given condition.
|
|
637
|
+
*
|
|
638
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
639
|
+
* @param list: The list to search
|
|
640
|
+
* @returns `Some(element)` containing the first value found or `None` otherwise
|
|
641
|
+
*
|
|
642
|
+
* @since v0.2.0
|
|
643
|
+
* @history v0.2.0: Originally failed if the list was empty
|
|
644
|
+
* @history v0.3.0: Return type converted to `Option` type
|
|
645
|
+
*/
|
|
646
|
+
export let rec find = (fn, list) => {
|
|
294
647
|
match (list) {
|
|
295
648
|
[] => None,
|
|
296
649
|
[first, ...rest] => if (fn(first)) Some(first) else find(fn, rest),
|
|
297
650
|
}
|
|
298
651
|
}
|
|
299
652
|
|
|
300
|
-
|
|
653
|
+
/**
|
|
654
|
+
* Finds the first index in a list where the element satifies the given condition.
|
|
655
|
+
*
|
|
656
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
657
|
+
* @param list: The list to search
|
|
658
|
+
* @returns `Some(index)` containing the index of the first element found or `None` otherwise
|
|
659
|
+
*
|
|
660
|
+
* @since v0.2.0
|
|
661
|
+
* @history v0.2.0: Originally failed if the list was empty
|
|
662
|
+
* @history v0.3.0: Return type converted to `Option` type
|
|
663
|
+
*/
|
|
664
|
+
export let findIndex = (fn, list) => {
|
|
301
665
|
let rec findItemIndex = (l, index) => {
|
|
302
666
|
match (l) {
|
|
303
667
|
[] => None,
|
|
@@ -308,25 +672,54 @@ let findIndex = (fn, list) => {
|
|
|
308
672
|
findItemIndex(list, 0)
|
|
309
673
|
}
|
|
310
674
|
|
|
311
|
-
|
|
675
|
+
/**
|
|
676
|
+
* Combines two lists into a Cartesian product of tuples containing
|
|
677
|
+
* all ordered pairs `(a, b)`.
|
|
678
|
+
*
|
|
679
|
+
* @param list1: The list to provide values for the first tuple element
|
|
680
|
+
* @param list2: The list to provide values for the second tuple element
|
|
681
|
+
* @returns The new list containing all pairs of `(a, b)`
|
|
682
|
+
*
|
|
683
|
+
* @since v0.2.0
|
|
684
|
+
*/
|
|
685
|
+
export let product = (list1, list2) => {
|
|
312
686
|
let mut list = []
|
|
313
687
|
forEach(aItem => {
|
|
314
688
|
forEach(bItem => {
|
|
315
689
|
list = [(aItem, bItem), ...list]
|
|
316
|
-
},
|
|
317
|
-
},
|
|
690
|
+
}, list2)
|
|
691
|
+
}, list1)
|
|
318
692
|
reverse(list)
|
|
319
693
|
}
|
|
320
694
|
|
|
321
|
-
|
|
695
|
+
/**
|
|
696
|
+
* Provides the subset of a list given zero-based start index and amount of elements
|
|
697
|
+
* to include.
|
|
698
|
+
*
|
|
699
|
+
* Fails if the start index or amount of elements are negative numbers.
|
|
700
|
+
*
|
|
701
|
+
* @param start: The index of the list where the subset will begin (inclusive)
|
|
702
|
+
* @param length: The amount of elements to be included in the subset
|
|
703
|
+
* @param list: The input list
|
|
704
|
+
* @returns The subset of the list
|
|
705
|
+
*
|
|
706
|
+
* @since v0.2.0
|
|
707
|
+
*/
|
|
708
|
+
export let sub = (start, length, list) => {
|
|
322
709
|
take(length, drop(start, list))
|
|
323
710
|
}
|
|
324
711
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
712
|
+
/**
|
|
713
|
+
* Combine the given list of strings into one string with the specified
|
|
714
|
+
* separator inserted between each item.
|
|
715
|
+
*
|
|
716
|
+
* @param separator: The separator to insert between elements
|
|
717
|
+
* @param list: The list to combine
|
|
718
|
+
* @returns The combined elements with the separator between each
|
|
719
|
+
*
|
|
720
|
+
* @since v0.4.0
|
|
721
|
+
*/
|
|
722
|
+
export let join = (separator: String, list: List<String>) => {
|
|
330
723
|
let rec iter = (sep, acc, rem) => {
|
|
331
724
|
match (rem) {
|
|
332
725
|
[] => acc,
|
|
@@ -341,7 +734,7 @@ let join = (separator: String, items: List<String>) => {
|
|
|
341
734
|
}
|
|
342
735
|
|
|
343
736
|
// Reverse and reduce to take advantage of TCE
|
|
344
|
-
match (iter(separator, None, reverse(
|
|
737
|
+
match (iter(separator, None, reverse(list))) {
|
|
345
738
|
None => "",
|
|
346
739
|
Some(s) => s,
|
|
347
740
|
}
|
|
@@ -349,12 +742,14 @@ let join = (separator: String, items: List<String>) => {
|
|
|
349
742
|
|
|
350
743
|
/**
|
|
351
744
|
* Reverses the first list and appends the second list to the end.
|
|
352
|
-
*
|
|
745
|
+
*
|
|
353
746
|
* @param list1: The list to reverse
|
|
354
747
|
* @param list2: The list to append
|
|
748
|
+
* @returns The new list
|
|
749
|
+
*
|
|
355
750
|
* @since v0.4.5
|
|
356
751
|
*/
|
|
357
|
-
let rec revAppend = (list1, list2) => {
|
|
752
|
+
export let rec revAppend = (list1, list2) => {
|
|
358
753
|
match (list1) {
|
|
359
754
|
[hd, ...tl] => revAppend(tl, [hd, ...list2]),
|
|
360
755
|
[] => list2,
|
|
@@ -363,13 +758,15 @@ let rec revAppend = (list1, list2) => {
|
|
|
363
758
|
|
|
364
759
|
/**
|
|
365
760
|
* Sorts the given list based on a given comparator function. The resulting list is sorted in increasing order.
|
|
366
|
-
*
|
|
761
|
+
*
|
|
367
762
|
* Ordering is calculated using a comparator function which takes two list elements and must return 0 if both are equal, a positive number if the first is greater, and a negative number if the first is smaller.
|
|
368
763
|
* @param comp: The comparator function used to indicate sort order
|
|
369
764
|
* @param list: The list to be sorted
|
|
765
|
+
* @returns The sorted list
|
|
766
|
+
*
|
|
370
767
|
* @since v0.4.5
|
|
371
768
|
*/
|
|
372
|
-
let sort = (comp, list) => {
|
|
769
|
+
export let sort = (comp, list) => {
|
|
373
770
|
let rec merge = (left, right, list) => {
|
|
374
771
|
match ((left, right)) {
|
|
375
772
|
(_, []) => {
|