@effekt-lang/effekt 0.2.1 → 0.3.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/bin/effekt +0 -0
  4. package/bin/effekt.sh +2 -0
  5. package/libraries/chez/THIRD-PARTY.txt +11 -0
  6. package/libraries/chez/callcc/datatype.ss +188 -0
  7. package/libraries/chez/callcc/effekt.ss +31 -0
  8. package/libraries/chez/callcc/seq.ss +44 -0
  9. package/libraries/chez/callcc/seq0.ss +69 -0
  10. package/libraries/chez/callcc/tail.ss +76 -0
  11. package/libraries/chez/callcc/tail0.ss +89 -0
  12. package/libraries/chez/common/effekt_primitives.ss +105 -0
  13. package/libraries/chez/common/immutable/cslist.effekt +37 -0
  14. package/libraries/chez/common/mutable/dict.effekt +28 -0
  15. package/libraries/chez/common/text/pregexp.scm +772 -0
  16. package/libraries/chez/common/text/regex.effekt +31 -0
  17. package/libraries/chez/lift/effekt.ss +118 -0
  18. package/libraries/chez/monadic/effekt.ss +84 -0
  19. package/libraries/chez/monadic/seq0.ss +76 -0
  20. package/libraries/common/args.effekt +95 -0
  21. package/libraries/common/array.effekt +225 -0
  22. package/libraries/common/bench.effekt +60 -0
  23. package/libraries/common/buffer.effekt +123 -0
  24. package/libraries/common/bytes.effekt +125 -0
  25. package/libraries/common/dequeue.effekt +92 -0
  26. package/libraries/common/effekt.effekt +764 -0
  27. package/libraries/common/exception.effekt +122 -0
  28. package/libraries/common/io/console.effekt +66 -0
  29. package/libraries/common/io/error.effekt +365 -0
  30. package/libraries/common/io/files.effekt +282 -0
  31. package/libraries/common/io/network.effekt +105 -0
  32. package/libraries/common/io/time.effekt +15 -0
  33. package/libraries/common/io.effekt +158 -0
  34. package/libraries/common/list.effekt +687 -0
  35. package/libraries/common/option.effekt +72 -0
  36. package/libraries/common/process.effekt +10 -0
  37. package/libraries/common/queue.effekt +140 -0
  38. package/libraries/common/ref.effekt +63 -0
  39. package/libraries/common/result.effekt +45 -0
  40. package/libraries/common/seq.effekt +914 -0
  41. package/libraries/common/string.effekt +395 -0
  42. package/libraries/common/test.effekt +98 -0
  43. package/libraries/js/effekt_builtins.js +57 -0
  44. package/libraries/js/effekt_runtime.js +385 -0
  45. package/libraries/js/io.js +143 -0
  46. package/libraries/js/mutable/map.effekt +31 -0
  47. package/libraries/js/text/regex.effekt +33 -0
  48. package/libraries/js/unsafe/cont.effekt +11 -0
  49. package/libraries/js/web/dom.effekt +45 -0
  50. package/libraries/llvm/array.c +53 -0
  51. package/libraries/llvm/buffer.c +286 -0
  52. package/libraries/llvm/forward-declare-c.ll +43 -0
  53. package/libraries/llvm/hole.c +11 -0
  54. package/libraries/llvm/io.c +566 -0
  55. package/libraries/llvm/io.ll +19 -0
  56. package/libraries/llvm/main.c +41 -0
  57. package/libraries/llvm/ref.c +45 -0
  58. package/libraries/llvm/rts.ll +761 -0
  59. package/libraries/llvm/sanity.c +16 -0
  60. package/libraries/llvm/types.c +43 -0
  61. package/libraries/ml/effekt.sml +65 -0
  62. package/libraries/ml/internal/mllist.effekt +9 -0
  63. package/libraries/ml/internal/mloption.effekt +18 -0
  64. package/libraries/ml/random.effekt +85 -0
  65. package/libraries/ml/text/regex.effekt +102 -0
  66. package/licenses/THIRD-PARTY.txt +21 -0
  67. package/licenses/apache-2.0 - license-2.0.txt +202 -0
  68. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
  69. package/licenses/kiama-license.txt +373 -0
  70. package/licenses/kiama-readme.txt +186 -0
  71. package/licenses/mit license - mit-license.html +1239 -0
  72. package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
  73. package/licenses/the bsd license - bsd-license.html +1237 -0
  74. package/licenses/the mit license - mit.html +1239 -0
  75. package/package.json +26 -18
