@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,13 +1,8 @@
|
|
|
1
|
-
module
|
|
1
|
+
module list
|
|
2
2
|
|
|
3
3
|
import effekt
|
|
4
|
-
import
|
|
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()
|
|
4
|
+
import option
|
|
5
|
+
import exception
|
|
11
6
|
|
|
12
7
|
// Immutable linked list for finite sequences of elements.
|
|
13
8
|
type List[A] {
|
|
@@ -46,7 +41,7 @@ def build[A](size: Int) { index: Int => A }: List[A] = {
|
|
|
46
41
|
// Check if list is empty.
|
|
47
42
|
//
|
|
48
43
|
// O(1)
|
|
49
|
-
def isEmpty[A](l: List[A]):
|
|
44
|
+
def isEmpty[A](l: List[A]): Bool = l match {
|
|
50
45
|
case Nil() => true
|
|
51
46
|
case Cons(a, rest) => false
|
|
52
47
|
}
|
|
@@ -54,26 +49,26 @@ def isEmpty[A](l: List[A]): Boolean = l match {
|
|
|
54
49
|
// Check if list is nonempty.
|
|
55
50
|
//
|
|
56
51
|
// O(1)
|
|
57
|
-
def nonEmpty[A](l: List[A]):
|
|
52
|
+
def nonEmpty[A](l: List[A]): Bool = l match {
|
|
58
53
|
case Nil() => false
|
|
59
54
|
case Cons(a, rest) => true
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
// Return the first element of a given list.
|
|
63
|
-
// Throws a `
|
|
58
|
+
// Throws a `MissingValue` exception if it's empty.
|
|
64
59
|
//
|
|
65
60
|
// O(1)
|
|
66
|
-
def head[A](l: List[A]): A / Exception[
|
|
67
|
-
case Nil() => do raise(
|
|
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")
|
|
68
63
|
case Cons(a, rest) => a
|
|
69
64
|
}
|
|
70
65
|
|
|
71
66
|
// Return all elements of a given list except the first element.
|
|
72
|
-
// Throws a `
|
|
67
|
+
// Throws a `MissingValue` exception if it's empty.
|
|
73
68
|
//
|
|
74
69
|
// O(1)
|
|
75
|
-
def tail[A](l: List[A]): List[A] / Exception[
|
|
76
|
-
case Nil() => do raise(
|
|
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")
|
|
77
72
|
case Cons(a, rest) => rest
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -86,19 +81,30 @@ def headOption[A](l: List[A]): Option[A] = l match {
|
|
|
86
81
|
case Cons(a, rest) => Some(a)
|
|
87
82
|
}
|
|
88
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
|
+
|
|
89
99
|
// Get the value at given index.
|
|
90
100
|
//
|
|
91
101
|
// O(N)
|
|
92
102
|
def get[A](list: List[A], index: Int): A / Exception[OutOfBounds] = {
|
|
93
|
-
def go(list: List[A], i: Int): A
|
|
103
|
+
def go(list: List[A], i: Int): A = {
|
|
94
104
|
list match {
|
|
95
105
|
case Nil() => do raise(OutOfBounds(), "Trying to get an element outside the bounds of a list")
|
|
96
|
-
case Cons(x, xs) =>
|
|
97
|
-
|
|
98
|
-
x
|
|
99
|
-
} else {
|
|
100
|
-
go(xs, i - 1)
|
|
101
|
-
}
|
|
106
|
+
case Cons(x, xs) and i == 0 => x
|
|
107
|
+
case Cons(x, xs) => go(xs, i - 1)
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
|
|
@@ -108,36 +114,53 @@ def get[A](list: List[A], index: Int): A / Exception[OutOfBounds] = {
|
|
|
108
114
|
// Traverse a list, applying the given action on every element.
|
|
109
115
|
//
|
|
110
116
|
// O(N)
|
|
111
|
-
def foreach[A](l: List[A]) { f: A => Unit
|
|
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 = {
|
|
112
126
|
var remainder = l
|
|
113
|
-
loop {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
} else { do break() }
|
|
127
|
+
loop { {label} =>
|
|
128
|
+
remainder match {
|
|
129
|
+
case Nil() => label.break()
|
|
130
|
+
case Cons(head, tail) =>
|
|
131
|
+
remainder = tail
|
|
132
|
+
f(head) {label}
|
|
133
|
+
}
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
// Traverse a list, applying the given action on every element and its (zero-based) index.
|
|
126
138
|
//
|
|
127
139
|
// O(N)
|
|
128
|
-
def foreachIndex[A](list: List[A]){ f: (Int, A) => Unit
|
|
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 = {
|
|
129
154
|
var remainder = list
|
|
130
155
|
var i = -1
|
|
131
|
-
loop {
|
|
132
|
-
if (not(remainder.isEmpty)) {
|
|
156
|
+
loop { {label} =>
|
|
133
157
|
remainder match {
|
|
134
|
-
case Nil() => ()
|
|
135
|
-
case Cons(
|
|
136
|
-
remainder =
|
|
158
|
+
case Nil() => label.break()
|
|
159
|
+
case Cons(head, tail) =>
|
|
160
|
+
remainder = tail
|
|
137
161
|
i = i + 1
|
|
138
|
-
f(i,
|
|
162
|
+
f(i, head) {label}
|
|
139
163
|
}
|
|
140
|
-
} else { do break() }
|
|
141
164
|
}
|
|
142
165
|
}
|
|
143
166
|
|
|
@@ -182,7 +205,7 @@ def flatMap[A, B](l: List[A]) { f : A => List[B] }: List[B] = {
|
|
|
182
205
|
// Check if predicate is true for all elements of the given list.
|
|
183
206
|
//
|
|
184
207
|
// O(N)
|
|
185
|
-
def all[A](list: List[A]) { predicate: A =>
|
|
208
|
+
def all[A](list: List[A]) { predicate: A => Bool }: Bool = {
|
|
186
209
|
list match {
|
|
187
210
|
case Cons(x, xs) => predicate(x) && all(xs) { predicate }
|
|
188
211
|
case Nil() => true
|
|
@@ -192,13 +215,31 @@ def all[A](list: List[A]) { predicate: A => Boolean }: Boolean = {
|
|
|
192
215
|
// Check if predicate is true for at least one element of the given list.
|
|
193
216
|
//
|
|
194
217
|
// O(N)
|
|
195
|
-
def any[A](list: List[A]) { predicate: A =>
|
|
218
|
+
def any[A](list: List[A]) { predicate: A => Bool }: Bool = {
|
|
196
219
|
list match {
|
|
197
220
|
case Cons(x, xs) => predicate(x) || any(xs) { predicate }
|
|
198
221
|
case Nil() => false
|
|
199
222
|
}
|
|
200
223
|
}
|
|
201
224
|
|
|
225
|
+
// Fold a list using `f`, starting from the left given a starting value.
|
|
226
|
+
//
|
|
227
|
+
// O(N)
|
|
228
|
+
def foldLeft[A, B](l: List[A], init: B) { f: (B, A) => B }: B = {
|
|
229
|
+
var acc = init;
|
|
230
|
+
l.foreach { x => acc = f(acc, x) };
|
|
231
|
+
acc
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Fold a list using `f`, starting from the right given a starting value.
|
|
235
|
+
//
|
|
236
|
+
// O(N)
|
|
237
|
+
def foldRight[A, B](l: List[A], init: B) { f: (A, B) => B }: B = {
|
|
238
|
+
var acc = init;
|
|
239
|
+
l.reverse.foreach { x => acc = f(x, acc) };
|
|
240
|
+
acc
|
|
241
|
+
}
|
|
242
|
+
|
|
202
243
|
// Sum the elements of the list.
|
|
203
244
|
//
|
|
204
245
|
// O(N)
|
|
@@ -594,7 +635,7 @@ def unzip[A, B](pairs: List[(A, B)]): (List[A], List[B]) = {
|
|
|
594
635
|
// the right list contains the elements that do not.
|
|
595
636
|
//
|
|
596
637
|
// O(N)
|
|
597
|
-
def partition[A](l: List[A]) { pred: A =>
|
|
638
|
+
def partition[A](l: List[A]) { pred: A => Bool }: (List[A], List[A]) = {
|
|
598
639
|
var lefts: List[A] = Nil()
|
|
599
640
|
var rights: List[A] = Nil()
|
|
600
641
|
l.foreach { el =>
|
|
@@ -613,7 +654,7 @@ def partition[A](l: List[A]) { pred: A => Boolean }: (List[A], List[A]) = {
|
|
|
613
654
|
// Note: this implementation is not stacksafe!
|
|
614
655
|
//
|
|
615
656
|
// O(N log N)
|
|
616
|
-
def sortBy[A](l: List[A]) { compare: (A, A) =>
|
|
657
|
+
def sortBy[A](l: List[A]) { compare: (A, A) => Bool }: List[A] =
|
|
617
658
|
l match {
|
|
618
659
|
case Nil() => Nil()
|
|
619
660
|
case Cons(pivot, rest) =>
|
|
@@ -624,14 +665,13 @@ def sortBy[A](l: List[A]) { compare: (A, A) => Boolean }: List[A] =
|
|
|
624
665
|
}
|
|
625
666
|
|
|
626
667
|
def sort(l: List[Int]): List[Int] = l.sortBy { (a, b) => a < b }
|
|
627
|
-
|
|
628
|
-
// Future work: ^ needs `le` for `Double`
|
|
668
|
+
def sort(l: List[Double]): List[Double] = l.sortBy { (a, b) => a < b }
|
|
629
669
|
|
|
630
670
|
// Check if a list is sorted according to the given comparison function.
|
|
631
671
|
//
|
|
632
672
|
// O(N)
|
|
633
|
-
def isSortedBy[A](list: List[A]) { compare: (A, A) =>
|
|
634
|
-
def go(list: List[A]):
|
|
673
|
+
def isSortedBy[A](list: List[A]) { compare: (A, A) => Bool }: Bool = {
|
|
674
|
+
def go(list: List[A]): Bool = {
|
|
635
675
|
list match {
|
|
636
676
|
case Nil() => true
|
|
637
677
|
case Cons(x, Nil()) => true
|
|
@@ -643,36 +683,23 @@ def isSortedBy[A](list: List[A]) { compare: (A, A) => Boolean }: Boolean = {
|
|
|
643
683
|
go(list)
|
|
644
684
|
}
|
|
645
685
|
|
|
646
|
-
// =========================================
|
|
647
|
-
// `show` / `println` overloads for options:
|
|
648
|
-
// =========================================
|
|
649
686
|
|
|
650
|
-
//
|
|
651
|
-
|
|
687
|
+
// Show Instances
|
|
688
|
+
// --------------
|
|
689
|
+
|
|
690
|
+
def show[A](l: List[A]) { showA: A => String }: String = {
|
|
652
691
|
def go(l: List[A]): String = l match {
|
|
653
692
|
case Nil() => "Nil()"
|
|
654
693
|
case Cons(x, xs) => "Cons(" ++ showA(x) ++ ", " ++ go(xs) ++ ")"
|
|
655
694
|
}
|
|
656
695
|
go(l)
|
|
657
696
|
}
|
|
658
|
-
def show(l: List[Int]): String =
|
|
659
|
-
def show(l: List[Double]): String =
|
|
660
|
-
def show(l: List[
|
|
661
|
-
def show(l: List[String]): String =
|
|
697
|
+
def show(l: List[Int]): String = show(l) { e => show(e) }
|
|
698
|
+
def show(l: List[Double]): String = show(l) { e => show(e) }
|
|
699
|
+
def show(l: List[Bool]): String = show(l) { e => show(e) }
|
|
700
|
+
def show(l: List[String]): String = show(l) { e => e }
|
|
662
701
|
|
|
663
|
-
def println(l: List[Int]): Unit =
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
def println(l: List[Double]): Unit = {
|
|
668
|
-
val s: String = show(l)
|
|
669
|
-
println(s)
|
|
670
|
-
}
|
|
671
|
-
def println(l: List[Boolean]): Unit = {
|
|
672
|
-
val s: String = show(l)
|
|
673
|
-
println(s)
|
|
674
|
-
}
|
|
675
|
-
def println(l: List[String]): Unit = {
|
|
676
|
-
val s: String = show(l)
|
|
677
|
-
println(s)
|
|
678
|
-
}
|
|
702
|
+
def println(l: List[Int]): Unit = println(show(l))
|
|
703
|
+
def println(l: List[Double]): Unit = println(show(l))
|
|
704
|
+
def println(l: List[Bool]): Unit = println(show(l))
|
|
705
|
+
def println(l: List[String]): Unit = println(show(l))
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module option
|
|
2
|
+
|
|
3
|
+
import effekt
|
|
4
|
+
import exception
|
|
5
|
+
|
|
6
|
+
type Option[A] {
|
|
7
|
+
None();
|
|
8
|
+
Some(value: A)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def isDefined[A](self: Option[A]): Bool = self match {
|
|
12
|
+
case None() => false
|
|
13
|
+
case Some(v) => true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def isEmpty[A](self: Option[A]): Bool =
|
|
17
|
+
self.isDefined.not
|
|
18
|
+
|
|
19
|
+
def orElse[A](self: Option[A]) { that: => Option[A] }: Option[A] = self match {
|
|
20
|
+
case None() => that()
|
|
21
|
+
case Some(v) => Some(v)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def getOrElse[A](self: Option[A]) { that: => A }: A = self match {
|
|
25
|
+
case None() => that()
|
|
26
|
+
case Some(v) => v
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def map[A, B](self: Option[A]) { f: A => B }: Option[B] = self match {
|
|
30
|
+
case None() => None()
|
|
31
|
+
case Some(v) => Some(f(v))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def foreach[A](self: Option[A]) { f: A => Unit }: Unit = self match {
|
|
35
|
+
case None() => ()
|
|
36
|
+
case Some(v) => f(v)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def value[A](self: Option[A]): A / Exception[MissingValue] = self match {
|
|
40
|
+
case None() => do raise(MissingValue(), "Trying to get the value of an empty option")
|
|
41
|
+
case Some(v) => v
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def option[A] { p: => A / Exception[MissingValue] }: Option[A] =
|
|
45
|
+
try { Some(p()) }
|
|
46
|
+
with Exception[MissingValue] { def raise(_, _) = None() }
|
|
47
|
+
|
|
48
|
+
def option[A, E](proxy: on[E]) { p: => A / Exception[E] }: Option[A] =
|
|
49
|
+
try { Some(p()) }
|
|
50
|
+
with Exception[E] { def raise(_, _) = None() }
|
|
51
|
+
|
|
52
|
+
// Interop with FFI
|
|
53
|
+
// ---------------
|
|
54
|
+
// These functions should only be used by libraries that interface with FFI
|
|
55
|
+
def undefinedToOption[A](value: A): Option[A] =
|
|
56
|
+
if (value.isUndefined) { None() } else { Some(value) }
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// Show Instances
|
|
60
|
+
// --------------
|
|
61
|
+
|
|
62
|
+
def show[A](o: Option[A]) { showA: A => String }: String = o match {
|
|
63
|
+
case None() => "None()"
|
|
64
|
+
case Some(v) => "Some(" ++ showA(v) ++ ")"
|
|
65
|
+
}
|
|
66
|
+
def show(o: Option[Int]): String = show(o) { e => show(e) }
|
|
67
|
+
def show(o: Option[Double]): String = show(o) { e => show(e) }
|
|
68
|
+
def show(o: Option[Bool]): String = show(o) { e => show(e) }
|
|
69
|
+
|
|
70
|
+
def println(o: Option[Int]): Unit = println(show(o))
|
|
71
|
+
def println(o: Option[Double]): Unit = println(show(o))
|
|
72
|
+
def println(o: Option[Bool]): Unit = println(show(o))
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
module queue
|
|
2
|
+
|
|
3
|
+
import array
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mutable, automatically resizing queue.
|
|
7
|
+
*/
|
|
8
|
+
interface Queue[T] {
|
|
9
|
+
def empty?(): Bool
|
|
10
|
+
|
|
11
|
+
def popFront(): Option[T]
|
|
12
|
+
|
|
13
|
+
def popBack(): Option[T]
|
|
14
|
+
|
|
15
|
+
def peekFront(): Option[T]
|
|
16
|
+
|
|
17
|
+
def peekBack(): Option[T]
|
|
18
|
+
|
|
19
|
+
def pushFront(el: T): Unit
|
|
20
|
+
|
|
21
|
+
def pushBack(el: T): Unit
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def emptyQueue[T](): Queue[T] at {global} =
|
|
26
|
+
emptyQueue[T](64)
|
|
27
|
+
|
|
28
|
+
def emptyQueue[T](initialCapacity: Int): Queue[T] at {global} = {
|
|
29
|
+
|
|
30
|
+
var contents in global = array[Option[T]](initialCapacity, None())
|
|
31
|
+
var head in global = 0
|
|
32
|
+
var tail in global = 0
|
|
33
|
+
var size in global = 0
|
|
34
|
+
var capacity in global = initialCapacity
|
|
35
|
+
|
|
36
|
+
def remove(arr: Array[Option[T]], index: Int): Option[T] = {
|
|
37
|
+
with on[OutOfBounds].default { None() };
|
|
38
|
+
val value = arr.get(index);
|
|
39
|
+
arr.set(index, None());
|
|
40
|
+
value
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def nonEmpty[T] { p: => Option[T] / Exception[OutOfBounds] }: Option[T] =
|
|
44
|
+
if (size <= 0) None() else on[OutOfBounds].default { None() } { p() }
|
|
45
|
+
|
|
46
|
+
// Exponential back-off
|
|
47
|
+
def resizeTo(requiredSize: Int): Unit =
|
|
48
|
+
if (requiredSize <= capacity) () else {
|
|
49
|
+
with on[OutOfBounds].ignore // should not happen
|
|
50
|
+
|
|
51
|
+
val oldSize = capacity
|
|
52
|
+
val newSize = capacity * 2
|
|
53
|
+
val oldContents = contents
|
|
54
|
+
val newContents = array::allocate[Option[T]](newSize)
|
|
55
|
+
|
|
56
|
+
if (head < tail) {
|
|
57
|
+
// The queue does not wrap around; direct copy is possible.
|
|
58
|
+
copy(oldContents, head, newContents, 0, size) // changed tail to size
|
|
59
|
+
} else if (size > 0) {
|
|
60
|
+
// The queue wraps around; copy in two segments.
|
|
61
|
+
copy(oldContents, head, newContents, 0, oldSize - head) // changed oldSize to oldSize - head
|
|
62
|
+
copy(oldContents, 0, newContents, oldSize - head, tail) // changed oldSize - head to oldSize - head
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
contents = newContents
|
|
66
|
+
capacity = newSize
|
|
67
|
+
head = 0
|
|
68
|
+
tail = oldSize
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
def queue = new Queue[T] {
|
|
72
|
+
def empty?() = size <= 0
|
|
73
|
+
|
|
74
|
+
def popFront() =
|
|
75
|
+
nonEmpty {
|
|
76
|
+
val result = contents.remove(head)
|
|
77
|
+
head = mod(head + 1, capacity)
|
|
78
|
+
size = size - 1
|
|
79
|
+
result
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
def popBack() =
|
|
83
|
+
nonEmpty {
|
|
84
|
+
tail = mod(tail - 1 + capacity, capacity)
|
|
85
|
+
val result = contents.remove(tail)
|
|
86
|
+
size = size - 1
|
|
87
|
+
result
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
def peekFront() = nonEmpty { contents.get(head) }
|
|
91
|
+
|
|
92
|
+
def peekBack() = nonEmpty { contents.get(tail) }
|
|
93
|
+
|
|
94
|
+
def pushFront(el: T) = {
|
|
95
|
+
resizeTo(size + 1);
|
|
96
|
+
head = mod(head - 1 + capacity, capacity);
|
|
97
|
+
size = size + 1;
|
|
98
|
+
contents.unsafeSet(head, Some(el))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
def pushBack(el: T) = {
|
|
102
|
+
resizeTo(size + 1);
|
|
103
|
+
contents.unsafeSet(tail, Some(el));
|
|
104
|
+
size = size + 1;
|
|
105
|
+
tail = mod(tail + 1, capacity)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
queue
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
namespace examples {
|
|
112
|
+
def main() = {
|
|
113
|
+
// queue with initial capacity 4
|
|
114
|
+
def b = emptyQueue[Int](4);
|
|
115
|
+
println(b.empty?);
|
|
116
|
+
b.pushFront(1);
|
|
117
|
+
b.pushBack(2);
|
|
118
|
+
b.pushFront(3);
|
|
119
|
+
b.pushBack(4);
|
|
120
|
+
// this will cause resizing:
|
|
121
|
+
b.pushBack(5);
|
|
122
|
+
b.pushBack(6);
|
|
123
|
+
b.pushBack(7);
|
|
124
|
+
b.pushBack(8);
|
|
125
|
+
// and again:
|
|
126
|
+
b.pushBack(9);
|
|
127
|
+
|
|
128
|
+
println(b.empty?);
|
|
129
|
+
println(b.popFront()); // Some(3)
|
|
130
|
+
println(b.popFront()); // Some(1)
|
|
131
|
+
println(b.popFront()); // Some(2)
|
|
132
|
+
println(b.popFront()); // Some(4)
|
|
133
|
+
println(b.popFront()); // Some(5)
|
|
134
|
+
println(b.popFront()); // Some(6)
|
|
135
|
+
println(b.popFront()); // Some(7)
|
|
136
|
+
println(b.popFront()); // Some(8)
|
|
137
|
+
println(b.popFront()); // Some(9)
|
|
138
|
+
println(b.popFront()); // None()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module ref
|
|
2
|
+
|
|
3
|
+
import effekt
|
|
4
|
+
|
|
5
|
+
extern js """
|
|
6
|
+
function set$impl(ref, value) {
|
|
7
|
+
ref.value = value;
|
|
8
|
+
return $effekt.unit;
|
|
9
|
+
}
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Global, mutable references
|
|
14
|
+
*/
|
|
15
|
+
extern type Ref[T]
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Allocates a new reference of size `size`, keeping its value _undefined_.
|
|
19
|
+
* Prefer using `ref` constructor instead to ensure that the value is defined.
|
|
20
|
+
*/
|
|
21
|
+
extern global def allocate[T](): Ref[T] =
|
|
22
|
+
js "{ value: undefined }"
|
|
23
|
+
chez "(box #f)"
|
|
24
|
+
llvm """
|
|
25
|
+
%z = call %Pos @c_ref_fresh(%Pos zeroinitializer)
|
|
26
|
+
ret %Pos %z
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new reference with the initial value `init`.
|
|
31
|
+
*/
|
|
32
|
+
extern global def ref[T](init: T): Ref[T] =
|
|
33
|
+
js "{ value: ${init} }"
|
|
34
|
+
chez "(box ${init})"
|
|
35
|
+
llvm """
|
|
36
|
+
%z = call %Pos @c_ref_fresh(%Pos ${init})
|
|
37
|
+
ret %Pos %z
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Gets the referenced element of the `ref` in constant time.
|
|
42
|
+
*/
|
|
43
|
+
extern global def get[T](ref: Ref[T]): T =
|
|
44
|
+
js "${ref}.value"
|
|
45
|
+
chez "(unbox ${ref})"
|
|
46
|
+
llvm """
|
|
47
|
+
%z = call %Pos @c_ref_get(%Pos ${ref})
|
|
48
|
+
ret %Pos %z
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Sets the referenced element of the `ref` to `value` in constant time.
|
|
53
|
+
*/
|
|
54
|
+
extern global def set[T](ref: Ref[T], value: T): Unit =
|
|
55
|
+
js "set$impl(${ref}, ${value})"
|
|
56
|
+
chez "(set-box! ${ref} ${value})"
|
|
57
|
+
llvm """
|
|
58
|
+
%z = call %Pos @c_ref_set(%Pos ${ref}, %Pos ${value})
|
|
59
|
+
ret %Pos %z
|
|
60
|
+
"""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module result
|
|
2
|
+
|
|
3
|
+
import effekt
|
|
4
|
+
import option
|
|
5
|
+
import exception
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents the result of a potentially failing computation.
|
|
9
|
+
* It is the "reification" of the Exception[E] effect.
|
|
10
|
+
*/
|
|
11
|
+
type Result[A, E] {
|
|
12
|
+
Error(exception: E, msg: String);
|
|
13
|
+
Success(a: A)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Represent ("reify") the result of a potentially failing computation.
|
|
18
|
+
*/
|
|
19
|
+
def result[A, E] { f: => A / Exception[E] }: Result[A, E] = try {
|
|
20
|
+
Success(f())
|
|
21
|
+
} with Exception[E] {
|
|
22
|
+
def raise(exc, msg) = Error(exc, msg)
|
|
23
|
+
}
|
|
24
|
+
def result[A, E](proxy: on[E]) { f: => A / Exception[E] }: Result[A, E] = try {
|
|
25
|
+
Success(f())
|
|
26
|
+
} with Exception[E] {
|
|
27
|
+
def raise(exc, msg) = Error(exc, msg)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extracts the value of a result, if available
|
|
32
|
+
* Monadic "reflection"
|
|
33
|
+
*/
|
|
34
|
+
def value[A, E](r: Result[A, E]): A / Exception[E] = r match {
|
|
35
|
+
case Success(a) => a
|
|
36
|
+
case Error(exc, msg) => do raise(exc, msg)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts a result to an option forgetting the error details
|
|
41
|
+
*/
|
|
42
|
+
def toOption[A, E](r: Result[A, E]): Option[A] = r match {
|
|
43
|
+
case Success(a) => Some(a)
|
|
44
|
+
case Error(exc, msg) => None()
|
|
45
|
+
}
|