@effekt-lang/effekt 0.2.1 → 0.2.2

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 (91) 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.effekt +221 -0
  8. package/libraries/chez/callcc/effekt.ss +31 -0
  9. package/libraries/chez/callcc/seq.ss +44 -0
  10. package/libraries/chez/callcc/seq0.ss +69 -0
  11. package/libraries/chez/callcc/tail.ss +76 -0
  12. package/libraries/chez/callcc/tail0.ss +89 -0
  13. package/libraries/chez/common/effekt_matching.ss +100 -0
  14. package/libraries/chez/common/effekt_primitives.ss +97 -0
  15. package/libraries/chez/common/immutable/cslist.effekt +31 -0
  16. package/libraries/chez/common/immutable/dequeue.effekt +78 -0
  17. package/libraries/chez/common/immutable/list.effekt +643 -0
  18. package/libraries/chez/common/immutable/option.effekt +39 -0
  19. package/libraries/chez/common/immutable/result.effekt +29 -0
  20. package/libraries/chez/common/io/args.effekt +20 -0
  21. package/libraries/chez/common/mutable/array.effekt +27 -0
  22. package/libraries/chez/common/mutable/dict.effekt +30 -0
  23. package/libraries/chez/common/mutable/heap.effekt +12 -0
  24. package/libraries/chez/common/test.effekt +59 -0
  25. package/libraries/chez/common/text/pregexp.scm +772 -0
  26. package/libraries/chez/common/text/regex.effekt +33 -0
  27. package/libraries/chez/common/text/string.effekt +46 -0
  28. package/libraries/chez/lift/effekt.effekt +217 -0
  29. package/libraries/chez/lift/effekt.ss +118 -0
  30. package/libraries/chez/monadic/effekt.effekt +218 -0
  31. package/libraries/chez/monadic/effekt.ss +84 -0
  32. package/libraries/chez/monadic/seq0.ss +76 -0
  33. package/libraries/js/effekt.effekt +284 -0
  34. package/libraries/js/effekt_builtins.js +26 -0
  35. package/libraries/js/effekt_matching.js +79 -0
  36. package/libraries/js/effekt_runtime.js +385 -0
  37. package/libraries/js/immutable/dequeue.effekt +78 -0
  38. package/libraries/js/immutable/list.effekt +643 -0
  39. package/libraries/js/immutable/option.effekt +49 -0
  40. package/libraries/js/immutable/result.effekt +29 -0
  41. package/libraries/js/io/args.effekt +9 -0
  42. package/libraries/js/io/async.effekt +28 -0
  43. package/libraries/js/io/async.js +2 -0
  44. package/libraries/js/io/file.effekt +50 -0
  45. package/libraries/js/io/file_include.js +13 -0
  46. package/libraries/js/mutable/array.effekt +98 -0
  47. package/libraries/js/mutable/heap.effekt +32 -0
  48. package/libraries/js/mutable/map.effekt +32 -0
  49. package/libraries/js/test.effekt +59 -0
  50. package/libraries/js/text/regex.effekt +34 -0
  51. package/libraries/js/text/string.effekt +64 -0
  52. package/libraries/js/unsafe/cont.effekt +11 -0
  53. package/libraries/js/web/dom.effekt +45 -0
  54. package/libraries/llvm/buffer.c +181 -0
  55. package/libraries/llvm/effekt.effekt +243 -0
  56. package/libraries/llvm/forward-declare-c.ll +24 -0
  57. package/libraries/llvm/hole.c +11 -0
  58. package/libraries/llvm/immutable/list.effekt +678 -0
  59. package/libraries/llvm/immutable/option.effekt +53 -0
  60. package/libraries/llvm/immutable/result.effekt +29 -0
  61. package/libraries/llvm/io/args.effekt +24 -0
  62. package/libraries/llvm/io.c +24 -0
  63. package/libraries/llvm/main.c +39 -0
  64. package/libraries/llvm/rts.ll +619 -0
  65. package/libraries/llvm/sanity.c +16 -0
  66. package/libraries/llvm/text/string.effekt +179 -0
  67. package/libraries/llvm/types.c +20 -0
  68. package/libraries/ml/effekt.effekt +267 -0
  69. package/libraries/ml/effekt.sml +63 -0
  70. package/libraries/ml/immutable/dequeue.effekt +81 -0
  71. package/libraries/ml/immutable/list.effekt +674 -0
  72. package/libraries/ml/immutable/option.effekt +53 -0
  73. package/libraries/ml/immutable/result.effekt +29 -0
  74. package/libraries/ml/immutable/seq.effekt +903 -0
  75. package/libraries/ml/internal/option.effekt +18 -0
  76. package/libraries/ml/io/args.effekt +41 -0
  77. package/libraries/ml/mutable/array.effekt +43 -0
  78. package/libraries/ml/random.effekt +85 -0
  79. package/libraries/ml/test.effekt +60 -0
  80. package/libraries/ml/text/regex.effekt +107 -0
  81. package/libraries/ml/text/string.effekt +81 -0
  82. package/licenses/THIRD-PARTY.txt +21 -0
  83. package/licenses/apache-2.0 - license-2.0.txt +202 -0
  84. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
  85. package/licenses/kiama-license.txt +373 -0
  86. package/licenses/kiama-readme.txt +186 -0
  87. package/licenses/mit license - mit-license.html +769 -0
  88. package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
  89. package/licenses/the bsd license - bsd-license.html +762 -0
  90. package/licenses/the mit license - mit.html +769 -0
  91. package/package.json +26 -18
