@grain/stdlib 0.5.3 → 0.5.5

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/array.gr +65 -57
  3. package/array.md +54 -6
  4. package/buffer.gr +71 -1
  5. package/buffer.md +142 -0
  6. package/bytes.gr +52 -3
  7. package/bytes.md +117 -0
  8. package/char.gr +23 -20
  9. package/char.md +18 -3
  10. package/immutablemap.gr +493 -0
  11. package/immutablemap.md +479 -0
  12. package/immutablepriorityqueue.gr +44 -16
  13. package/immutablepriorityqueue.md +44 -1
  14. package/immutableset.gr +498 -0
  15. package/immutableset.md +449 -0
  16. package/int32.gr +39 -37
  17. package/int32.md +6 -0
  18. package/int64.gr +39 -37
  19. package/int64.md +6 -0
  20. package/list.gr +33 -24
  21. package/list.md +39 -10
  22. package/map.gr +19 -28
  23. package/marshal.gr +4 -4
  24. package/number.gr +727 -26
  25. package/number.md +345 -23
  26. package/option.gr +30 -26
  27. package/option.md +12 -0
  28. package/package.json +1 -1
  29. package/path.gr +787 -0
  30. package/path.md +727 -0
  31. package/pervasives.gr +3 -4
  32. package/pervasives.md +6 -1
  33. package/priorityqueue.gr +25 -5
  34. package/priorityqueue.md +30 -0
  35. package/queue.gr +22 -7
  36. package/queue.md +18 -1
  37. package/regex.gr +161 -65
  38. package/regex.md +70 -0
  39. package/result.gr +24 -20
  40. package/result.md +12 -0
  41. package/runtime/atof/common.gr +198 -0
  42. package/runtime/atof/common.md +243 -0
  43. package/runtime/atof/decimal.gr +663 -0
  44. package/runtime/atof/decimal.md +59 -0
  45. package/runtime/atof/lemire.gr +264 -0
  46. package/runtime/atof/lemire.md +6 -0
  47. package/runtime/atof/parse.gr +615 -0
  48. package/runtime/atof/parse.md +12 -0
  49. package/runtime/atof/slow.gr +238 -0
  50. package/runtime/atof/slow.md +6 -0
  51. package/runtime/atof/table.gr +2016 -0
  52. package/runtime/atof/table.md +12 -0
  53. package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
  54. package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
  55. package/runtime/bigint.gr +7 -7
  56. package/runtime/compare.gr +2 -1
  57. package/runtime/equal.gr +3 -2
  58. package/runtime/exception.gr +9 -5
  59. package/runtime/exception.md +8 -2
  60. package/runtime/gc.gr +2 -1
  61. package/runtime/malloc.gr +1 -3
  62. package/runtime/numberUtils.gr +13 -13
  63. package/runtime/numberUtils.md +6 -0
  64. package/runtime/numbers.gr +123 -39
  65. package/runtime/numbers.md +26 -0
  66. package/runtime/string.gr +4 -2
  67. package/runtime/unsafe/conv.gr +21 -41
  68. package/runtime/unsafe/conv.md +0 -3
  69. package/runtime/unsafe/printWasm.gr +4 -40
  70. package/runtime/utils/printing.gr +3 -3
  71. package/set.gr +25 -25
  72. package/stack.gr +14 -0
  73. package/stack.md +17 -0
  74. package/string.gr +313 -39
  75. package/string.md +99 -0
  76. package/sys/file.gr +1 -1
  77. package/sys/time.gr +4 -4
package/char.gr CHANGED
@@ -4,7 +4,7 @@
4
4
  * The Char type represents a single [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value).
5
5
  *
6
6
  * @example import Char from "char"
7
- *
7
+ *
8
8
  * @since 0.3.0
9
9
  */
10
10
 
@@ -26,37 +26,37 @@ exception MalformedUtf8
26
26
 
27
27
  /**
28
28
  * The minimum valid Unicode scalar value.
29
- *
29
+ *
30
30
  * @since 0.3.0
31
31
  */
32
32
  export let min = 0x0000
33
33
  /**
34
34
  * The maximum valid Unicode scalar value.
35
- *
35
+ *
36
36
  * @since 0.3.0
37
37
  */
38
38
  export let max = 0x10FFFF
39
39
 
40
40
  /**
41
41
  * Determines whether the given character code is a valid Unicode scalar value.
42
- *
42
+ *
43
43
  * @param charCode: The number to check
44
44
  * @returns `true` if the number refers to a valid Unicode scalar value or `false` otherwise
45
- *
45
+ *
46
46
  * @since 0.3.0
47
47
  */