@@ -0,0 +1,687 @@
1
+ module list
2
+
3
+ import effekt
4
+ import option
5
+ import exception
6
+
7
+ // Immutable linked list for finite sequences of elements.
8
+ type List[A] {
9
+ Nil();
10
+ Cons(head: A, tail: List[A])
11
+ }
12
+
13
+ // Create an empty list.
14
+ //
15
+ // O(1)
16
+ def empty[A](): List[A] = Nil()
17
+
18
+ // Create a list with one element.
19
+ //
20
+ // O(1)
21
+ def singleton[A](x: A): List[A] = Cons(x, Nil())
22
+
23
+ // Create a list of length `size` where all elements are `default`.
24
+ //
25
+ // O(size)
26
+ def fill[A](size: Int, default: A): List[A] = {
27
+ build(size) { i => default }
28
+ }
29
+
30
+ // Create a list from a function `index` of given `size`.
31
+ //
32
+ // O(size)
33
+ def build[A](size: Int) { index: Int => A }: List[A] = {
34
+ var result = empty()
35
+ each(0, size) { i =>
36
+ result = Cons(index(i), result)
37
+ }
38
+ result.reverse
39
+ }
40
+
41
+ // Check if list is empty.
42
+ //
43
+ // O(1)
44
+ def isEmpty[A](l: List[A]): Bool = l match {
45
+ case Nil() => true
46
+ case Cons(a, rest) => false
47
+ }
48
+
49
+ // Check if list is nonempty.
50
+ //
51
+ // O(1)
52
+ def nonEmpty[A](l: List[A]): Bool = l match {
53
+ case Nil() => false
54
+ case Cons(a, rest) => true
55
+ }
56
+
57
+ // Return the first element of a given list.
58
+ // Throws a `MissingValue` exception if it's empty.
59
+ //
60
+ // O(1)
61
+ def head[A](l: List[A]): A / Exception[MissingValue] = l match {
62
+ case Nil() => do raise(MissingValue(), "Trying to get the head of an empty list")
63
+ case Cons(a, rest) => a
64
+ }
65
+
66
+ // Return all elements of a given list except the first element.
67
+ // Throws a `MissingValue` exception if it's empty.
68
+ //
69
+ // O(1)
70
+ def tail[A](l: List[A]): List[A] / Exception[MissingValue] = l match {
71
+ case Nil() => do raise(MissingValue(), "Trying to get the head of an empty list")
72
+ case Cons(a, rest) => rest
73
+ }
74
+
75
+ // Return the first element of a given list.
76
+ // Returns `None()` if it's empty.
77
+ //
78
+ // O(1)
79
+ def headOption[A](l: List[A]): Option[A] = l match {
80
+ case Nil() => None()
81
+ case Cons(a, rest) => Some(a)
82
+ }
83
+
84
+ // Returns the last element of a given list.
85
+ //
86
+ // O(N)
87
+ def last[A](l: List[A]): A / Exception[MissingValue] = {
88
+ def go(list: List[A]): A = {
89
+ list match {
90
+ case Nil() => do raise(MissingValue(), "Trying to get the last element of an empty list")
91
+ case Cons(x, Nil()) => x
92
+ case Cons(x, xs) => go(xs)
93
+ }
94
+ }
95
+
96
+ go(l)
97
+ }
98
+
99
+ // Get the value at given index.
100
+ //
101
+ // O(N)
102
+ def get[A](list: List[A], index: Int): A / Exception[OutOfBounds] = {
103
+ def go(list: List[A], i: Int): A = {
104
+ list match {
105
+ case Nil() => do raise(OutOfBounds(), "Trying to get an element outside the bounds of a list")
106
+ case Cons(x, xs) and i == 0 => x
107
+ case Cons(x, xs) => go(xs, i - 1)
108
+ }
109
+ }
110
+
111
+ go(list, index)
112
+ }
113
+
114
+ // Traverse a list, applying the given action on every element.
115
+ //
116
+ // O(N)
117
+ def foreach[A](l: List[A]) { f: (A) => Unit } : Unit = l match {
118
+ case Nil() => ()
119
+ case Cons(head, tail) => f(head); tail.foreach {f}
120
+ }
121
+
122
+ // Traverse a list, applying the given action on every element.
123
+ //
124
+ // O(N)
125
+ def foreach[A](l: List[A]) { f: (A) {Control} => Unit } : Unit = {
126
+ var remainder = l
127
+ loop { {label} =>
128
+ remainder match {
129
+ case Nil() => label.break()
130
+ case Cons(head, tail) =>
131
+ remainder = tail
132
+ f(head) {label}
133
+ }
134
+ }
135
+ }
136
+
137
+ // Traverse a list, applying the given action on every element and its (zero-based) index.
138
+ //
139
+ // O(N)
140
+ def foreachIndex[A](list: List[A]){ f: (Int, A) => Unit }: Unit = {
141
+ def loop(index: Int, remainder: List[A]): Unit = remainder match {
142
+ case Nil() => ()
143
+ case Cons(head, tail) =>
144
+ f(index, head);
145
+ loop(index + 1, tail)
146
+ }
147
+ loop(0, list)
148
+ }
149
+
150
+ // Traverse a list, applying the given action on every element and its (zero-based) index.
151
+ //
152
+ // O(N)
153
+ def foreachIndex[A](list: List[A]){ f: (Int, A) {Control} => Unit }: Unit = {
154
+ var remainder = list
155
+ var i = -1
156
+ loop { {label} =>
157
+ remainder match {
158
+ case Nil() => label.break()
159
+ case Cons(head, tail) =>
160
+ remainder = tail
161
+ i = i + 1
162
+ f(i, head) {label}
163
+ }
164
+ }
165
+ }
166
+
167
+ // Map a function `f` over elements in a given list.
168
+ //
169
+ // O(N)
170
+ def map[A, B](l: List[A]) { f: A => B } : List[B] = {
171
+ var acc = Nil[B]()
172
+ l.foreach { el => acc = Cons(f(el), acc) }
173
+ acc.reverse
174
+ }
175
+
176
+ // Map a function `f` over elements in a given list,
177
+ // keeping only the elements for which the function returned `Some(...)`,
178
+ // discarding the elements for which the function returned `None()`.
179
+ //
180
+ // O(N)
181
+ def collect[A, B](l: List[A]) { f : A => Option[B] }: List[B] = {
182
+ var acc = Nil[B]()
183
+ l.foreach { a =>
184
+ val optB = f(a)
185
+ optB match {
186
+ case None() => ();
187
+ case Some(b) => acc = Cons(b, acc);
188
+ }
189
+ }
190
+ acc.reverse
191
+ }
192
+
193
+ // Map a function `f` over elements in a given list and concatenate the results.
194
+ //
195
+ // O(N)
196
+ def flatMap[A, B](l: List[A]) { f : A => List[B] }: List[B] = {
197
+ var acc = Nil[B]()
198
+ l.foreach { a =>
199
+ val bs = f(a)
200
+ acc = acc.append(bs)
201
+ }
202
+ acc
203
+ }
204
+
205
+ // Check if predicate is true for all elements of the given list.
206
+ //
207
+ // O(N)
208
+ def all[A](list: List[A]) { predicate: A => Bool }: Bool = {
209
+ list match {
210
+ case Cons(x, xs) => predicate(x) && all(xs) { predicate }
211
+ case Nil() => true
212
+ }
213
+ }
214
+
215
+ // Check if predicate is true for at least one element of the given list.
216
+ //
217
+ // O(N)
218
+ def any[A](list: List[A]) { predicate: A => Bool }: Bool = {
219
+ list match {
220
+ case Cons(x, xs) => predicate(x) || any(xs) { predicate }
221
+ case Nil() => false
222
+ }
223
+ }
224
+
225
+ // Sum the elements of the list.
226
+ //
227
+ // O(N)
228
+ def sum(list: List[Int]): Int = {
229
+ var n = 0;
230
+ list.foreach { x => n = n + x };
231
+ n
232
+ }
233
+
234
+ // Calculate the size of the list.
235
+ //
236
+ // O(N)
237
+ def size[A](l: List[A]): Int = {
238
+ var n = 0;
239
+ l.foreach { _ => n = n + 1 };
240
+ n
241
+ }
242
+
243
+ // Reverse the list.
244
+ //
245
+ // O(N)
246
+ def reverse[A](l: List[A]): List[A] = {
247
+ var res = Nil[A]()
248
+ l.foreach { el => res = Cons(el, res) }
249
+ res
250
+ }
251
+
252
+ // Reverse a list `l` and append `other` to it.
253
+ //
254
+ // Example:
255
+ // ```
256
+ // > [1,2,3].reverseOnto([4,5,6])
257
+ // [3,2,1,4,5,6]
258
+ // ```
259
+ //
260
+ // O(|l|)
261
+ def reverseOnto[A](l: List[A], other: List[A]): List[A] = l match {
262
+ case Nil() => other
263
+ case Cons(a, rest) => rest.reverseOnto(Cons(a, other))
264
+ }
265
+
266
+ // Concatenate list `l` with list `other`:
267
+ //
268
+ // Example:
269
+ // ```
270
+ // > [1,2,3].append([4,5,6])
271
+ // [1,2,3,4,5,6]
272
+ // ```
273
+ //
274
+ // O(N)
275
+ def append[A](l: List[A], other: List[A]): List[A] =
276
+ l.reverse.reverseOnto(other)
277
+
278
+ // Flatten a list of lists into a single list.
279
+ //
280
+ // Examples:
281
+ // ```
282
+ // > [[1, 2, 3], [4, 5], [6]].join()
283
+ // [1, 2, 3, 4, 5, 6]
284
+ //
285
+ // > [[]].join()
286
+ // []
287
+ // ```
288
+ //
289
+ // O(N)
290
+ def join[A](lists: List[List[A]]): List[A] = {
291
+ var acc: List[A] = Nil()
292
+ lists.foreach { list =>
293
+ acc = acc.append(list)
294
+ }
295
+ acc
296
+ }
297
+
298
+ // Flatten a list of lists into a single list,
299
+ // putting the `between` list in between each list in the input.
300
+ //
301
+ // Examples:
302
+ // ```
303
+ // > [[100], [200, 300], [400]].join([1, 2, 3])
304
+ // [100, 1, 2, 3, 200, 300, 1, 2, 3, 400]
305
+ //
306
+ // > [[]].join([1, 2, 3])
307
+ // []
308
+ // ```
309
+ //
310
+ // O(N)
311
+ def join[A](lists: List[List[A]], between: List[A]): List[A] = {
312
+ lists match {
313
+ case Nil() => Nil()
314
+ case Cons(firstList, restOfLists) =>
315
+ firstList.append(
316
+ restOfLists.flatMap { list => between.append(list)}
317
+ )
318
+ }
319
+ }
320
+
321
+ // Take the first `n` elements of a given list.
322
+ //
323
+ // Examples:
324
+ // ```
325
+ // > [1, 2, 3].take(2)
326
+ // [1, 2]
327
+ //
328
+ // > [1, 2, 3].take(0)
329
+ // []
330
+ //
331
+ // > [1, 2, 3].take(3)
332
+ // [1, 2, 3]
333
+ //
334
+ // > [1, 2, 3].take(5)
335
+ // [1, 2, 3]
336
+ //
337
+ // > [1, 2, 3].take(-1)
338
+ // []
339
+ // ```
340
+ //
341
+ // O(n)
342
+ def take[A](l: List[A], n: Int): List[A] =
343
+ if (n <= 0) {
344
+ Nil()
345
+ } else l match {
346
+ case Nil() => Nil()
347
+ case Cons(a, rest) => Cons(a, rest.take(n - 1))
348
+ }
349
+
350
+ // Drop the first `n` elements of a given list.
351
+ //
352
+ // Examples:
353
+ // ```
354
+ // > [1, 2, 3].drop(2)
355
+ // [3]
356
+ //
357
+ // > [1, 2, 3].drop(0)
358
+ // [1, 2, 3]
359
+ //
360
+ // > [1, 2, 3].drop(3)
361
+ // []
362
+ //
363
+ // > [1, 2, 3].drop(5)
364
+ // []
365
+ //
366
+ // > [1, 2, 3].drop(-1)
367
+ // [1, 2, 3]
368
+ // ```
369
+ //
370
+ // O(n)
371
+ def drop[A](l: List[A], n: Int): List[A] =
372
+ if (n <= 0) {
373
+ l
374
+ } else l match {
375
+ case Nil() => Nil()
376
+ case Cons(a, rest) => rest.drop(n - 1)
377
+ }
378
+
379
+ // Return a slice of a given list from the starting index (inclusive)
380
+ // to the given end index (exclusive).
381
+ //
382
+ // Examples:
383
+ // ```
384
+ // > [1, 2, 3, 4, 5, 6].slice(1, 4)
385
+ // [2, 3, 4]
386
+ //
387
+ // > [1, 2, 3, 4, 5, 6].slice(1, 2)
388
+ // [2]
389
+ //
390
+ // > [1, 2, 3, 4, 5, 6].slice(1, 1)
391
+ // []
392
+ //
393
+ // > [1, 2, 3, 4, 5, 6].slice(4, 1)
394
+ // []
395
+ //
396
+ // > [1, 2, 3, 4, 5, 6].slice(-100, 100)
397
+ // [1, 2, 3, 4, 5, 6]
398
+ // ```
399
+ //
400
+ // O(N)
401
+ def slice[A](list: List[A], start: Int, stopExclusive: Int): List[A] = {
402
+ val prefix = list.drop(start)
403
+ val length = stopExclusive - start
404
+ prefix.take(length)
405
+ }
406
+
407
+ // Split the list at given index.
408
+ //
409
+ // Law: `val (l, r) = list.splitAt(i); l.append(r) === list`
410
+ //
411
+ // O(N)
412
+ def splitAt[A](list: List[A], index: Int): (List[A], List[A]) = {
413
+ (list.take(index), list.drop(index))
414
+ }
415
+
416
+ // Update the element at given index in the list using the `update` function.
417
+ // Returns the original list if the index is out of bounds.
418
+ //
419
+ // See: `modifyAt`
420
+ // Examples:
421
+ // ```
422
+ // > [1, 2, 3].updateAt(1) { n => n + 100 }
423
+ // [1, 102, 3]
424
+ //
425
+ // > [1, 2, 3].updateAt(10) { n => n + 100 }
426
+ // [1, 2, 3]
427
+ // ```
428
+ //
429
+ // O(N)
430
+ def updateAt[A](list: List[A], index: Int) { update: A => A }: List[A] = {
431
+ list.splitAt(index) match {
432
+ case (left, Cons(x, right)) =>
433
+ left.append(Cons(update(x), right))
434
+ case _ => list
435
+ }
436
+ }
437
+
438
+ // Modify the element at given index in the list using the `update` function.
439
+ // Throws `OutOfBounds` if the index is out of bounds.
440
+ //
441
+ // See: `updateAt`
442
+ // Examples:
443
+ // ```
444
+ // > [1, 2, 3].modifyAt(1) { n => n + 100 }
445
+ // Some([1, 102, 3])
446
+ //
447
+ // > [1, 2, 3].modifyAt(10) { n => n + 100 }
448
+ // None()
449
+ // ```
450
+ //
451
+ // O(N)
452
+ def modifyAt[A](list: List[A], index: Int) { update: A => A }: List[A] / Exception[OutOfBounds] = {
453
+ list.splitAt(index) match {
454
+ case (left, Cons(x, right)) =>
455
+ left.append(Cons(update(x), right))
456
+ case _ => do raise(OutOfBounds(), "Trying to modify an element outside the bounds of a list")
457
+ }
458
+ }
459
+
460
+ // Delete the element at given index in the list.
461
+ //
462
+ // Example:
463
+ // ```
464
+ // > [1, 2, 3, 4].deleteAt(1)
465
+ // [1, 3, 4]
466
+ //
467
+ // > [1, 2, 3, 4].deleteAt(-1)
468
+ // [1, 2, 3, 4]
469
+ //
470
+ // > [1, 2, 3, 4].deleteAt(10)
471
+ // [1, 2, 3, 4]
472
+ // ```
473
+ //
474
+ // O(N)
475
+ def deleteAt[A](list: List[A], index: Int): List[A] = {
476
+ val left = list.slice(0, index)
477
+ val right = list.slice(index + 1, list.size())
478
+ left.append(right)
479
+ }
480
+
481
+ // Add an element at given index in the list.
482
+ //
483
+ // Examples:
484
+ // ```
485
+ // > [1, 2, 3].insert(-1, 0)
486
+ // [0, 1, 2, 3]
487
+ //
488
+ // > [1, 2, 3].insert(0, 0)
489
+ // [0, 1, 2, 3]
490
+ //
491
+ // > [1, 2, 3].insert(1, 0)
492
+ // [1, 0, 2, 3]
493
+ //
494
+ // > [1, 2, 3].insert(3, 0)
495
+ // [1, 2, 3, 0]
496
+ //
497
+ // > [1, 2, 3].insert(10, 0)
498
+ // [1, 2, 3, 0]
499
+ // ```
500
+ //
501
+ // O(N)
502
+ def insert[A](list: List[A], index: Int, x: A): List[A] = {
503
+ val (left, right) = list.splitAt(index)
504
+ left.append(Cons(x, right))
505
+ }
506
+
507
+ // Replace an element at given index in the list.
508
+ // Returns the original list when the index is out of bounds.
509
+ //
510
+ // Examples:
511
+ // ```
512
+ // > [1, 2, 3].replace(0, 42)
513
+ // [42, 2, 3]
514
+ //
515
+ // > [1, 2, 3].replace(-1, 42)
516
+ // [1, 2, 3]
517
+ //
518
+ // > [1, 2, 3].replace(10, 42)
519
+ // [1, 2, 3]
520
+ // ```
521
+ //
522
+ // O(N)
523
+ def replace[A](list: List[A], index: Int, x: A): List[A] = {
524
+ if (index < 0 || index >= list.size()) {
525
+ list
526
+ } else {
527
+ val left = list.take(index)
528
+ val right = list.drop(index + 1)
529
+ left.append(Cons(x, right))
530
+ }
531
+ }
532
+
533
+ // Produce a list of pairs from a pair of lists.
534
+ // The length of the result is the minimum of lengths of the two lists.
535
+ //
536
+ // Examples:
537
+ // ```
538
+ // > zip([1, 2, 3], [100, 200, 300])
539
+ // [(1, 100), (2, 200), (3, 300)]
540
+ //
541
+ // > zip([1, 2, 3], Nil[Int]())
542
+ // []
543
+ //
544
+ // > zip(Nil[Int](), [1, 2, 3])
545
+ // []
546
+ //
547
+ // > zip([1, 2, 3], [42])
548
+ // [(1, 42)]
549
+ // ```
550
+ //
551
+ // O(N)
552
+ def zip[A, B](left: List[A], right: List[B]): List[(A, B)] = {
553
+ def go(acc: List[(A, B)], left: List[A], right: List[B]): List[(A, B)] = {
554
+ (left, right) match {
555
+ case (Cons(a, as), Cons(b, bs)) =>
556
+ val pair = (a, b)
557
+ val newAcc = Cons(pair, acc)
558
+ go(newAcc, as, bs)
559
+ case _ => acc.reverse
560
+ }
561
+ }
562
+ go(Nil(), left, right)
563
+ }
564
+
565
+ // Combine two lists with the given function.
566
+ // The length of the result is the minimum of lengths of the two lists.
567
+ //
568
+ // Examples:
569
+ // ```
570
+ // > zipWith([1, 2, 3], [100, 200, 300]) { (a, b) => a + b }
571
+ // [101, 202, 303]
572
+ //
573
+ // > zipWith([1, 2, 3], Nil[Int]()) { (a, b) => a + b }
574
+ // []
575
+ //
576
+ // > zipWith(Nil[Int](), [1, 2, 3]) { (a, b) => a + b }
577
+ // []
578
+ //
579
+ // > zipWith([1, 2, 3], [42]) { (a, b) => a + b }
580
+ // [43]
581
+ // ```
582
+ //
583
+ // O(N)
584
+ def zipWith[A, B, C](left: List[A], right: List[B]) { combine : (A, B) => C }: List[C] = {
585
+ def go(acc: List[C], left: List[A], right: List[B]): List[C] = {
586
+ (left, right) match {
587
+ case (Cons(a, as), Cons(b, bs)) =>
588
+ val result = combine(a, b)
589
+ val newAcc = Cons(result, acc)
590
+ go(newAcc, as, bs)
591
+ case _ => acc.reverse
592
+ }
593
+ }
594
+ go(Nil(), left, right)
595
+ }
596
+
597
+ // Produce a pair of lists from a list of pairs.
598
+ //
599
+ // Examples:
600
+ // ```
601
+ // > [(1, 100), (2, 200), (3, 300)].unzip()
602
+ // ([1, 2, 3], [100, 200, 300])
603
+ // ```
604
+ //
605
+ // O(N)
606
+ def unzip[A, B](pairs: List[(A, B)]): (List[A], List[B]) = {
607
+ pairs match {
608
+ case Nil() => (Nil(), Nil())
609
+ case Cons((l, r), rest) =>
610
+ val (left, right) = rest.unzip();
611
+ (Cons(l, left), Cons(r, right))
612
+ }
613
+ }
614
+
615
+ // Partition a given list into two lists.
616
+ // The left list contains the elements that satsify the predicate,
617
+ // the right list contains the elements that do not.
618
+ //
619
+ // O(N)
620
+ def partition[A](l: List[A]) { pred: A => Bool }: (List[A], List[A]) = {
621
+ var lefts: List[A] = Nil()
622
+ var rights: List[A] = Nil()
623
+ l.foreach { el =>
624
+ if (pred(el)) {
625
+ lefts = Cons(el, lefts)
626
+ } else {
627
+ rights = Cons(el, rights)
628
+ }
629
+ }
630
+
631
+ (lefts.reverse, rights.reverse)
632
+ }
633
+
634
+ // Sort a list using a given comparison function.
635
+ //
636
+ // Note: this implementation is not stacksafe!
637
+ //
638
+ // O(N log N)
639
+ def sortBy[A](l: List[A]) { compare: (A, A) => Bool }: List[A] =
640
+ l match {
641
+ case Nil() => Nil()
642
+ case Cons(pivot, rest) =>
643
+ val (lt, gt) = rest.partition { el => compare(el, pivot) };
644
+ val leftSorted = sortBy(lt) { (a, b) => compare(a, b) }
645
+ val rightSorted = sortBy(gt) { (a, b) => compare(a, b) }
646
+ leftSorted.append(Cons(pivot, rightSorted))
647
+ }
648
+
649
+ def sort(l: List[Int]): List[Int] = l.sortBy { (a, b) => a < b }
650
+ def sort(l: List[Double]): List[Double] = l.sortBy { (a, b) => a < b }
651
+
652
+ // Check if a list is sorted according to the given comparison function.
653
+ //
654
+ // O(N)
655
+ def isSortedBy[A](list: List[A]) { compare: (A, A) => Bool }: Bool = {
656
+ def go(list: List[A]): Bool = {
657
+ list match {
658
+ case Nil() => true
659
+ case Cons(x, Nil()) => true
660
+ case Cons(x, Cons(y, rest)) =>
661
+ val next = Cons(y, rest) // Future work: Replace this by an @-pattern!
662
+ compare(x, y) && go(next)
663
+ }
664
+ }
665
+ go(list)
666
+ }
667
+
668
+
669
+ // Show Instances
670
+ // --------------
671
+
672
+ def show[A](l: List[A]) { showA: A => String }: String = {
673
+ def go(l: List[A]): String = l match {
674
+ case Nil() => "Nil()"
675
+ case Cons(x, xs) => "Cons(" ++ showA(x) ++ ", " ++ go(xs) ++ ")"
676
+ }
677
+ go(l)
678
+ }
679
+ def show(l: List[Int]): String = show(l) { e => show(e) }
680
+ def show(l: List[Double]): String = show(l) { e => show(e) }
681
+ def show(l: List[Bool]): String = show(l) { e => show(e) }
682
+ def show(l: List[String]): String = show(l) { e => e }
683
+
684
+ def println(l: List[Int]): Unit = println(show(l))
685
+ def println(l: List[Double]): Unit = println(show(l))
686
+ def println(l: List[Bool]): Unit = println(show(l))
687
+ def println(l: List[String]): Unit = println(show(l))