@grain/stdlib 0.5.12 → 0.6.0

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 (155) hide show
  1. package/CHANGELOG.md +200 -0
  2. package/LICENSE +1 -1
  3. package/README.md +25 -2
  4. package/array.gr +1512 -199
  5. package/array.md +2032 -94
  6. package/bigint.gr +239 -140
  7. package/bigint.md +450 -106
  8. package/buffer.gr +595 -102
  9. package/buffer.md +903 -145
  10. package/bytes.gr +401 -110
  11. package/bytes.md +551 -63
  12. package/char.gr +228 -49
  13. package/char.md +373 -7
  14. package/exception.gr +26 -12
  15. package/exception.md +29 -5
  16. package/float32.gr +130 -109
  17. package/float32.md +185 -57
  18. package/float64.gr +112 -99
  19. package/float64.md +185 -57
  20. package/hash.gr +47 -37
  21. package/hash.md +21 -3
  22. package/int16.gr +430 -0
  23. package/int16.md +618 -0
  24. package/int32.gr +200 -269
  25. package/int32.md +254 -289
  26. package/int64.gr +142 -225
  27. package/int64.md +254 -289
  28. package/int8.gr +511 -0
  29. package/int8.md +786 -0
  30. package/json.gr +2084 -0
  31. package/json.md +608 -0
  32. package/list.gr +120 -68
  33. package/list.md +125 -80
  34. package/map.gr +560 -57
  35. package/map.md +672 -56
  36. package/marshal.gr +239 -227
  37. package/marshal.md +36 -4
  38. package/number.gr +626 -676
  39. package/number.md +738 -153
  40. package/option.gr +33 -35
  41. package/option.md +58 -42
  42. package/package.json +2 -2
  43. package/path.gr +148 -187
  44. package/path.md +47 -96
  45. package/pervasives.gr +75 -416
  46. package/pervasives.md +85 -180
  47. package/priorityqueue.gr +433 -74
  48. package/priorityqueue.md +422 -54
  49. package/queue.gr +362 -80
  50. package/queue.md +433 -38
  51. package/random.gr +67 -75
  52. package/random.md +68 -40
  53. package/range.gr +135 -63
  54. package/range.md +198 -43
  55. package/rational.gr +284 -0
  56. package/rational.md +545 -0
  57. package/regex.gr +933 -1066
  58. package/regex.md +59 -60
  59. package/result.gr +23 -25
  60. package/result.md +54 -39
  61. package/runtime/atof/common.gr +78 -82
  62. package/runtime/atof/common.md +22 -10
  63. package/runtime/atof/decimal.gr +102 -127
  64. package/runtime/atof/decimal.md +28 -7
  65. package/runtime/atof/lemire.gr +56 -71
  66. package/runtime/atof/lemire.md +9 -1
  67. package/runtime/atof/parse.gr +83 -110
  68. package/runtime/atof/parse.md +12 -2
  69. package/runtime/atof/slow.gr +28 -35
  70. package/runtime/atof/slow.md +9 -1
  71. package/runtime/atof/table.gr +19 -18
  72. package/runtime/atof/table.md +10 -2
  73. package/runtime/atoi/parse.gr +153 -136
  74. package/runtime/atoi/parse.md +50 -1
  75. package/runtime/bigint.gr +410 -517
  76. package/runtime/bigint.md +71 -57
  77. package/runtime/compare.gr +176 -85
  78. package/runtime/compare.md +31 -1
  79. package/runtime/dataStructures.gr +144 -32
  80. package/runtime/dataStructures.md +267 -31
  81. package/runtime/debugPrint.gr +34 -15
  82. package/runtime/debugPrint.md +37 -5
  83. package/runtime/equal.gr +53 -52
  84. package/runtime/equal.md +30 -1
  85. package/runtime/exception.gr +38 -47
  86. package/runtime/exception.md +10 -8
  87. package/runtime/gc.gr +23 -152
  88. package/runtime/gc.md +13 -17
  89. package/runtime/malloc.gr +31 -31
  90. package/runtime/malloc.md +11 -3
  91. package/runtime/numberUtils.gr +191 -172
  92. package/runtime/numberUtils.md +17 -9
  93. package/runtime/numbers.gr +1695 -1021
  94. package/runtime/numbers.md +1098 -134
  95. package/runtime/string.gr +540 -242
  96. package/runtime/string.md +76 -6
  97. package/runtime/unsafe/constants.gr +30 -13
  98. package/runtime/unsafe/constants.md +80 -0
  99. package/runtime/unsafe/conv.gr +55 -28
  100. package/runtime/unsafe/conv.md +41 -9
  101. package/runtime/unsafe/memory.gr +10 -30
  102. package/runtime/unsafe/memory.md +15 -19
  103. package/runtime/unsafe/tags.gr +37 -21
  104. package/runtime/unsafe/tags.md +88 -8
  105. package/runtime/unsafe/wasmf32.gr +30 -36
  106. package/runtime/unsafe/wasmf32.md +64 -56
  107. package/runtime/unsafe/wasmf64.gr +30 -36
  108. package/runtime/unsafe/wasmf64.md +64 -56
  109. package/runtime/unsafe/wasmi32.gr +49 -66
  110. package/runtime/unsafe/wasmi32.md +102 -94
  111. package/runtime/unsafe/wasmi64.gr +52 -79
  112. package/runtime/unsafe/wasmi64.md +108 -100
  113. package/runtime/utils/printing.gr +13 -15
  114. package/runtime/utils/printing.md +11 -3
  115. package/runtime/wasi.gr +294 -295
  116. package/runtime/wasi.md +62 -42
  117. package/set.gr +574 -64
  118. package/set.md +634 -54
  119. package/stack.gr +181 -64
  120. package/stack.md +271 -42
  121. package/string.gr +453 -533
  122. package/string.md +241 -151
  123. package/uint16.gr +369 -0
  124. package/uint16.md +585 -0
  125. package/uint32.gr +470 -0
  126. package/uint32.md +737 -0
  127. package/uint64.gr +471 -0
  128. package/uint64.md +737 -0
  129. package/uint8.gr +369 -0
  130. package/uint8.md +585 -0
  131. package/uri.gr +1093 -0
  132. package/uri.md +477 -0
  133. package/{sys → wasi}/file.gr +914 -500
  134. package/{sys → wasi}/file.md +454 -50
  135. package/wasi/process.gr +292 -0
  136. package/{sys → wasi}/process.md +164 -6
  137. package/wasi/random.gr +77 -0
  138. package/wasi/random.md +80 -0
  139. package/{sys → wasi}/time.gr +15 -22
  140. package/{sys → wasi}/time.md +5 -5
  141. package/immutablearray.gr +0 -929
  142. package/immutablearray.md +0 -1038
  143. package/immutablemap.gr +0 -493
  144. package/immutablemap.md +0 -479
  145. package/immutablepriorityqueue.gr +0 -360
  146. package/immutablepriorityqueue.md +0 -291
  147. package/immutableset.gr +0 -498
  148. package/immutableset.md +0 -449
  149. package/runtime/debug.gr +0 -2
  150. package/runtime/debug.md +0 -6
  151. package/runtime/unsafe/errors.gr +0 -36
  152. package/runtime/unsafe/errors.md +0 -204
  153. package/sys/process.gr +0 -254
  154. package/sys/random.gr +0 -79
  155. package/sys/random.md +0 -66