@@ -0,0 +1,179 @@
1
+ module text/string
2
+
3
+ import immutable/option
4
+ import immutable/list
5
+
6
+ extern pure def length(s: String): Int = """
7
+ %x = call %Int @c_buffer_length(%Pos %s)
8
+ call void @c_buffer_refcount_decrement(%Pos %s)
9
+ ret %Int %x
10
+ """
11
+ extern pure def substring(s: String, start: Int, end: Int): String = """
12
+ %x = call %Pos @c_buffer_substring(%Pos %s, i64 %start, i64 %end)
13
+ call void @c_buffer_refcount_decrement(%Pos %s)
14
+ ret %Pos %x
15
+ """
16
+ def unsafeCharAt(s: String, i: Int): String = substring(s, i, i+1)
17
+
18
+ def charAt(str: String, i: Int): Option[String] = {
19
+ if ( i < 0 || i >= length(str)) {
20
+ None()
21
+ } else {
22
+ Some(unsafeCharAt(str, i))
23
+ }
24
+ }
25
+
26
+ def startsWith(str: String, prefix: String): Boolean = {
27
+ if (length(str) < length(prefix)) {
28
+ false
29
+ } else {
30
+ substring(str, 0, length(prefix)) == prefix
31
+ }
32
+ }
33
+ def map(str: String){ f: String => String }: String = {
34
+ def rec(i: Int, acc: String): String = {
35
+ if (i < length(str)) {
36
+ rec(i+1, acc ++ f(unsafeCharAt(str, i)))
37
+ } else acc
38
+ }
39
+ rec(0, "")
40
+ }
41
+ def map[A](str: String){ f: String => A }: List[A] = {
42
+ def rec(i: Int): List[A] = {
43
+ if (i < length(str)) {
44
+ Cons(f(unsafeCharAt(str, i)), rec(i+1))
45
+ } else Nil()
46
+ }
47
+ rec(0)
48
+ }
49
+ def indexOf(str: String, start: Int, substr: String): Option[Int] = {
50
+ if(length(str) - start < length(substr)) {
51
+ None()
52
+ } else if(substring(str, start, start + length(substr)) == substr) {
53
+ Some(start)
54
+ } else {
55
+ indexOf(str, start + 1, substr)
56
+ }
57
+ }
58
+ // """ // fix some parsing bug for vscode syntax highlighting
59
+
60
+ def showQuoted(s: String): String =
61
+ "\x22" ++ map(s){ c =>
62
+ if(c == "\x22") {
63
+ "\\\x22"
64
+ } else if (c == "\\") {
65
+ "\\\\"
66
+ } else c
67
+ } ++ "\x22"
68
+ def showQuoted(l: List[String]): String = showList(l){e => showQuoted(e)}
69
+ def showQuoted(o: Option[String]): String = showOption(o){ e => showQuoted(e) }
70
+
71
+ def toInt(s: String): Option[Int] = {
72
+ def go(i: Int, acc: Int): Int / Exception[RuntimeError] = {
73
+ if(i >= length(s)) {
74
+ acc
75
+ } else if(unsafeCharAt(s, i) == "0") {
76
+ go(i + 1, 10 * acc + 0)
77
+ } else if(unsafeCharAt(s, i) == "1") {
78
+ go(i + 1, 10 * acc + 1)
79
+ } else if(unsafeCharAt(s, i) == "2") {
80
+ go(i + 1, 10 * acc + 2)
81
+ } else if(unsafeCharAt(s, i) == "3") {
82
+ go(i + 1, 10 * acc + 3)
83
+ } else if(unsafeCharAt(s, i) == "4") {
84
+ go(i + 1, 10 * acc + 4)
85
+ } else if(unsafeCharAt(s, i) == "5") {
86
+ go(i + 1, 10 * acc + 5)
87
+ } else if(unsafeCharAt(s, i) == "6") {
88
+ go(i + 1, 10 * acc + 6)
89
+ } else if(unsafeCharAt(s, i) == "7") {
90
+ go(i + 1, 10 * acc + 7)
91
+ } else if(unsafeCharAt(s, i) == "8") {
92
+ go(i + 1, 10 * acc + 8)
93
+ } else if(unsafeCharAt(s, i) == "9") {
94
+ go(i + 1, 10 * acc + 9)
95
+ } else {
96
+ raise("Not an integer")
97
+ }
98
+ }
99
+ try {
100
+ if(s.length == 0) {
101
+ None()
102
+ } else if(s.startsWith("-")) {
103
+ Some(0 - go(1, 0))
104
+ } else {
105
+ Some(go(0, 0))
106
+ }
107
+ } with Exception[RuntimeError] {
108
+ def raise(e: RuntimeError, msg: String) = {
109
+ None()
110
+ }
111
+ }
112
+ }
113
+ def toBoolean(s: String): Option[Boolean] = {
114
+ if(s == "true") {
115
+ Some(true)
116
+ } else if (s == "false") {
117
+ Some(false)
118
+ } else {
119
+ None()
120
+ }
121
+ }
122
+
123
+
124
+ // Byte arrays (for compatibility with other backends, we have the Bytes type)
125
+ type Bytes = String
126
+ def bytes(s: String): Bytes = s
127
+ // length(Bytes) = length(String)
128
+ extern pure def unsafeIndex(s: Bytes, i: Int): Int = """
129
+ %x = call %Int @c_buffer_index(%Pos %s, i64 %i)
130
+ call void @c_buffer_refcount_decrement(%Pos %s)
131
+ ret %Int %x
132
+ """
133
+ // """ // fix some parsing bug for vscode syntax highlighting
134
+ def index(b: Bytes, i: Int): Option[Int] = if(i < b.length) { Some(b.unsafeIndex(i)) } else { None() }
135
+
136
+ def eachInRange(b: Bytes, start: Int, end: Int){ fn: Int => Unit }: Unit = {
137
+ if(end < 0 || end > b.length) {
138
+ b.eachInRange(start,b.length){fn}
139
+ }
140
+ def rec(start: Int): Unit = {
141
+ if(start < end) {
142
+ fn(b.unsafeIndex(start))
143
+ rec(start+1)
144
+ } else { () }
145
+ }
146
+ rec(start)
147
+ }
148
+ def each(b: Bytes){ fn: Int => Unit } = {
149
+ b.eachInRange(0,b.length){fn}
150
+ }
151
+
152
+ effect Abort(): Unit // TODO: Maybe use Control effect
153
+ def occursAt(subb: Bytes, b: Bytes, i: Int): Boolean = {
154
+ if(i + subb.length <= b.length) {
155
+ try{
156
+ var x = 0;
157
+ b.eachInRange(i, i + subb.length){ b =>
158
+ if(b != subb.unsafeIndex(x)){ do Abort() }
159
+ x = x + 1
160
+ }
161
+ true
162
+ } with Abort {
163
+ () => false
164
+ }
165
+ } else false
166
+ }
167
+ def split(b: String, sep: String): List[String] = {
168
+ def rec(next: Int, done: Int, acc: List[String]): List[Bytes] = {
169
+ if(sep.occursAt(b, next)) {
170
+ rec(next - 1, next,
171
+ Cons(b.substring(next + sep.length, done), acc))
172
+ } else if(next == 0) {
173
+ Cons(b.substring(0, done), acc)
174
+ } else {
175
+ rec(next - 1, done, acc)
176
+ }
177
+ }
178
+ rec(b.length - sep.length, b.length, Nil())
179
+ }
@@ -0,0 +1,20 @@
1
+ #ifndef EFFEKT_TYPES_C
2
+ #define EFFEKT_TYPES_C
3
+
4
+
5
+ typedef int64_t Int;
6
+ typedef double Double;
7
+
8
+ struct Pos {
9
+ uint64_t tag; // type-local tag
10
+ void *obj; // pointer into the heap
11
+ };
12
+
13
+ static const struct Pos Unit = (struct Pos) { .tag = 0, .obj = NULL, };
14
+ static const struct Pos BooleanFalse = (struct Pos) { .tag = 0, .obj = NULL, };
15
+ static const struct Pos BooleanTrue = (struct Pos) { .tag = 1, .obj = NULL, };
16
+
17
+ typedef struct Pos String;
18
+
19
+
20
+ #endif
@@ -0,0 +1,267 @@
1
+ // Based on libraries\js\monadic\effekt.effekt
2
+
3
+ module effekt
4
+
5
+ extern include "effekt.sml"
6
+
7
+ def locally[R] { f: => R }: R = f()
8
+
9
+ // Side effecting ops
10
+ // ==================
11
+ def println(value: Int): Unit = println(value.show)
12
+ def println(value: Unit): Unit = println(value.show)
13
+ def println(value: Double): Unit = println(value.show)
14
+ def println(value: Boolean): Unit = println(value.show)
15
+
16
+ def println(value: String): Unit = print(value ++ "\n")
17
+ extern io def print(value: String): Unit = "print ${value}"
18
+
19
+ extern io def random(): Double =
20
+ "mlRandomReal ()"
21
+
22
+ // TODO: js is absolute, but that is too big for 32-bit ints
23
+ extern io def timestamp(): Int =
24
+ "IntInf.toInt ((Time.toMilliseconds (Time.now ())) - mlStartTime)"
25
+
26
+ // String ops
27
+ // ==========
28
+ extern pure def show(value: Int): String =
29
+ "show'int ${value}"
30
+ extern pure def show(value: Unit): String =
31
+ "show'unit ${value}"
32
+ extern pure def show(value: Double): String =
33
+ "show'real ${value}"
34
+ extern pure def show(value: String): String =
35
+ "show'string ${value}"
36
+ extern pure def show(value: Boolean): String =
37
+ "show'bool ${value}"
38
+
39
+ extern pure def infixConcat(s1: String, s2: String): String =
40
+ "${s1} ^ ${s2}"
41
+
42
+ // Math ops
43
+ // ========
44
+ extern pure def infixAdd(x: Int, y: Int): Int =
45
+ "(${x}: int) + ${y}"
46
+
47
+ extern pure def infixMul(x: Int, y: Int): Int =
48
+ "(${x}: int) * ${y}"
49
+
50
+ extern pure def infixDiv(x: Int, y: Int): Int =
51
+ "(${x}: int) div ${y}"
52
+
53
+ extern pure def infixSub(x: Int, y: Int): Int =
54
+ "(${x}: int) - ${y}"
55
+
56
+ extern pure def mod(x: Int, y: Int): Int =
57
+ "(${x}: int) mod ${y}"
58
+
59
+ extern pure def infixAdd(x: Double, y: Double): Double =
60
+ "(${x}: real) + ${y}"
61
+
62
+ extern pure def infixMul(x: Double, y: Double): Double =
63
+ "(${x}: real) * ${y}"
64
+
65
+ extern pure def infixSub(x: Double, y: Double): Double =
66
+ "(${x}: real) - ${y}"
67
+
68
+ extern pure def infixDiv(x: Double, y: Double): Double =
69
+ "(${x}: real) / ${y}"
70
+
71
+ def min(n: Int, m: Int): Int =
72
+ if (n < m) n else m
73
+
74
+ def max(n: Int, m: Int): Int =
75
+ if (n > m) n else m
76
+
77
+ // trig
78
+ // ====
79
+
80
+ extern pure def cos(x: Double): Double =
81
+ "Math.cos ${x}"
82
+
83
+ extern pure def sin(x: Double): Double =
84
+ "Math.sin ${x}"
85
+
86
+ extern pure def atan(x: Double): Double =
87
+ "Math.atan ${x}"
88
+
89
+ extern pure def tan(x: Double): Double =
90
+ "Math.tan ${x}"
91
+
92
+ extern pure def sqrt(x: Double): Double =
93
+ "Math.sqrt ${x}"
94
+
95
+ extern pure def square(x: Double): Double =
96
+ "(${x}: real) * ${x}"
97
+
98
+ extern pure def log(x: Double): Double =
99
+ "Math.ln ${x}"
100
+
101
+ extern pure def log1p(x: Double): Double =
102
+ "Math.ln (${x} + 1.0)"
103
+
104
+ extern pure def exp(x: Double): Double =
105
+ "Math.exp ${x}"
106
+
107
+ // since we do not have "extern val", yet
108
+ extern pure def _pi(): Double =
109
+ "Math.pi"
110
+
111
+ val PI: Double = _pi()
112
+
113
+ extern pure def toInt(d: Double): Int =
114
+ "Real.round ${d}"
115
+
116
+ extern pure def toDouble(d: Int): Double =
117
+ "Real.fromInt ${d}"
118
+
119
+ extern pure def floor(d: Double): Int =
120
+ "Real.floor ${d}"
121
+
122
+ extern pure def ceil(d: Double): Int =
123
+ "Real.ceil ${d}"
124
+
125
+
126
+ // Comparison ops
127
+ // ==============
128
+ extern pure def infixEq[R](x: R, y: R): Boolean =
129
+ "${x} = ${y}"
130
+
131
+ extern pure def infixNeq[R](x: R, y: R): Boolean =
132
+ "not (${x} = ${y})"
133
+
134
+ extern pure def infixLt(x: Int, y: Int): Boolean =
135
+ "(${x}: int) < ${y}"
136
+
137
+ extern pure def infixLte(x: Int, y: Int): Boolean =
138
+ "(${x}: int) <= ${y}"
139
+
140
+ extern pure def infixGt(x: Int, y: Int): Boolean =
141
+ "(${x}: int) > ${y}"
142
+
143
+ extern pure def infixGte(x: Int, y: Int): Boolean =
144
+ "(${x}: int) >= ${y}"
145
+
146
+ extern pure def infixLt(x: Double, y: Double): Boolean =
147
+ "(${x}: real) < ${y}"
148
+
149
+ extern pure def infixLte(x: Double, y: Double): Boolean =
150
+ "(${x}: real) <= ${y}"
151
+
152
+ extern pure def infixGt(x: Double, y: Double): Boolean =
153
+ "(${x}: real) > ${y}"
154
+
155
+ extern pure def infixGte(x: Double, y: Double): Boolean =
156
+ "(${x}: real) >= ${y}"
157
+
158
+ extern pure def infixLt(x: String, y: String): Boolean =
159
+ "(${x}: string) < ${y}"
160
+
161
+ extern pure def infixLte(x: String, y: String): Boolean =
162
+ "(${x}: string) <= ${y}"
163
+
164
+ extern pure def infixGt(x: String, y: String): Boolean =
165
+ "(${x}: string) > ${y}"
166
+
167
+ extern pure def infixGte(x: String, y: String): Boolean =
168
+ "(${x}: string) >= ${y}"
169
+
170
+ // Boolean ops
171
+ // ===========
172
+ extern pure def not(b: Boolean): Boolean =
173
+ "not ${b}"
174
+
175
+ extern pure def infixOr(x: Boolean, y: Boolean): Boolean =
176
+ "${x} orelse ${y}"
177
+
178
+ extern pure def infixAnd(x: Boolean, y: Boolean): Boolean =
179
+ "${x} andalso ${y}"
180
+
181
+ // Pairs
182
+ // =====
183
+ record Tuple2[A, B](first: A, second: B)
184
+ record Tuple3[A, B, C](first: A, second: B, third: C)
185
+ record Tuple4[A, B, C, D](first: A, second: B, third: C, fourth: D)
186
+ record Tuple5[A, B, C, D, E](first: A, second: B, third: C, fourth: D, fifth: E)
187
+ record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth: E, sixth: F)
188
+
189
+ // Exceptions
190
+ // ==========
191
+ // a fatal runtime error that cannot be caught
192
+ extern io def panic[R](msg: String): R =
193
+ "raise Fail ${msg}"
194
+
195
+ interface Exception[E] {
196
+ def raise(exception: E, msg: String): Nothing
197
+ }
198
+ record RuntimeError()
199
+
200
+ def raise[A](msg: String): A / Exception[RuntimeError] = do raise(RuntimeError(), msg) match {}
201
+ def raise[A, E](exception: E, msg: String): A / Exception[E] = do raise(exception, msg) match {}
202
+
203
+ // converts exceptions of (static) type E to an uncatchable panic that aborts the program
204
+ def panicOn[E] { prog: => Unit / Exception[E] }: Unit =
205
+ try { prog() } with Exception[E] { def raise(exception: E, msg: String) = panic(msg) }
206
+
207
+ // reports exceptions of (static) type E to the console
208
+ def report[E] { prog: => Unit / Exception[E] }: Unit =
209
+ try { prog() } with Exception[E] { def raise(exception: E, msg: String) = println(msg) }
210
+
211
+ // ignores exceptions of (static) type E
212
+ // TODO this should be called "ignore" but that name currently clashes with internal pattern matching names on $effekt
213
+ def ignoring[E] { prog: => Unit / Exception[E] }: Unit =
214
+ try { prog() } with Exception[E] { def raise(exception: E, msg: String) = () }
215
+
216
+ // Control Flow
217
+ // ============
218
+ interface Control {
219
+ def break(): Unit
220
+ def continue(): Unit
221
+ }
222
+
223
+ def loop { f: () => Unit / Control }: Unit = try {
224
+ def go(): Unit = { f(); go() }
225
+ go()
226
+ } with Control {
227
+ def break() = ()
228
+ def continue() = loop { f }
229
+ }
230
+
231
+ /**
232
+ * Calls provided action repeatedly. `start` is inclusive, `end` is not.
233
+ */
234
+ def each(start: Int, end: Int) { action: (Int) => Unit / Control } = {
235
+ var i = start;
236
+ loop {
237
+ if (i < end) { val el = i; i = i + 1; action(el) }
238
+ else { do break() }
239
+ }
240
+ }
241
+
242
+ def repeat(n: Int) { action: () => Unit / Control } = each(0, n) { n => action() }
243
+
244
+
245
+
246
+ // Benchmarking
247
+ // ============
248
+
249
+ // runs the block and returns the time in nanoseconds
250
+ def timed { block: => Unit }: Int = {
251
+ val before = timestamp()
252
+ block()
253
+ val after = timestamp()
254
+ 1000 * (after - before)
255
+ }
256
+
257
+ def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
258
+ def run(n: Int, report: Boolean): Unit = {
259
+ if (n <= 0) { () } else {
260
+ val time = timed { block() };
261
+ if (report) { println(time) } else { () };
262
+ run(n - 1, report)
263
+ }
264
+ }
265
+ run(warmup, false)
266
+ run(iterations, true)
267
+ }
@@ -0,0 +1,63 @@
1
+ (* EVIDENCE *)
2
+ fun lift m k1 k2 = m (fn a => k1 a k2);
3
+ fun nested ev1 ev2 m = ev1 (ev2 m);
4
+ fun here x = x;
5
+
6
+ (* REGIONS *)
7
+ (* type region = ((() -> () -> ()) list) ref *)
8
+ fun newRegion () = ref nil
9
+ fun backup cell = fn () => let val oldState = !cell in fn () => cell := oldState end
10
+ fun fresh r init = let val cell = ref init in (r := (backup cell) :: (!r); cell) end
11
+ fun withRegion body =
12
+ let val r = newRegion()
13
+ fun lift m k = let val fields = map (fn f => f()) (!r) in
14
+ m (fn a => (map (fn f => f()) fields; k a)) end
15
+ in body lift r end
16
+
17
+ (* SHOW INSTANCES *)
18
+ fun show'int x =
19
+ let val s = (Int.toString x) in
20
+ case String.sub (s, 0) of
21
+ #"~" => "-" ^ String.extract (s, 1, NONE)
22
+ | _ => s
23
+ end;
24
+
25
+ (*
26
+ To align with the js backend inf and nan is rewritten
27
+ - `nan` -> `NaN`
28
+ - `inf` -> `Infinity`
29
+ - `~2.1` -> `-2.1`
30
+ They do still disagree on the truncating of `2.0` to `2` (ml does not).
31
+ *)
32
+ fun show'real x =
33
+ let val s = (Real.toString x) in
34
+ case s of
35
+ "nan" => "NaN"
36
+ | "inf" => "Infinity"
37
+ | _ => case String.sub (s, 0) of
38
+ #"~" => "-" ^ String.extract (s, 1, NONE)
39
+ | _ => s
40
+ end;
41
+
42
+ fun show'unit x = ""
43
+
44
+ fun show'bool x = Bool.toString x
45
+
46
+ fun show'string x = x
47
+
48
+ (* TIMING *)
49
+ val mlStartTime = Time.toMilliseconds (Time.now ());
50
+
51
+ (* RANDOM *)
52
+ fun mlRandomReal () =
53
+ let
54
+ val r = MLton.Random.rand ();
55
+ val rreal = MLton.Real.fromWord r;
56
+ val wsize = Real.fromInt Word.wordSize;
57
+ fun shiftRight r shift = r / (Math.pow(2.0, shift))
58
+ in
59
+ shiftRight rreal wsize
60
+ end;
61
+
62
+ (* HOLES *)
63
+ exception Hole
@@ -0,0 +1,81 @@
1
+ module immutable/dequeue
2
+
3
+ // An implementation of a functional dequeue, using Okasaki's
4
+ // bankers dequeue implementation.
5
+ //
6
+ // Translation from the Haskell implementation:
7
+ // https://hackage.haskell.org/package/dequeue-0.1.12/docs/src/Data-Dequeue.html#Dequeue
8
+ record Dequeue[R](front: List[R], frontSize: Int, rear: List[R], rearSize: Int)
9
+
10
+ def emptyQueue[R](): Dequeue[R] = Dequeue(Nil(), 0, Nil(), 0)
11
+
12
+ def isEmpty[R](dq: Dequeue[R]): Boolean = dq match {
13
+ case Dequeue(f, fs, r, rs) => (fs == 0) && (rs == 0)
14
+ }
15
+
16
+ def size[R](dq: Dequeue[R]): Int = dq match {
17
+ case Dequeue(f, fs, r, rs) => fs + rs
18
+ }
19
+
20
+ def first[R](dq: Dequeue[R]): Option[R] = dq match {
21
+ case Dequeue(f, fs, r, rs) =>
22
+ if ((fs == 0) && (rs == 1)) { r.headOption }
23
+ else { f.headOption }
24
+ }
25
+
26
+ def last[R](dq: Dequeue[R]): Option[R] = dq match {
27
+ case Dequeue(f, fs, r, rs) =>
28
+ if ((fs == 1) && (rs == 0)) { f.headOption }
29
+ else { r.headOption }
30
+ }
31
+
32
+ def check[R](dq: Dequeue[R]): Dequeue[R] = dq match {
33
+ case Dequeue(f, fs, r, rs) =>
34
+ val c = 4;
35
+ val size1 = (fs + rs) / 2;
36
+ val size2 = (fs + rs) - size1;
37
+
38
+ if (fs > c * rs + 1) {
39
+ val front = f.take(size1);
40
+ val rear = r.append(f.drop(size1).reverse);
41
+ Dequeue(front, size1, rear, size2)
42
+ } else if (rs > c * fs + 1) {
43
+ val front = f.append(r.drop(size1).reverse);
44
+ val rear = r.take(size1);
45
+ Dequeue(front, size2, rear, size1)
46
+ } else {
47
+ dq
48
+ }
49
+ }
50
+
51
+ def pushFront[R](dq: Dequeue[R], el: R): Dequeue[R] = dq match {
52
+ case Dequeue(f, fs, r, rs) => Dequeue(Cons(el, f), fs + 1, r, rs).check
53
+ }
54
+
55
+ def popFront[R](dq: Dequeue[R]): Option[(R, Dequeue[R])] = dq match {
56
+ case Dequeue(Nil(), fs, Cons(x, Nil()), rs) =>
57
+ Some((x, emptyQueue()))
58
+ case Dequeue(Nil(), fs, r, rs) =>
59
+ None()
60
+ case Dequeue(Cons(x, rest), fs, r, rs) =>
61
+ Some((x, Dequeue(rest, fs - 1, r, rs).check))
62
+ }
63
+
64
+ def pushBack[R](dq: Dequeue[R], el: R): Dequeue[R] = dq match {
65
+ case Dequeue(f, fs, r, rs) => Dequeue(f, fs, Cons(el, r), rs + 1).check
66
+ }
67
+
68
+ def popBack[R](dq: Dequeue[R]): Option[(R, Dequeue[R])] = dq match {
69
+ case Dequeue(Cons(x, Nil()), fs, Nil(), rs) =>
70
+ Some((x, emptyQueue()))
71
+ case Dequeue(f, fs, Nil(), rs) =>
72
+ None()
73
+ case Dequeue(f, fs, Cons(x, rest), rs) =>
74
+ Some((x, Dequeue(f, fs, rest, rs - 1).check))
75
+ }
76
+
77
+ def show[A](d: Dequeue[A]) { showA: A => String }: String = {
78
+ val Dequeue(front, frontSize, rear, rearSize) = d;
79
+ "Dequeue(" ++ show(front){showA} ++ ", " ++ show(frontSize) ++ ", " ++
80
+ show(rear){showA} ++ ", " ++ show(rearSize) ++ ")"
81
+ }