48
48
  export let isValid = charCode => {
49
49
  charCode >= min &&
50
- (charCode <= 0xD7FF || charCode >= 0xE000) &&
51
- charCode <= max
50
+ (charCode <= 0xD7FF || charCode >= 0xE000) &&
51
+ charCode <= max
52
52
  }
53
53
 
54
54
  /**
55
55
  * Determines the Unicode scalar value for a character.
56
- *
56
+ *
57
57
  * @param char: The character
58
58
  * @returns The Unicode scalar value for the given character
59
- *
59
+ *
60
60
  * @since 0.3.0
61
61
  */
62
62
  @unsafe
@@ -70,11 +70,12 @@ export let code = (char: Char) => {
70
70
 
71
71
  /**
72
72
  * Creates a character from the given Unicode scalar value.
73
- * Throws an exception if the Unicode scalar value is invalid.
74
- *
73
+ *
75
74
  * @param usv: The Unicode scalar value
76
75
  * @returns The character for the given Unicode scalar value
77
- *
76
+ *
77
+ * @throws InvalidArgument(String): When the Unicode scalar value is invalid
78
+ *
78
79
  * @since 0.3.0
79
80
  */
80
81
  @unsafe
@@ -101,11 +102,12 @@ export let fromCode = (usv: Number) => {
101
102
 
102
103
  /**
103
104
  * Returns the next valid character by Unicode scalar value.
104
- * Throws if the input character is the max valid Unicode scalar value.
105
- *
105
+ *
106
106
  * @param char: The character
107
107
  * @returns The next valid character by Unicode scalar value
108
- *
108
+ *
109
+ * @throws Failure(String): When the input character is the maximum valid Unicode scalar value
110
+ *
109
111
  * @since 0.3.0
110
112
  */
111
113
  export let succ = char => {
@@ -121,11 +123,12 @@ export let succ = char => {
121
123
 
122
124
  /**
123
125
  * Returns the previous valid character by Unicode scalar value.
124
- * Throws if the input character is the min valid Unicode scalar value.
125
- *
126
+ *
126
127
  * @param char: The character
127
128
  * @returns The previous valid character by Unicode scalar value
128
- *
129
+ *
130
+ * @throws Failure(String): When the input character is the minimum valid Unicode scalar value
131
+ *
129
132
  * @since 0.3.0
130
133
  */
131
134
  export let pred = char => {
@@ -141,10 +144,10 @@ export let pred = char => {
141
144
 
142
145
  /**
143
146
  * Converts the given character to a string.
144
- *
147
+ *
145
148
  * @param char: The character to convert
146
149
  * @returns A string containing the given character
147
- *
150
+ *
148
151
  * @since 0.3.0
149
152
  */
150
153
  @unsafe
package/char.md CHANGED
@@ -107,7 +107,6 @@ fromCode : Number -> Char
107
107
  ```
108
108
 
109
109
  Creates a character from the given Unicode scalar value.
110
- Throws an exception if the Unicode scalar value is invalid.
111
110
 
112
111
  Parameters:
113
112
 
@@ -121,6 +120,12 @@ Returns:
121
120
  |----|-----------|
122
121
  |`Char`|The character for the given Unicode scalar value|
123
122
 
123
+ Throws:
124
+
125
+ `InvalidArgument(String)`
126
+
127
+ * When the Unicode scalar value is invalid
128
+
124
129
  ### Char.**succ**
125
130
 
126
131
  <details disabled>
@@ -133,7 +138,6 @@ succ : Char -> Char
133
138
  ```
134
139
 
135
140
  Returns the next valid character by Unicode scalar value.
136
- Throws if the input character is the max valid Unicode scalar value.
137
141
 
138
142
  Parameters:
139
143
 
@@ -147,6 +151,12 @@ Returns:
147
151
  |----|-----------|
148
152
  |`Char`|The next valid character by Unicode scalar value|
149
153
 
154
+ Throws:
155
+
156
+ `Failure(String)`
157
+
158
+ * When the input character is the maximum valid Unicode scalar value
159
+
150
160
  ### Char.**pred**
151
161
 
152
162
  <details disabled>
@@ -159,7 +169,6 @@ pred : Char -> Char
159
169
  ```
160
170
 
161
171
  Returns the previous valid character by Unicode scalar value.
162
- Throws if the input character is the min valid Unicode scalar value.
163
172
 
164
173
  Parameters:
165
174
 
@@ -173,6 +182,12 @@ Returns:
173
182
  |----|-----------|
174
183
  |`Char`|The previous valid character by Unicode scalar value|
175
184
 
185
+ Throws:
186
+
187
+ `Failure(String)`
188
+
189
+ * When the input character is the minimum valid Unicode scalar value
190
+
176
191
  ### Char.**toString**
177
192
 
178
193
  <details disabled>
@@ -0,0 +1,493 @@
1
+ /**
2
+ * @module ImmutableMap: An ImmutableMap holds key-value pairs. Any value may be used as a key or value. Operations on an ImmutableMap do not mutate the map's internal state.
3
+ * @example import ImmutableMap from "immutablemap"
4
+ *
5
+ * @since v0.5.4
6
+ */
7
+
8
+ import List from "list"
9
+ import Array from "array"
10
+ import Option from "option"
11
+
12
+ // implementation based on the paper "Implementing Sets Efficiently in a
13
+ // Functional Language" by Stephen Adams
14
+ record Node<k, v> {
15
+ key: k,
16
+ val: v,
17
+ size: Number,
18
+ left: ImmutableMap<k, v>,
19
+ right: ImmutableMap<k, v>,
20
+ },
21
+ /**
22
+ * @section Types: Type declarations included in the ImmutableMap module.
23
+ */
24
+ enum ImmutableMap<k, v> {
25
+ Empty,
26
+ Tree(Node<k, v>),
27
+ }
28
+
29
+ /**
30
+ * @section Values: Functions and constants for working with ImmutableMaps.
31
+ */
32
+
33
+ // semi-arbitrary value chosen for algorithm for determining when to balance
34
+ // trees; no tree can have a left subtree containing this number of times
35
+ // more elements than its right subtree or vice versa
36
+ let weight = 4
37
+
38
+ /**
39
+ * An empty map
40
+ *
41
+ * @since v0.5.4
42
+ */
43
+ export let empty = Empty
44
+
45
+ // returns the key-value pair of the minimum key in a tree
46
+ let rec min = node => {
47
+ match (node) {
48
+ Tree({ key, val, left: Empty, _ }) => (key, val),
49
+ Tree({ left, _ }) => min(left),
50
+ Empty => fail "Impossible: min of empty element in ImmutableMap",
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Provides the count of key-value pairs stored within the map.
56
+ *
57
+ * @param map: The map to inspect
58
+ * @returns The count of key-value pairs in the map
59
+ *
60
+ * @since v0.5.4
61
+ */
62
+ export let size = map => {
63
+ match (map) {
64
+ Empty => 0,
65
+ Tree({ size, _ }) => size,
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Determines if the map contains no key-value pairs.
71
+ *
72
+ * @param map: The map to inspect
73
+ * @returns `true` if the given map is empty or `false` otherwise
74
+ *
75
+ * @since v0.5.4
76
+ */
77
+ export let isEmpty = map => {
78
+ match (map) {
79
+ Empty => true,
80
+ Tree(_) => false,
81
+ }
82
+ }
83
+
84
+ let unwrapTree = node => {
85
+ match (node) {
86
+ Empty => fail "Impossible: ImmutableMap unwrapTree got an empty tree node",
87
+ Tree(tree) => tree,
88
+ }
89
+ }
90
+
91
+ // helper function for creating a tree node with correct size from
92
+ // two balanced trees
93
+ let makeNode = (key, val, left, right) => {
94
+ Tree({ key, val, size: 1 + size(left) + size(right), left, right })
95
+ }
96
+
97
+ // note: see Figure 1 of paper referenced above for visual illustration of
98
+ // the rotations below
99
+
100
+ // node rotation moving the left subtree of the right node to the left side
101
+ let singleL = (key, val, left, right) => {
102
+ let { key: rKey, val: rVal, left: rl, right: rr, _ } = unwrapTree(right)
103
+ makeNode(rKey, rVal, makeNode(key, val, left, rl), rr)
104
+ }
105
+
106
+ // node rotation moving left child of right tree to the root
107
+ let doubleL = (key, val, left, right) => {
108
+ let { key: rKey, val: rVal, left: rl, right: rr, _ } = unwrapTree(right)
109
+ let { key: rlKey, val: rlVal, left: rll, right: rlr, _ } = unwrapTree(rl)
110
+ makeNode(
111
+ rlKey,
112
+ rlVal,
113
+ makeNode(key, val, left, rll),
114
+ makeNode(rKey, rVal, rlr, rr)
115
+ )
116
+ }
117
+
118
+ // node rotation moving the right subtree of the left node to the right side
119
+ let singleR = (key, val, left, right) => {
120
+ let { key: lKey, val: lVal, left: ll, right: lr, _ } = unwrapTree(left)
121
+ makeNode(lKey, lVal, ll, makeNode(key, val, lr, right))
122
+ }
123
+
124
+ // node rotation moving right child of left tree to the root
125
+ let doubleR = (key, val, left, right) => {
126
+ let { key: lKey, val: lVal, left: ll, right: lr, _ } = unwrapTree(left)
127
+ let { key: lrKey, val: lrVal, left: lrl, right: lrr, _ } = unwrapTree(lr)
128
+ makeNode(
129
+ lrKey,
130
+ lrVal,
131
+ makeNode(lKey, lVal, ll, lrl),
132
+ makeNode(key, val, lrr, right)
133
+ )
134
+ }
135
+
136
+ // creates a new node after either the left or right trees have just had an
137
+ // element inserted or removed from them, maintaining balance in the tree
138
+ let balancedNode = (key, val, left, right) => {
139
+ let makeNodeFn = if (size(left) + size(right) < 2) {
140
+ makeNode
141
+ } else if (size(right) > weight * size(left)) {
142
+ // if the right tree is too much larger than the left then move part of
143
+ // the right tree to the left side
144
+ let { left: rl, right: rr, _ } = unwrapTree(right)
145
+ if (size(rl) < size(rr)) singleL else doubleL
146
+ } else if (size(left) > weight * size(right)) {
147
+ // if the left tree is too much larger than the right then move part of
148
+ // the left tree to the right side
149
+ let { left: ll, right: lr, _ } = unwrapTree(left)
150
+ if (size(lr) < size(ll)) singleR else doubleR
151
+ } else {
152
+ // if neither tree is too much larger than the other then simply create
153
+ // a new node
154
+ makeNode
155
+ }
156
+
157
+ makeNodeFn(key, val, left, right)
158
+ }
159
+
160
+ /**
161
+ * Produces a new map containing a new key-value pair. If the key already exists in the map, the value is replaced.
162
+ *
163
+ * @param key: The unique key in the map
164
+ * @param value: The value to store
165
+ * @param map: The base map
166
+ * @returns A new map containing the new key-value pair
167
+ *
168
+ * @since v0.5.4
169
+ */
170
+ export let rec set = (key, val, map) => {
171
+ match (map) {
172
+ Empty => Tree({ key, val, size: 1, left: Empty, right: Empty }),
173
+ Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
174
+ match (compare(key, nodeKey)) {
175
+ cmp when cmp < 0 =>
176
+ balancedNode(nodeKey, nodeVal, set(key, val, left), right),
177
+ cmp when cmp > 0 =>
178
+ balancedNode(nodeKey, nodeVal, left, set(key, val, right)),
179
+ _ => makeNode(key, val, left, right),
180
+ }
181
+ },
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Retrieves the value for the given key.
187
+ *
188
+ * @param key: The key to access
189
+ * @param map: The map to access
190
+ * @returns `Some(value)` if the key exists in the map or `None` otherwise
191
+ *
192
+ * @since v0.5.4
193
+ */
194
+ export let rec get = (key, map) => {
195
+ match (map) {
196
+ Empty => None,
197
+ Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
198
+ match (compare(key, nodeKey)) {
199
+ cmp when cmp < 0 => get(key, left),
200
+ cmp when cmp > 0 => get(key, right),
201
+ _ => Some(nodeVal),
202
+ }
203
+ },
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Determines if the map contains the given key. In such a case, it will always contain a value for the given key.
209
+ *
210
+ * @param key: The key to search for
211
+ * @param map: The map to search
212
+ * @returns `true` if the map contains the given key or `false` otherwise
213
+ *
214
+ * @since v0.5.4
215
+ */
216
+ export let rec contains = (key, map) => {
217
+ Option.isSome(get(key, map))
218
+ }
219
+
220
+ // removes the minimum element from a tree
221
+ let rec removeMin = node => {
222
+ match (node) {
223
+ Tree({ left: Empty, right, _ }) => right,
224
+ Tree({ key, val, left, right, _ }) =>
225
+ balancedNode(key, val, removeMin(left), right),
226
+ _ => fail "Impossible: ImmutableMap removeMin on empty node",
227
+ }
228
+ }
229
+
230
+ // helper function for removing a node by creating a new node containing the
231
+ // removed node's left and right subtrees
232
+ let removeInner = (left, right) => {
233
+ match ((left, right)) {
234
+ (Empty, node) | (node, Empty) => node,
235
+ (left, right) => {
236
+ let (minKey, minVal) = min(right)
237
+ balancedNode(minKey, minVal, left, removeMin(right))
238
+ },
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Produces a new map without the key-value pair corresponding to the given
244
+ * key. If the key doesn't exist in the map, the map will be returned unmodified.
245
+ *
246
+ * @param key: The key to exclude
247
+ * @param map: The map to exclude from
248
+ * @returns A new map without the given key
249
+ *
250
+ * @since v0.5.4
251
+ */
252
+ export let rec remove = (key, map) => {
253
+ match (map) {
254
+ Empty => Empty,
255
+ Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
256
+ match (compare(key, nodeKey)) {
257
+ cmp when cmp < 0 =>
258
+ balancedNode(nodeKey, nodeVal, remove(key, left), right),
259
+ cmp when cmp > 0 =>
260
+ balancedNode(nodeKey, nodeVal, left, remove(key, right)),
261
+ _ => removeInner(left, right),
262
+ }
263
+ },
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Produces a new map by calling an updater function that receives the
269
+ * previously stored value as an `Option` and returns the new value to be
270
+ * stored as an `Option`. If the key didn't exist previously, the value
271
+ * will be `None`. If `None` is returned from the updater function, the
272
+ * key-value pair is excluded.
273
+ *
274
+ * @param key: The unique key in the map
275
+ * @param fn: The updater function
276
+ * @param map: The base map
277
+ * @returns A new map with the value at the given key modified according to the function's output
278
+ *
279
+ * @since v0.5.4
280
+ */
281
+ export let update = (key, fn, map) => {
282
+ let val = get(key, map)
283
+ match (fn(val)) {
284
+ Some(next) => set(key, next, map),
285
+ None => remove(key, map),
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Iterates the map, calling an iterator function with each key and value.
291
+ *
292
+ * @param fn: The iterator function to call with each key and value
293
+ * @param map: The map to iterate
294
+ *
295
+ * @since v0.5.4
296
+ */
297
+ export let forEach = (fn, map) => {
298
+ let rec forEachInner = node => {
299
+ match (node) {
300
+ Empty => void,
301
+ Tree({ key, val, left, right, _ }) => {
302
+ forEachInner(left)
303
+ fn(key, val): Void
304
+ forEachInner(right)
305
+ },
306
+ }
307
+ }
308
+ forEachInner(map)
309
+ }
310
+
311
+ /**
312
+ * Combines all key-value pairs of a map using a reducer function.
313
+ *
314
+ * @param fn: The reducer function to call on each key and value, where the value returned will be the next accumulator value
315
+ * @param init: The initial value to use for the accumulator on the first iteration
316
+ * @param map: The map to iterate
317
+ * @returns The final accumulator returned from `fn`
318
+ *
319
+ * @since v0.5.4
320
+ */
321
+ export let reduce = (fn, init, map) => {
322
+ let rec reduceInner = (acc, node) => {
323
+ match (node) {
324
+ Empty => acc,
325
+ Tree({ key, val, left, right, _ }) => {
326
+ let newAcc = fn(reduceInner(acc, left), key, val)
327
+ reduceInner(newAcc, right)
328
+ },
329
+ }
330
+ }
331
+ reduceInner(init, map)
332
+ }
333
+
334
+ // joins two trees with a value, preserving the BST property of left children
335
+ // being less the node and right children being greater than the node
336
+ let rec concat3 = (key, val, left, right) => {
337
+ match ((left, right)) {
338
+ (Empty, node) | (node, Empty) => set(key, val, node),
339
+ (Tree(left) as leftOpt, Tree(right) as rightOpt) => {
340
+ if (weight * left.size < right.size) {
341
+ balancedNode(
342
+ right.key,
343
+ right.val,
344
+ concat3(key, val, leftOpt, right.left),
345
+ right.right
346
+ )
347
+ } else if (weight * right.size < left.size) {
348
+ balancedNode(
349
+ left.key,
350
+ left.val,
351
+ left.left,
352
+ concat3(key, val, left.right, rightOpt)
353
+ )
354
+ } else {
355
+ makeNode(key, val, leftOpt, rightOpt)
356
+ }
357
+ },
358
+ }
359
+ }
360
+
361
+ // concatenates two trees of arbitrary size
362
+ let concat = (node1, node2) => {
363
+ match (node2) {
364
+ Empty => node1,
365
+ _ => {
366
+ let (minKey, minVal) = min(node2)
367
+ concat3(minKey, minVal, node1, removeMin(node2))
368
+ },
369
+ }
370
+ }
371
+
372
+ let reduceRight = (fn, init, map) => {
373
+ let rec reduceInner = (acc, node) => {
374
+ match (node) {
375
+ Empty => acc,
376
+ Tree({ key, val, left, right, _ }) => {
377
+ let newAcc = fn(reduceInner(acc, right), key, val)
378
+ reduceInner(newAcc, left)
379
+ },
380
+ }
381
+ }
382
+ reduceInner(init, map)
383
+ }
384
+
385
+ /**
386
+ * Enumerates all keys in the given map.
387
+ *
388
+ * @param map: The map to enumerate
389
+ * @returns A list containing all keys from the given map
390
+ *
391
+ * @since v0.5.4
392
+ */
393
+ export let keys = map => {
394
+ reduceRight((list, key, _) => [key, ...list], [], map)
395
+ }
396
+
397
+ /**
398
+ * Enumerates all values in the given map.
399
+ *
400
+ * @param map: The map to enumerate
401
+ * @returns A list containing all values from the given map
402
+ *
403
+ * @since v0.5.4
404
+ */
405
+ export let values = map => {
406
+ reduceRight((list, _, value) => [value, ...list], [], map)
407
+ }
408
+
409
+ /**
410
+ * Produces a new map excluding the key-value pairs where a predicate function returns `false`.
411
+ *
412
+ * @param fn: The predicate function to indicate which key-value pairs to exclude from the map, where returning `false` indicates the key-value pair should be excluded
413
+ * @param map: The map to iterate
414
+ * @returns A new map excluding the key-value pairs not fulfilling the predicate
415
+ *
416
+ * @since v0.5.4
417
+ */
418
+ export let filter = (fn, map) => {
419
+ let rec filterInner = node => {
420
+ match (node) {
421
+ Empty => Empty,
422
+ Tree({ key, val, left, right, _ }) => {
423
+ if (fn(key, val)) {
424
+ concat3(key, val, filterInner(left), filterInner(right))
425
+ } else {
426
+ concat(filterInner(left), filterInner(right))
427
+ }
428
+ },
429
+ }
430
+ }
431
+ filterInner(map)
432
+ }
433
+
434
+ /**
435
+ * Produces a new map excluding the key-value pairs where a predicate function returns `true`.
436
+ *
437
+ * @param fn: The predicate function to indicate which key-value pairs to exclude from the map, where returning `true` indicates the key-value pair should be excluded
438
+ * @param map: The map to iterate
439
+ * @returns A new map excluding the key-value pairs fulfilling the predicate
440
+ *
441
+ * @since v0.5.4
442
+ */
443
+ export let reject = (fn, map) => {
444
+ filter((key, val) => !fn(key, val), map)
445
+ }
446
+
447
+ /**
448
+ * Creates a map from a list.
449
+ *
450
+ * @param list: The list to convert
451
+ * @returns A map containing all key-value pairs from the list
452
+ *
453
+ * @since v0.5.4
454
+ */
455
+ export let fromList = list => {
456
+ List.reduce((map, (key, val)) => set(key, val, map), empty, list)
457
+ }
458
+
459
+ /**
460
+ * Enumerates all key-value pairs in the given map.
461
+ *
462
+ * @param map: The map to enumerate
463
+ * @returns A list containing all key-value pairs from the given map
464
+ *
465
+ * @since v0.5.4
466
+ */
467
+ export let toList = map => {
468
+ reduceRight((list, key, val) => [(key, val), ...list], [], map)
469
+ }
470
+
471
+ /**
472
+ * Creates a map from an array.
473
+ *
474
+ * @param array: The array to convert
475
+ * @returns A map containing all key-value pairs from the array
476
+ *
477
+ * @since v0.5.4
478
+ */
479
+ export let fromArray = array => {
480
+ Array.reduce((map, (key, val)) => set(key, val, map), empty, array)
481
+ }
482
+
483
+ /**
484
+ * Converts a map into an array of its key-value pairs.
485
+ *
486
+ * @param map: The map to convert
487
+ * @returns An array containing all key-value pairs from the given map
488
+ *
489
+ * @since v0.5.4
490
+ */
491
+ export let toArray = map => {
492
+ Array.fromList(toList(map))
493
+ }