package/priorityqueue.gr CHANGED
@@ -1,33 +1,28 @@
1
1
  /**
2
- * @module PriorityQueue: A mutable priority queue implementation. A priority queue is a data structure that maintains elements in a priority order. Elements with higher priority are served before elements with lower priority when extracting from the priority queue.
2
+ * A priority queue is a data structure that maintains elements in a priority order. Elements with higher priority are served before elements with lower priority when extracting from the priority queue.
3
3
  *
4
- * @example import PriorityQueue from "priorityqueue"
4
+ * An immutable priority queue implementation is available in the `Immutable` submodule.
5
+ *
6
+ * @example from "priorityqueue" include Priorityqueue
5
7
  *
6
8
  * @since v0.5.3
7
9
  */
10
+ module PriorityQueue
8
11
 
9
- import Array from "array"
10
- import List from "list"
11
- import Number from "number"
12
- import Option from "option"
13
-
14
- /**
15
- * @section Types: Type declarations included in the PriorityQueue module.
16
- */
12
+ from "array" include Array
13
+ from "list" include List
14
+ from "number" include Number
15
+ from "option" include Option
17
16
 
18
17
  /**
19
18
  * Mutable data structure which maintains a priority order for its elements.
20
19
  */
21
- record PriorityQueue<a> {
20
+ abstract record PriorityQueue<a> {
22
21
  mut size: Number,
23
22
  mut array: Array<Option<a>>,
24
- comp: (a, a) -> Number,
23
+ comp: (a, a) => Number,
25
24
  }
26
25
 
27
- /**
28
- * @section Values: Functions for working with PriorityQueues.
29
- */
30
-
31
26
  let swap = (i1, i2, array) => {
32
27
  let t = array[i2]
33
28
  array[i2] = array[i1]
@@ -37,8 +32,8 @@ let swap = (i1, i2, array) => {
37
32
  let get = (array, i) =>
38
33
  Option.expect(
39
34
  "Impossible: " ++
40
- toString(i) ++
41
- " in PriorityQueue's inner storage array is None",
35
+ toString(i) ++
36
+ " in PriorityQueue's inner storage array is None",
42
37
  array[i]
43
38
  )
44
39
 
@@ -78,71 +73,58 @@ let rec siftUp = (i, pq) => {
78
73
  * comparator function takes two elements and must return 0 if both share
79
74
  * priority, a positive number if the first has greater priority, and a
80
75
  * negative number if the first has less priority.
81
- *
76
+ *
82
77
  * Generally, you won't need to care about the storage size of your priority
83
- * queue and can use `PriorityQueue.make()` instead.
84
- *
78
+ * queue and can use the default size.
79
+ *
80
+ * @param compare: The comparator function used to indicate priority order
85
81
  * @param size: The initial storage size of the priority queue
86
- * @param comp: The comparator function used to indicate priority order
87
82
  * @returns An empty priority queue
88
83
  *
89
84
  * @since v0.5.3
90
- */
91
- export let makeSized = (size, comp) => {
92
- { size: 0, array: Array.make(size, None), comp }
93
- }
94
-
95
- /**
96
- * Creates a new priority queue with a comparator function, which is used to
97
- * determine priority of elements. The comparator function takes two elements
98
- * and must return 0 if both share priority, a positive number if the first
99
- * has greater priority, and a negative number if the first has less priority.
100
- *
101
- * @param comp: The comparator function used to indicate priority order
102
- * @returns An empty priority queue
103
- *
104
- * @example PriorityQueue.make(compare) // creates a min priority queue of numbers using the compare pervasive
105
- * @example PriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
85
+ * @history v0.6.0: Merged with `makeSized`; modified signature to accept size
106
86
  *
107
- * @since v0.5.3
87
+ * @example PriorityQueue.make() // creates a min priority queue of numbers using the compare pervasive
88
+ * @example PriorityQueue.make(compare=compare, size=32) // creates a min priority queue of numbers using the compare pervasive and an initial size of 32
89
+ * @example PriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
108
90
  */
109
- export let make = comp => {
110
- makeSized(16, comp)
91
+ provide let make = (compare=compare, size=16) => {
92
+ { size: 0, array: Array.make(size, None), comp: compare }
111
93
  }
112
94
 
113
95
  /**
114
96
  * Gets the number of elements in a priority queue.
115
- *
97
+ *
116
98
  * @param pq: The priority queue to inspect
117
99
  * @returns The number of elements in the priority queue
118
100
  *
119
101
  * @since v0.5.3
120
102
  */
121
- export let size = pq => {
103
+ provide let size = pq => {
122
104
  pq.size
123
105
  }
124
106
 
125
107
  /**
126
108
  * Determines if the priority queue contains no elements.
127
- *
109
+ *
128
110
  * @param pq: The priority queue to check
129
111
  * @returns `true` if the priority queue is empty and `false` otherwise
130
112
  *
131
113
  * @since v0.5.3
132
114
  */
133
- export let isEmpty = pq => {
115
+ provide let isEmpty = pq => {
134
116
  pq.size == 0
135
117
  }
136
118
 
137
119
  /**
138
120
  * Adds a new element to the priority queue.
139
- *
121
+ *
140
122
  * @param val: The value to add into the priority queue
141
123
  * @param pq: The priority queue to update
142
124
  *
143
125
  * @since v0.5.3
144
126
  */
145
- export let push = (val, pq) => {
127
+ provide let push = (val, pq) => {
146
128
  let arrLen = Array.length(pq.array)
147
129
  // double size of internal array if out of space
148
130
  if (pq.size == arrLen) {
@@ -162,13 +144,13 @@ export let push = (val, pq) => {
162
144
  /**
163
145
  * Retrieves the highest priority element in the priority queue. It is not
164
146
  * removed from the queue.
165
- *
147
+ *
166
148
  * @param pq: The priority queue to inspect
167
149
  * @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
168
150
  *
169
151
  * @since v0.5.3
170
152
  */
171
- export let peek = pq => {
153
+ provide let peek = pq => {
172
154
  if (pq.size == 0) {
173
155
  None
174
156
  } else {
@@ -178,38 +160,35 @@ export let peek = pq => {
178
160
 
179
161
  /**
180
162
  * Removes and retrieves the highest priority element in the priority queue.
181
- *
163
+ *
182
164
  * @param pq: The priority queue to inspect
183
165
  * @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
184
166
  *
185
167
  * @since v0.5.3
186
168
  */
187
- export let pop = pq => {
188
- if (pq.size == 0) {
189
- None
190
- } else {
191
- let root = pq.array[0]
192
-
193
- pq.array[0] = pq.array[pq.size - 1]
194
- pq.array[pq.size - 1] = None
195
- pq.size -= 1
196
- // reorder heap to ensure that binary heap property of parent nodes having
197
- // larger values than their children is upheld
198
- siftDown(0, pq)
199
- root
200
- }
169
+ provide let pop = pq => {
170
+ if (pq.size == 0) return None
171
+ let root = pq.array[0]
172
+
173
+ pq.array[0] = pq.array[pq.size - 1]
174
+ pq.array[pq.size - 1] = None
175
+ pq.size -= 1
176
+ // reorder heap to ensure that binary heap property of parent nodes having
177
+ // larger values than their children is upheld
178
+ siftDown(0, pq)
179
+ return root
201
180
  }
202
181
 
203
182
  /**
204
183
  * Clears the priority queue and produces a list of all of the elements in the priority
205
184
  * queue in priority order.
206
- *
185
+ *
207
186
  * @param pq: The priority queue to drain
208
187
  * @returns A list of all elements in the priority in priority order
209
188
  *
210
189
  * @since v0.5.3
211
190
  */
212
- export let drain = pq => {
191
+ provide let drain = pq => {
213
192
  let rec drainRec = acc => {
214
193
  match (pop(pq)) {
215
194
  Some(val) => drainRec([val, ...acc]),
@@ -225,17 +204,18 @@ export let drain = pq => {
225
204
  * elements. The comparator function takes two elements and must return 0 if
226
205
  * both share priority, a positive number if the first has greater priority,
227
206
  * and a negative number if the first has less priority.
228
- *
207
+ *
229
208
  * @param array: An array of values used to initialize the priority queue
230
- * @param comp: A comparator function used to assign priority to elements
209
+ * @param compare: A comparator function used to assign priority to elements
231
210
  * @returns A priority queue containing the elements from the array
232
211
  *
233
212
  * @since v0.5.4
213
+ * @history v0.6.0: Made `compare` a default argument
234
214
  */
235
- export let fromArray = (array, comp) => {
215
+ provide let fromArray = (array, compare=compare) => {
236
216
  let size = Array.length(array)
237
217
  let array = Array.map(x => Some(x), array)
238
- let heap = { size, array, comp }
218
+ let heap = { size, array, comp: compare }
239
219
  for (let mut i = size - 1; i >= 0; i -= 1) {
240
220
  siftDown(i, heap)
241
221
  }
@@ -248,14 +228,393 @@ export let fromArray = (array, comp) => {
248
228
  * elements. The comparator function takes two elements and must return 0 if
249
229
  * both share priority, a positive number if the first has greater priority,
250
230
  * and a negative number if the first has less priority.
251
- *
231
+ *
252
232
  * @param list: A list of values used to initialize the priority queue
253
- * @param comp: A comparator function used to assign priority to elements
233
+ * @param compare: A comparator function used to assign priority to elements
254
234
  * @returns A priority queue containing the elements from the list
255
235
  *
256
236
  * @since v0.5.3
237
+ * @history v0.6.0: Made `compare` a default argument
257
238
  */
258
- export let fromList = (list, comp) => {
239
+ provide let fromList = (list, compare=compare) => {
259
240
  let array = Array.fromList(list)
260
- fromArray(array, comp)
241
+ fromArray(array, compare=compare)
242
+ }
243
+
244
+ /**
245
+ * An immutable priority queue implementation.
246
+ *
247
+ * @since v0.6.0
248
+ * @history v0.5.4: Originally in `"immutablepriorityqueue"` module
249
+ */
250
+ provide module Immutable {
251
+ // implementation based on immutable skew binomial queue with global root optimization
252
+ // as described in the paper "Optimal Purely Functional Priority Queues" by Chris Okasaki.
253
+
254
+ // rank is a stand-in for height of this skew binomial tree
255
+ record rec Node<a> {
256
+ val: a,
257
+ rank: Number,
258
+ children: List<Node<a>>,
259
+ }
260
+
261
+ // an optimization over binomial queue that allows keeping track of the root value
262
+
263
+ // a skew binomial queue is defined as a forest of heap-ordered skew binomial trees
264
+ record PQRoot<a> {
265
+ rootVal: a,
266
+ pq: List<Node<a>>,
267
+ }
268
+
269
+ /**
270
+ * Immutable data structure which maintains a priority order for its elements.
271
+ */
272
+ abstract record PriorityQueue<a> {
273
+ comp: (a, a) => Number,
274
+ size: Number,
275
+ root: Option<PQRoot<a>>,
276
+ }
277
+
278
+ /**
279
+ * An empty priority queue with the default `compare` comparator.
280
+ *
281
+ * @since v0.6.0
282
+ * @history v0.5.4: Originally in `"immutablepriorityqueue"` module
283
+ */
284
+ provide let empty = {
285
+ let empty = { comp: compare, size: 0, root: None }
286
+ empty
287
+ }
288
+
289
+ /**
290
+ * Creates a new priority queue with a comparator function, which is used to
291
+ * determine priority of elements. The comparator function takes two elements
292
+ * and must return 0 if both share priority, a positive number if the first
293
+ * has greater priority, and a negative number if the first has less priority.
294
+ *
295
+ * @param compare: The comparator function used to indicate priority order
296
+ * @returns An empty priority queue
297
+ *
298
+ * @example PriorityQueue.Immutable.make(compare) // creates a min priority queue of numbers using the compare pervasive
299
+ * @example PriorityQueue.Immutable.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
300
+ *
301
+ * @since v0.6.0
302
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
303
+ */
304
+ provide let make = (compare=compare) => {
305
+ { comp: compare, size: 0, root: None }
306
+ }
307
+
308
+ /**
309
+ * Gets the number of elements in a priority queue.
310
+ *
311
+ * @param pq: The priority queue to inspect
312
+ * @returns The number of elements in the priority queue
313
+ *
314
+ * @since v0.6.0
315
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
316
+ */
317
+ provide let size = ({ size, _ } as pq: PriorityQueue<a>) => {
318
+ size
319
+ }
320
+
321
+ /**
322
+ * Determines if the priority queue contains no elements.
323
+ *
324
+ * @param pq: The priority queue to check
325
+ * @returns `true` if the priority queue is empty and `false` otherwise
326
+ *
327
+ * @since v0.6.0
328
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
329
+ */
330
+ provide let isEmpty = ({ size, _ } as pq: PriorityQueue<a>) => {
331
+ size == 0
332
+ }
333
+
334
+ let skewLinkNodes = (comp, newNode, node1, node2) => {
335
+ // make the two nodes with larger values children of the node with the smallest value
336
+ if (comp(node1.val, newNode.val) <= 0 && comp(node1.val, node2.val) <= 0) {
337
+ {
338
+ val: node1.val,
339
+ rank: node1.rank + 1,
340
+ children: [newNode, node2, ...node1.children],
341
+ }
342
+ } else if (
343
+ comp(node2.val, newNode.val) <= 0 &&
344
+ comp(node2.val, node1.val) <= 0
345
+ ) {
346
+ {
347
+ val: node2.val,
348
+ rank: node2.rank + 1,
349
+ children: [newNode, node1, ...node2.children],
350
+ }
351
+ } else {
352
+ { val: newNode.val, rank: node1.rank + 1, children: [node1, node2] }
353
+ }
354
+ }
355
+
356
+ let skewInsert = (comp, val, pq) => {
357
+ let newNode = { val, rank: 0, children: [] }
358
+ match (pq) {
359
+ // the only time two trees will have the same rank is if they are the
360
+ // smallest-ranked trees in the queue, in which case we should link
361
+ // them with the new node
362
+ [node1, node2, ...rest] when node1.rank == node2.rank =>
363
+ [skewLinkNodes(comp, newNode, node1, node2), ...rest],
364
+ _ => [newNode, ...pq],
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Produces a new priority queue by inserting the given element into the given priority queue.
370
+ *
371
+ * @param val: The value to add into the priority queue
372
+ * @param pq: The priority queue
373
+ * @returns A new priority queue with the given element inserted
374
+ *
375
+ * @since v0.6.0
376
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
377
+ */
378
+ provide let push = (val, pq) => {
379
+ let { comp, size, root } = pq
380
+ match (root) {
381
+ None => { comp, size: 1, root: Some({ rootVal: val, pq: [] }) },
382
+ Some({ rootVal, pq }) => {
383
+ // make the new value the root if it has higher priority than the highest priority value
384
+ let (morePriorityVal, lessPriorityVal) = if (comp(val, rootVal) <= 0)
385
+ (val, rootVal)
386
+ else
387
+ (rootVal, val)
388
+
389
+ let newRoot = Some(
390
+ {
391
+ rootVal: morePriorityVal,
392
+ pq: skewInsert(comp, lessPriorityVal, pq),
393
+ },
394
+ )
395
+ { comp, size: size + 1, root: newRoot }
396
+ },
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Retrieves the highest priority element in the priority queue. It is not
402
+ * removed from the queue.
403
+ *
404
+ * @param pq: The priority queue to inspect
405
+ * @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
406
+ *
407
+ * @since v0.6.0
408
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
409
+ */
410
+ provide let peek = pq => {
411
+ match (pq.root) {
412
+ None => None,
413
+ Some({ rootVal, _ }) => Some(rootVal),
414
+ }
415
+ }
416
+
417
+ let linkNodes = (comp, node1, node2) => {
418
+ // make the node with higher priority the parent of the node with smaller
419
+ // priority to presere heap-ordering
420
+ let (morePriority, lessPriority) = if (comp(node1.val, node2.val) <= 0)
421
+ (node1, node2)
422
+ else
423
+ (node2, node1)
424
+ {
425
+ val: morePriority.val,
426
+ rank: morePriority.rank + 1,
427
+ children: [lessPriority, ...morePriority.children],
428
+ }
429
+ }
430
+
431
+ // step through the trees in the priority queue in increasing rank order until we
432
+ // find a missing rank, linking trees of equal rank as we go
433
+ let rec ins = (comp, node, pq) => {
434
+ match (pq) {
435
+ [] => [node],
436
+ [firstNode, ...rest] => {
437
+ if (node.rank < firstNode.rank) {
438
+ [node, firstNode, ...rest]
439
+ } else {
440
+ ins(comp, linkNodes(comp, node, firstNode), rest)
441
+ }
442
+ },
443
+ }
444
+ }
445
+
446
+ let uniquify = (comp, pq) => {
447
+ match (pq) {
448
+ [] => [],
449
+ [node, ...rest] => ins(comp, node, rest),
450
+ }
451
+ }
452
+
453
+ // step through the trees of two priority queues in increasing rank order,
454
+ // performing a simple link whenever we find two trees of equal rank
455
+ let rec mergeUniq = (comp, pq1, pq2) => {
456
+ match ((pq1, pq2)) {
457
+ ([], ts) | (ts, []) => ts,
458
+ ([node1, ...rest1], [node2, ...rest2]) => {
459
+ if (node1.rank < node2.rank) {
460
+ [node1, ...mergeUniq(comp, rest1, pq2)]
461
+ } else if (node2.rank < node1.rank) {
462
+ [node2, ...mergeUniq(comp, pq1, rest2)]
463
+ } else {
464
+ ins(
465
+ comp,
466
+ linkNodes(comp, node1, node2),
467
+ mergeUniq(comp, rest1, rest2)
468
+ )
469
+ }
470
+ },
471
+ }
472
+ }
473
+
474
+ let merge = (comp, pq1, pq2) =>
475
+ mergeUniq(comp, uniquify(comp, pq1), uniquify(comp, pq2))
476
+
477
+ // splits the node with the minimum value out from the rest of the nodes
478
+ let rec separateHighestPriority = (comp, pq) => {
479
+ match (pq) {
480
+ // empty list case should never happen; this is here just to satisfy the compiler
481
+ [] => fail "Impossible: getHighestPriority called with empty PQ",
482
+ [node] => (node, []),
483
+ [node, ...rest] => {
484
+ let (currMinNode, currNonMinNodes) = separateHighestPriority(comp, rest)
485
+ if (comp(node.val, currMinNode.val) <= 0) {
486
+ (node, rest)
487
+ } else {
488
+ (currMinNode, [node, ...currNonMinNodes])
489
+ }
490
+ },
491
+ }
492
+ }
493
+
494
+ // splits the nodes of rank 0 out from the other nodes
495
+ let rec splitRankZero = (rankZeroVals, nonRankZeroNodes, pq) => {
496
+ match (pq) {
497
+ [] => (rankZeroVals, nonRankZeroNodes),
498
+ [node, ...rest] => {
499
+ if (node.rank == 0) {
500
+ splitRankZero([node.val, ...rankZeroVals], nonRankZeroNodes, rest)
501
+ } else {
502
+ splitRankZero(rankZeroVals, [node, ...nonRankZeroNodes], rest)
503
+ }
504
+ },
505
+ }
506
+ }
507
+
508
+ let withoutHighestPriority = (comp, pq) => {
509
+ // split out the node with the highest priority
510
+ let (hpNode, nonHpNodes) = separateHighestPriority(comp, pq)
511
+ // split out the values with nodes of rank 0, which will all be singleton nodes
512
+ let (rankZeroVals, nonRankZeroNodes) = splitRankZero(
513
+ [],
514
+ [],
515
+ hpNode.children
516
+ )
517
+
518
+ let mergedPq = merge(comp, nonHpNodes, nonRankZeroNodes)
519
+ List.reduce((pq, val) => skewInsert(comp, val, pq), mergedPq, rankZeroVals)
520
+ }
521
+
522
+ let rec findHighestPriority = (comp, pq) => {
523
+ match (pq) {
524
+ // empty list case should never happen; this is here just to satisfy the compiler
525
+ [] => fail "Impossible: findHighestPriority with empty PQ",
526
+ [node] => node.val,
527
+ [node, ...rest] => {
528
+ let currMin = findHighestPriority(comp, rest)
529
+ if (comp(node.val, currMin) <= 0) node.val else currMin
530
+ },
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Produces a new priority queue without the highest priority element in the
536
+ * given priority queue. If the input priority queue is empty, this function will
537
+ * return it.
538
+ *
539
+ * @param pq: The priority queue
540
+ * @returns A new priority queue without the highest priority element
541
+ *
542
+ * @since v0.6.0
543
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
544
+ */
545
+ provide let pop = pq => {
546
+ let pqWithRoot = pq
547
+ let { comp, size, root } = pq
548
+ match (root) {
549
+ None => pq,
550
+ Some({ pq, rootVal }) => {
551
+ let newRoot = if (pq == []) {
552
+ None
553
+ } else {
554
+ Some(
555
+ {
556
+ rootVal: findHighestPriority(comp, pq),
557
+ pq: withoutHighestPriority(comp, pq),
558
+ },
559
+ )
560
+ }
561
+ { comp, size: size - 1, root: newRoot }
562
+ },
563
+ }
564
+ }
565
+
566
+ /**
567
+ * Produces a list of all elements in the priority queue in priority order.
568
+ *
569
+ * @param pq: The priority queue to drain
570
+ * @returns A list of all elements in the priority in priority order
571
+ *
572
+ * @since v0.6.0
573
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module
574
+ */
575
+ provide let drain = pq => {
576
+ let rec drainRec = (acc, pq) => {
577
+ match (pq.root) {
578
+ None => acc,
579
+ Some(root) => drainRec([root.rootVal, ...acc], pop(pq)),
580
+ }
581
+ }
582
+ List.reverse(drainRec([], pq))
583
+ }
584
+
585
+ /**
586
+ * Constructs a new priority queue initialized with the elements in the list
587
+ * using a custom comparator function, which is used to determine priority of
588
+ * elements. The comparator function takes two elements and must return 0 if
589
+ * both share priority, a positive number if the first has greater priority,
590
+ * and a negative number if the first has less priority.
591
+ *
592
+ * @param list: A list of values used to initialize the priority queue
593
+ * @param compare: A comparator function used to assign priority to elements
594
+ * @returns A priority queue containing the elements from the list
595
+ *
596
+ * @since v0.6.0
597
+ * @history v0.5.3: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
598
+ */
599
+ provide let fromList = (list, compare=compare) => {
600
+ List.reduce((pq, val) => push(val, pq), make(compare=compare), list)
601
+ }
602
+
603
+ /**
604
+ * Constructs a new priority queue initialized with the elements in the array
605
+ * using a custom comparator function, which is used to determine priority of
606
+ * elements. The comparator function takes two elements and must return 0 if
607
+ * both share priority, a positive number if the first has greater priority,
608
+ * and a negative number if the first has less priority.
609
+ *
610
+ * @param array: An array of values used to initialize the priority queue
611
+ * @param compare: A comparator function used to assign priority to elements
612
+ * @returns A priority queue containing the elements from the array
613
+ *
614
+ * @since v0.6.0
615
+ * @history v0.5.4: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
616
+ */
617
+ provide let fromArray = (array, compare=compare) => {
618
+ Array.reduce((pq, val) => push(val, pq), make(compare=compare), array)
619
+ }
261
620
  }