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