@grain/stdlib 0.5.2 → 0.5.3

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.
@@ -0,0 +1,332 @@
1
+ /**
2
+ * @module ImmutablePriorityQueue: An immutable priority queue. 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
+ *
4
+ * @example import ImmutablePriorityQueue from "immutablepriorityqueue"
5
+ *
6
+ * @since v0.5.3
7
+ */
8
+
9
+ import List from "list"
10
+
11
+ // implementation based on immutable skew binomial queue with global root optimization
12
+ // as described in the paper "Optimal Purely Functional Priority Queues" by Chris Okasaki.
13
+
14
+ // rank is a stand-in for height of this skew binomial tree
15
+ record Node<a> {
16
+ val: a,
17
+ rank: Number,
18
+ children: List<Node<a>>,
19
+ }
20
+
21
+ // an optimization over binomial queue that allows keeping track of the root value
22
+
23
+ // a skew binomial queue is defined as a forest of heap-ordered skew binomial trees
24
+ record PQRoot<a> {
25
+ rootVal: a,
26
+ pq: List<Node<a>>,
27
+ }
28
+
29
+ /**
30
+ * @section Types: Type declarations included in the ImmutablePriorityQueue module.
31
+ */
32
+
33
+ /**
34
+ * Immutable data structure which maintains a priority order for its elements.
35
+ */
36
+ record ImmutablePriorityQueue<a> {
37
+ comp: (a, a) -> Number,
38
+ size: Number,
39
+ root: Option<PQRoot<a>>,
40
+ }
41
+
42
+ /**
43
+ * @section Values: Functions for working with ImmutablePriorityQueues.
44
+ */
45
+
46
+ /**
47
+ * Creates a new priority queue with a comparator function, which is used to
48
+ * determine priority of elements. The comparator function takes two elements
49
+ * and must return 0 if both share priority, a positive number if the first
50
+ * has greater priority, and a negative number if the first has less priority.
51
+ *
52
+ * @param comp: The comparator function used to indicate priority order
53
+ * @returns An empty priority queue
54
+ *
55
+ * @example ImmutablePriorityQueue.make(compare) // creates a min priority queue of numbers using the compare pervasive
56
+ * @example ImmutablePriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
57
+ *
58
+ * @since v0.5.3
59
+ */
60
+ export let make = comp => {
61
+ { comp, size: 0, root: None }
62
+ }
63
+
64
+ /**
65
+ * Gets the number of elements in a priority queue.
66
+ *
67
+ * @param pq: The priority queue to inspect
68
+ * @returns The number of elements in the priority queue
69
+ *
70
+ * @since v0.5.3
71
+ */
72
+ export let size = pq => {
73
+ pq.size
74
+ }
75
+
76
+ /**
77
+ * Determines if the priority queue contains no elements.
78
+ *
79
+ * @param pq: The priority queue to check
80
+ * @returns `true` if the priority queue is empty and `false` otherwise
81
+ *
82
+ * @since v0.5.3
83
+ */
84
+ export let isEmpty = pq => {
85
+ pq.size == 0
86
+ }
87
+
88
+ let skewLinkNodes = (comp, newNode, node1, node2) => {
89
+ // make the two nodes with larger values children of the node with the smallest value
90
+ if (comp(node1.val, newNode.val) <= 0 && comp(node1.val, node2.val) <= 0) {
91
+ {
92
+ val: node1.val,
93
+ rank: node1.rank + 1,
94
+ children: [newNode, node2, ...node1.children],
95
+ }
96
+ } else if (
97
+ comp(node2.val, newNode.val) <= 0 && comp(node2.val, node1.val) <= 0
98
+ ) {
99
+ {
100
+ val: node2.val,
101
+ rank: node2.rank + 1,
102
+ children: [newNode, node1, ...node2.children],
103
+ }
104
+ } else {
105
+ { val: newNode.val, rank: node1.rank + 1, children: [node1, node2] }
106
+ }
107
+ }
108
+
109
+ let skewInsert = (comp, val, pq) => {
110
+ let newNode = { val, rank: 0, children: [] }
111
+ match (pq) {
112
+ // the only time two trees will have the same rank is if they are the
113
+ // smallest-ranked trees in the queue, in which case we should link
114
+ // them with the new node
115
+ [node1, node2, ...rest] when node1.rank == node2.rank =>
116
+ [skewLinkNodes(comp, newNode, node1, node2), ...rest],
117
+ _ => [newNode, ...pq],
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Produces a new priority queue by inserting the given element into the given priority queue.
123
+ *
124
+ * @param val: The value to add into the priority queue
125
+ * @param pq: The priority queue
126
+ * @returns A new priority queue with the given element inserted
127
+ */
128
+ export let push = (val, pq) => {
129
+ let { comp, size, root } = pq
130
+ match (root) {
131
+ None => { comp, size: 1, root: Some({ rootVal: val, pq: [] }) },
132
+ Some({ rootVal, pq }) => {
133
+ // make the new value the root if it has higher priority than the highest priority value
134
+ let (morePriorityVal, lessPriorityVal) = if (comp(val, rootVal) <= 0)
135
+ (val, rootVal) else (rootVal, val)
136
+
137
+ let newRoot = Some(
138
+ { rootVal: morePriorityVal, pq: skewInsert(comp, lessPriorityVal, pq) }
139
+ )
140
+ { comp, size: size + 1, root: newRoot }
141
+ },
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Retrieves the highest priority element in the priority queue. It is not
147
+ * removed from the queue.
148
+ *
149
+ * @param pq: The priority queue to inspect
150
+ * @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
151
+ *
152
+ * @since v0.5.3
153
+ */
154
+ export let peek = pq => {
155
+ match (pq.root) {
156
+ None => None,
157
+ Some({ rootVal, _ }) => Some(rootVal),
158
+ }
159
+ }
160
+
161
+ let linkNodes = (comp, node1, node2) => {
162
+ // make the node with higher priority the parent of the node with smaller
163
+ // priority to presere heap-ordering
164
+ let (morePriority, lessPriority) = if (comp(node1.val, node2.val) <= 0)
165
+ (node1, node2) else (node2, node1)
166
+ {
167
+ val: morePriority.val,
168
+ rank: morePriority.rank + 1,
169
+ children: [lessPriority, ...morePriority.children],
170
+ }
171
+ }
172
+
173
+ // step through the trees in the priority queue in increasing rank order until we
174
+ // find a missing rank, linking trees of equal rank as we go
175
+ let rec ins = (comp, node, pq) => {
176
+ match (pq) {
177
+ [] => [node],
178
+ [firstNode, ...rest] => {
179
+ if (node.rank < firstNode.rank) {
180
+ [node, firstNode, ...rest]
181
+ } else {
182
+ ins(comp, linkNodes(comp, node, firstNode), rest)
183
+ }
184
+ },
185
+ }
186
+ }
187
+
188
+ let uniquify = (comp, pq) => {
189
+ match (pq) {
190
+ [] => [],
191
+ [node, ...rest] => ins(comp, node, rest),
192
+ }
193
+ }
194
+
195
+ // step through the trees of two priority queues in increasing rank order,
196
+ // performing a simple link whenever we find two trees of equal rank
197
+ let rec mergeUniq = (comp, pq1, pq2) => {
198
+ match ((pq1, pq2)) {
199
+ ([], ts) | (ts, []) => ts,
200
+ ([node1, ...rest1], [node2, ...rest2]) => {
201
+ if (node1.rank < node2.rank) {
202
+ [node1, ...mergeUniq(comp, rest1, pq2)]
203
+ } else if (node2.rank < node1.rank) {
204
+ [node2, ...mergeUniq(comp, pq1, rest2)]
205
+ } else {
206
+ ins(comp, linkNodes(comp, node1, node2), mergeUniq(comp, rest1, rest2))
207
+ }
208
+ },
209
+ }
210
+ }
211
+
212
+ let merge = (comp, pq1, pq2) =>
213
+ mergeUniq(comp, uniquify(comp, pq1), uniquify(comp, pq2))
214
+
215
+ // splits the node with the minimum value out from the rest of the nodes
216
+ let rec separateHighestPriority = (comp, pq) => {
217
+ match (pq) {
218
+ // empty list case should never happen; this is here just to satisfy the compiler
219
+ [] => fail "getHighestPriority called with empty PQ",
220
+ [node] => (node, []),
221
+ [node, ...rest] => {
222
+ let (currMinNode, currNonMinNodes) = separateHighestPriority(comp, rest)
223
+ if (comp(node.val, currMinNode.val) <= 0) {
224
+ (node, rest)
225
+ } else {
226
+ (currMinNode, [node, ...currNonMinNodes])
227
+ }
228
+ },
229
+ }
230
+ }
231
+
232
+ // splits the nodes of rank 0 out from the other nodes
233
+ let rec splitRankZero = (rankZeroVals, nonRankZeroNodes, pq) => {
234
+ match (pq) {
235
+ [] => (rankZeroVals, nonRankZeroNodes),
236
+ [node, ...rest] => {
237
+ if (node.rank == 0) {
238
+ splitRankZero([node.val, ...rankZeroVals], nonRankZeroNodes, rest)
239
+ } else {
240
+ splitRankZero(rankZeroVals, [node, ...nonRankZeroNodes], rest)
241
+ }
242
+ },
243
+ }
244
+ }
245
+
246
+ let withoutHighestPriority = (comp, pq) => {
247
+ // split out the node with the highest priority
248
+ let (hpNode, nonHpNodes) = separateHighestPriority(comp, pq)
249
+ // split out the values with nodes of rank 0, which will all be singleton nodes
250
+ let (rankZeroVals, nonRankZeroNodes) = splitRankZero([], [], hpNode.children)
251
+
252
+ let mergedPq = merge(comp, nonHpNodes, nonRankZeroNodes)
253
+ List.reduce((pq, val) => skewInsert(comp, val, pq), mergedPq, rankZeroVals)
254
+ }
255
+
256
+ let rec findHighestPriority = (comp, pq) => {
257
+ match (pq) {
258
+ // empty list case should never happen; this is here just to satisfy the compiler
259
+ [] => fail "findHighestPriority with empty PQ",
260
+ [node] => node.val,
261
+ [node, ...rest] => {
262
+ let currMin = findHighestPriority(comp, rest)
263
+ if (comp(node.val, currMin) <= 0) node.val else currMin
264
+ },
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Produces a new priority queue without the highest priority element in the
270
+ * given priority queue. If the input priority queue is empty, this function will
271
+ * return it.
272
+ *
273
+ * @param pq: The priority queue
274
+ * @returns A new priority queue without the highest priority element
275
+ *
276
+ * @since v0.5.3
277
+ */
278
+ export let pop = pq => {
279
+ let pqWithRoot = pq
280
+ let { comp, size, root } = pq
281
+ match (root) {
282
+ None => pq,
283
+ Some({ pq, rootVal }) => {
284
+ let newRoot = if (pq == []) {
285
+ None
286
+ } else {
287
+ Some(
288
+ {
289
+ rootVal: findHighestPriority(comp, pq),
290
+ pq: withoutHighestPriority(comp, pq),
291
+ }
292
+ )
293
+ }
294
+ { comp, size: size - 1, root: newRoot }
295
+ },
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Produces a list of all elements in the priority queue in priority order.
301
+ *
302
+ * @param pq: The priority queue to drain
303
+ * @returns A list of all elements in the priority in priority order
304
+ *
305
+ * @since v0.5.3
306
+ */
307
+ export let drain = pq => {
308
+ let rec drainRec = (acc, pq) => {
309
+ match (pq.root) {
310
+ None => acc,
311
+ Some(root) => drainRec([root.rootVal, ...acc], pop(pq)),
312
+ }
313
+ }
314
+ List.reverse(drainRec([], pq))
315
+ }
316
+
317
+ /**
318
+ * Constructs a new priority queue initialized with the elements in the list
319
+ * using a custom comparator function, which is used to determine priority of
320
+ * elements. The comparator function takes two elements and must return 0 if
321
+ * both share priority, a positive number if the first has greater priority,
322
+ * and a negative number if the first has less priority.
323
+ *
324
+ * @param list: A list of values used to initialize the priority queue
325
+ * @param comp: A comparator function used to assign priority to elements
326
+ * @returns A priority queue containing the elements from the list
327
+ *
328
+ * @since v0.5.3
329
+ */
330
+ export let fromList = (list, comp) => {
331
+ List.reduce((pq, val) => push(val, pq), make(comp), list)
332
+ }
@@ -0,0 +1,248 @@
1
+ ---
2
+ title: ImmutablePriorityQueue
3
+ ---
4
+
5
+ An immutable priority queue. 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.
6
+
7
+ <details disabled>
8
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
9
+ No other changes yet.
10
+ </details>
11
+
12
+ ```grain
13
+ import ImmutablePriorityQueue from "immutablepriorityqueue"
14
+ ```
15
+
16
+ ## Types
17
+
18
+ Type declarations included in the ImmutablePriorityQueue module.
19
+
20
+ ### ImmutablePriorityQueue.**ImmutablePriorityQueue**
21
+
22
+ ```grain
23
+ type ImmutablePriorityQueue<a>
24
+ ```
25
+
26
+ Immutable data structure which maintains a priority order for its elements.
27
+
28
+ ## Values
29
+
30
+ Functions for working with ImmutablePriorityQueues.
31
+
32
+ ### ImmutablePriorityQueue.**make**
33
+
34
+ <details disabled>
35
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
36
+ No other changes yet.
37
+ </details>
38
+
39
+ ```grain
40
+ make : ((a, a) -> Number) -> ImmutablePriorityQueue<a>
41
+ ```
42
+
43
+ Creates a new priority queue with a comparator function, which is used to
44
+ determine priority of elements. The comparator function takes two elements
45
+ and must return 0 if both share priority, a positive number if the first
46
+ has greater priority, and a negative number if the first has less priority.
47
+
48
+ Parameters:
49
+
50
+ |param|type|description|
51
+ |-----|----|-----------|
52
+ |`comp`|`(a, a) -> Number`|The comparator function used to indicate priority order|
53
+
54
+ Returns:
55
+
56
+ |type|description|
57
+ |----|-----------|
58
+ |`ImmutablePriorityQueue<a>`|An empty priority queue|
59
+
60
+ Examples:
61
+
62
+ ```grain
63
+ ImmutablePriorityQueue.make(compare) // creates a min priority queue of numbers using the compare pervasive
64
+ ```
65
+
66
+ ```grain
67
+ ImmutablePriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
68
+ ```
69
+
70
+ ### ImmutablePriorityQueue.**size**
71
+
72
+ <details disabled>
73
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
74
+ No other changes yet.
75
+ </details>
76
+
77
+ ```grain
78
+ size : ImmutablePriorityQueue<a> -> Number
79
+ ```
80
+
81
+ Gets the number of elements in a priority queue.
82
+
83
+ Parameters:
84
+
85
+ |param|type|description|
86
+ |-----|----|-----------|
87
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue to inspect|
88
+
89
+ Returns:
90
+
91
+ |type|description|
92
+ |----|-----------|
93
+ |`Number`|The number of elements in the priority queue|
94
+
95
+ ### ImmutablePriorityQueue.**isEmpty**
96
+
97
+ <details disabled>
98
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
99
+ No other changes yet.
100
+ </details>
101
+
102
+ ```grain
103
+ isEmpty : ImmutablePriorityQueue<a> -> Bool
104
+ ```
105
+
106
+ Determines if the priority queue contains no elements.
107
+
108
+ Parameters:
109
+
110
+ |param|type|description|
111
+ |-----|----|-----------|
112
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue to check|
113
+
114
+ Returns:
115
+
116
+ |type|description|
117
+ |----|-----------|
118
+ |`Bool`|`true` if the priority queue is empty and `false` otherwise|
119
+
120
+ ### ImmutablePriorityQueue.**push**
121
+
122
+ ```grain
123
+ push : (a, ImmutablePriorityQueue<a>) -> ImmutablePriorityQueue<a>
124
+ ```
125
+
126
+ Produces a new priority queue by inserting the given element into the given priority queue.
127
+
128
+ Parameters:
129
+
130
+ |param|type|description|
131
+ |-----|----|-----------|
132
+ |`val`|`a`|The value to add into the priority queue|
133
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue|
134
+
135
+ Returns:
136
+
137
+ |type|description|
138
+ |----|-----------|
139
+ |`ImmutablePriorityQueue<a>`|A new priority queue with the given element inserted|
140
+
141
+ ### ImmutablePriorityQueue.**peek**
142
+
143
+ <details disabled>
144
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
145
+ No other changes yet.
146
+ </details>
147
+
148
+ ```grain
149
+ peek : ImmutablePriorityQueue<a> -> Option<a>
150
+ ```
151
+
152
+ Retrieves the highest priority element in the priority queue. It is not
153
+ removed from the queue.
154
+
155
+ Parameters:
156
+
157
+ |param|type|description|
158
+ |-----|----|-----------|
159
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue to inspect|
160
+
161
+ Returns:
162
+
163
+ |type|description|
164
+ |----|-----------|
165
+ |`Option<a>`|`Some(value)` containing the highest priority element or `None` if the priority queue is empty|
166
+
167
+ ### ImmutablePriorityQueue.**pop**
168
+
169
+ <details disabled>
170
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
171
+ No other changes yet.
172
+ </details>
173
+
174
+ ```grain
175
+ pop : ImmutablePriorityQueue<a> -> ImmutablePriorityQueue<a>
176
+ ```
177
+
178
+ Produces a new priority queue without the highest priority element in the
179
+ given priority queue. If the input priority queue is empty, this function will
180
+ return it.
181
+
182
+ Parameters:
183
+
184
+ |param|type|description|
185
+ |-----|----|-----------|
186
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue|
187
+
188
+ Returns:
189
+
190
+ |type|description|
191
+ |----|-----------|
192
+ |`ImmutablePriorityQueue<a>`|A new priority queue without the highest priority element|
193
+
194
+ ### ImmutablePriorityQueue.**drain**
195
+
196
+ <details disabled>
197
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
198
+ No other changes yet.
199
+ </details>
200
+
201
+ ```grain
202
+ drain : ImmutablePriorityQueue<a> -> List<a>
203
+ ```
204
+
205
+ Produces a list of all elements in the priority queue in priority order.
206
+
207
+ Parameters:
208
+
209
+ |param|type|description|
210
+ |-----|----|-----------|
211
+ |`pq`|`ImmutablePriorityQueue<a>`|The priority queue to drain|
212
+
213
+ Returns:
214
+
215
+ |type|description|
216
+ |----|-----------|
217
+ |`List<a>`|A list of all elements in the priority in priority order|
218
+
219
+ ### ImmutablePriorityQueue.**fromList**
220
+
221
+ <details disabled>
222
+ <summary tabindex="-1">Added in <code>0.5.3</code></summary>
223
+ No other changes yet.
224
+ </details>
225
+
226
+ ```grain
227
+ fromList : (List<a>, ((a, a) -> Number)) -> ImmutablePriorityQueue<a>
228
+ ```
229
+
230
+ Constructs a new priority queue initialized with the elements in the list
231
+ using a custom comparator function, which is used to determine priority of
232
+ elements. The comparator function takes two elements and must return 0 if
233
+ both share priority, a positive number if the first has greater priority,
234
+ and a negative number if the first has less priority.
235
+
236
+ Parameters:
237
+
238
+ |param|type|description|
239
+ |-----|----|-----------|
240
+ |`list`|`List<a>`|A list of values used to initialize the priority queue|
241
+ |`comp`|`(a, a) -> Number`|A comparator function used to assign priority to elements|
242
+
243
+ Returns:
244
+
245
+ |type|description|
246
+ |----|-----------|
247
+ |`ImmutablePriorityQueue<a>`|A priority queue containing the elements from the list|
248
+
package/list.gr CHANGED
@@ -548,6 +548,79 @@ export let unique = list => {
548
548
  iter(list, [])
549
549
  }
550
550
 
551
+ /**
552
+ * Produces a new list filled with tuples of elements from both given lists.
553
+ * The first tuple will contain the first item of each list, the second tuple
554
+ * will contain the second item of each list, and so on.
555
+ *
556
+ * Calling this function with lists of different sizes will cause the returned
557
+ * list to have the length of the smaller list.
558
+ *
559
+ * @param list1: The list to provide values for the first tuple element
560
+ * @param list2: The list to provide values for the second tuple element
561
+ * @returns The new list containing indexed pairs of `(a, b)`
562
+ *
563
+ * @example List.zip([1, 2, 3], [4, 5, 6]) // [(1, 4), (2, 5), (3, 6)]
564
+ * @example List.zip([1, 2, 3], [4, 5]) // [(1, 4), (2, 5)]
565
+ *
566
+ * @since v0.5.3
567
+ */
568
+ export let zip = (list1, list2) => {
569
+ let rec zipInner = (list1, list2, acc) => {
570
+ match ((list1, list2)) {
571
+ ([first1, ...rest1], [first2, ...rest2]) =>
572
+ zipInner(rest1, rest2, [(first1, first2), ...acc]),
573
+ _ => acc,
574
+ }
575
+ }
576
+ reverse(zipInner(list1, list2, []))
577
+ }
578
+
579
+ /**
580
+ * Produces a new list filled with elements defined by applying a function on
581
+ * pairs from both given lists. The first element will contain the result of
582
+ * applying the function to the first elements of each list, the second element
583
+ * will contain the result of applying the function to the second elements of
584
+ * each list, and so on.
585
+ *
586
+ * Calling this function with lists of different sizes will cause the returned
587
+ * list to have the length of the smaller list.
588
+ *
589
+ * @param fn: The function to apply to pairs of elements
590
+ * @param list1: The list whose elements will each be passed to the function as the first argument
591
+ * @param list2: The list whose elements will each be passed to the function as the second argument
592
+ * @returns The new list containing elements derived from applying the function to pairs of input list elements
593
+ *
594
+ * @example List.zipWith((a, b) => a + b, [1, 2, 3], [4, 5, 6]) // [5, 7, 9]
595
+ * @example List.zipWith((a, b) => a * b, [1, 2, 3], [4, 5]) // [4, 10]
596
+ *
597
+ * @since v0.5.3
598
+ */
599
+ export let zipWith = (fn, list1, list2) => {
600
+ let rec zipWithInner = (list1, list2, acc) => {
601
+ match ((list1, list2)) {
602
+ ([first1, ...rest1], [first2, ...rest2]) =>
603
+ zipWithInner(rest1, rest2, [fn(first1, first2), ...acc]),
604
+ _ => acc,
605
+ }
606
+ }
607
+ reverse(zipWithInner(list1, list2, []))
608
+ }
609
+
610
+ /**
611
+ * Produces two lists by splitting apart a list of tuples.
612
+ *
613
+ * @param list: The list of tuples to split
614
+ * @returns An list containing all elements from the first tuple element, and a list containing all elements from the second tuple element
615
+ *
616
+ * @since v0.5.3
617
+ */
618
+ export let unzip = list => {
619
+ reduceRight(((first, second), (firstUnzipped, secondUnzipped)) => {
620
+ ([first, ...firstUnzipped], [second, ...secondUnzipped])
621
+ }, ([], []), list)
622
+ }
623
+
551
624
  /**
552
625
  * Produces a new list with the specified number of elements removed from
553
626
  * the beginning of the input list.