@effekt-lang/effekt 0.4.0 → 0.6.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.
@@ -1,385 +1,218 @@
1
- const $runtime = (function() {
2
1
 
3
- // Common Runtime
4
- // --------------
5
-
6
- // Regions
7
- // TODO maybe use weak refs (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef)
8
- function Cell(init) {
9
- var _value = init;
10
- const cell = ({
11
- backup: function() {
12
- var _backup = _value
13
- var cell = this;
14
- return () => { _value = _backup; return cell }
15
- }
16
- });
17
- // $getOp and $putOp are auto generated from the compiler
18
- cell[$getOp] = function() {
19
- return _value
20
- };
21
- cell[$putOp] = function(v) {
22
- _value = v;
23
- return $effekt.unit;
24
- };
25
- return cell
26
- }
27
-
28
- function Arena() {
29
- return {
30
- fields: [], // Array[Cell],
31
- fresh: function(init) {
32
- const cell = Cell(init)
33
- this.fields.push(cell)
34
- return cell;
35
- },
36
- backup: function() {
37
- return this.fields.map(c => c.backup())
38
- },
39
- restore: function(backup) {
40
- this.fields = backup.map(c => c());
41
- return this
42
- }
43
- }
44
- }
45
-
46
- const global = {
47
- fresh: function(init) { return Cell(init) },
48
- backup: function() {},
49
- restore: function(_) {}
50
- }
51
-
52
- // Lists / Pairs
53
- function Cons(head, tail) {
54
- return { head: head, tail: tail }
55
- }
56
- const Nil = null
57
-
58
- // reverseOnto[A, B, C](init: Frames[A, B], tail: Stack[B, C]): Stack[A, C]
59
- function reverseOnto(init, tail) {
60
- let rest = init;
61
- let result = tail;
62
- while (rest !== Nil) {
63
- result = Cons(rest.head, result)
64
- rest = rest.tail
65
- }
66
- return result
67
- }
68
-
69
- let _prompt = 2;
70
-
71
- // Monadic Style Runtime
72
- // ---------------------
73
-
74
- const toplevel = 1;
75
-
76
- // Result -- Trampoline
77
- function Step(c, k) {
78
- return { isStep: true, c: c, k: k }
79
- }
80
- function trampoline(r) {
81
- var res = r
82
- while (res !== null && res !== undefined && res.isStep) {
83
- res = res.c.apply(res.k)
84
- }
85
- return res
86
- }
87
-
88
- // Frame = A => Control[B]
89
-
90
- // Metacontinuations / Stacks
91
- // (frames: List<Frame>, fields: [Cell], prompt: Int, tail: Stack) -> Stack
92
- function Stack(frames, arena, prompt, tail) {
93
- return { frames: frames, arena: arena, prompt: prompt, tail: tail }
94
- }
95
- function SubStack(frames, arena, backup, prompt, tail) {
96
- return { frames: frames, arena: arena, backup: backup, prompt: prompt, tail: tail }
97
- }
98
- const EmptyStack = null;
99
-
100
- // (stack: Stack<A, B>, a: A) -> Step<B>
101
- function apply(stack, a) {
102
- var s = stack;
103
- while (true) {
104
- if (s === EmptyStack) return a;
105
- const fs = s.frames;
106
- if (fs === Nil) { s = s.tail; continue }
107
- const result = fs.head(a);
108
- s.frames = fs.tail;
109
- return Step(result, s)
110
- }
111
- }
112
-
113
- // (subcont: Stack, stack: Stack) -> Stack
114
- function pushSubcont(subcont, stack) {
115
- var sub = subcont;
116
- var s = stack;
117
-
118
- while (sub !== EmptyStack) {
119
- s = Stack(sub.frames, sub.arena.restore(sub.backup), sub.prompt, s)
120
- sub = sub.tail
2
+ // Common Runtime
3
+ // --------------
4
+ function Cell(init, region) {
5
+ const cell = {
6
+ value: init,
7
+ backup: function() {
8
+ const _backup = cell.value;
9
+ // restore function (has a STRONG reference to `this`)
10
+ return () => { cell.value = _backup; return cell }
121
11
  }
122
- return s;
123
- }
124
-
125
- function flatMap(stack, f) {
126
- if (stack === EmptyStack) { return Stack(Cons(f, Nil), Arena(), null, stack) }
127
- var fs = stack.frames
128
- // it should be safe to mutate the frames field, since they are copied in the subcont
129
- stack.frames = Cons(f, fs)
130
- return stack
131
12
  }
13
+ return cell;
14
+ }
132
15
 
133
- function splitAt(stack, p) {
134
- var sub = EmptyStack;
135
- var s = stack;
16
+ const global = {
17
+ fresh: Cell
18
+ }
136
19
 
137
- while (s !== EmptyStack) {
138
- const currentPrompt = s.prompt;
139
- sub = SubStack(s.frames, s.arena, s.arena.backup(), currentPrompt, sub);
140
- s = s.tail;
141
- if (currentPrompt === p) { return Cons(sub, s) }
142
- }
143
- throw ("Prompt " + p + " not found")
144
- }
145
-
146
- function allocateInto(stack, p, cell) {
147
- var s = stack;
148
-
149
- while (s !== EmptyStack) {
150
- const currentPrompt = s.prompt
151
- if (currentPrompt === p) {
152
- return s.fields.push(cell);
153
- } else {
154
- s = s.tail
20
+ function Arena(_region) {
21
+ const region = _region;
22
+ return {
23
+ fresh: function(init) {
24
+ const cell = Cell(init);
25
+ // region keeps track what to backup, but we do not need to backup unreachable cells
26
+ region.push(new WeakRef(cell))
27
+ return cell;
28
+ },
29
+ region: _region,
30
+ newRegion: function() {
31
+ // a region aggregates weak references
32
+ const nested = Arena([])
33
+ // this doesn't work yet, since Arena.backup doesn't return a thunk
34
+ region.push(new WeakRef(nested))
35
+ return nested;
36
+ },
37
+ backup: function() {
38
+ const _backup = []
39
+ let nextIndex = 0;
40
+ for (const ref of region) {
41
+ // console.log(ref)
42
+ const cell = ref.deref()
43
+ // only backup live cells
44
+ if (cell) {
45
+ _backup[nextIndex] = cell.backup()
46
+ nextIndex++
47
+ }
48
+ }
49
+ function restore() {
50
+ const region = []
51
+ let nextIndex = 0;
52
+ for (const restoreCell of _backup) {
53
+ region[nextIndex] = new WeakRef(restoreCell())
54
+ nextIndex++
55
+ }
56
+ return Arena(region)
155
57
  }
58
+ return restore;
156
59
  }
157
- throw ("Prompt " + p + " not found")
158
60
  }
61
+ }
159
62
 
160
- function withState(init, f) {
161
- return Control(k => {
162
- const cell = k.arena.fresh(init)
163
- return Step(f(cell), k)
164
- })
165
- }
166
63
 
167
- function withRegion(prog) {
168
- return Control(k => {
169
- return Step(prog(k.arena), k)
170
- })
171
- }
64
+ let _prompt = 1;
172
65
 
173
- function withStateIn(prompt, init, f) {
174
- const cell = Cell(init)
66
+ const TOPLEVEL_K = (x, ks) => { throw { computationIsDone: true, result: x } }
67
+ const TOPLEVEL_KS = { prompt: 0, arena: Arena([]), rest: null }
175
68
 
176
- if (prompt === toplevel) {
177
- return f(cell)
178
- } else {
179
- return Control(k => {
180
- allocateInto(k, prompt, cell);
181
- return Step(f(cell), k)
182
- })
183
- }
184
- }
69
+ function THUNK(f) {
70
+ f.thunk = true
71
+ return f
72
+ }
185
73
 
186
- // Delimited Control
187
- function Control(apply) {
188
- const self = {
189
- apply: apply,
190
- run: () => trampoline(Step(self, Stack(Nil, global, toplevel, EmptyStack))),
191
- then: f => Control(k => Step(self, flatMap(k, f))),
192
- state: f => self.then(init => withState(init, f))
193
- }
194
- return self
74
+ function CAPTURE(body) {
75
+ return (ks, k) => {
76
+ const res = body(x => TRAMPOLINE(() => k(x, ks)))
77
+ if (res instanceof Function) return res
78
+ else throw { computationIsDone: true, result: $effekt.unit }
195
79
  }
80
+ }
196
81
 
197
- const pure = a => Control(k => apply(k, a))
198
-
199
- const delayed = a => Control(k => apply(k, a()))
200
-
201
- const shift = (p, f) => Control(k => {
202
- const split = splitAt(k, p)
203
- const localCont = a => Control(k =>
204
- Step(pure(a), pushSubcont(split.head, k)))
205
- return Step(f(localCont), split.tail)
206
- })
207
-
208
- const callcc = f => Control(k => {
209
- return f(a => trampoline(apply(k, a)))
210
- })
82
+ const RETURN = (x, ks) => ks.rest.stack(x, ks.rest)
211
83
 
212
- const abort = Control(k => $effekt.unit)
84
+ // const r = ks.arena.newRegion(); body
85
+ // const x = r.alloc(init); body
213
86
 
87
+ // HANDLE(ks, ks, (p, ks, k) => { STMT })
88
+ function RESET(prog, ks, k) {
89
+ const prompt = _prompt++;
90
+ const rest = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
91
+ return prog(prompt, { prompt, arena: Arena([]), rest }, RETURN)
92
+ }
214
93
 
215
- const capture = f => {
216
- // [abort; f
217
- const action = () => f($effekt.unit).then(() => abort)
218
- return shift(toplevel)(k =>
219
- k({
220
- shouldRun: false,
221
- cont : () => k({ shouldRun: true, cont: action })
222
- })).then(a => a.shouldRun ? a.cont() : $effekt.pure(a.cont))
94
+ function DEALLOC(ks) {
95
+ const arena = ks.arena
96
+ if (!!arena) {
97
+ arena.length = arena.length - 1
223
98
  }
99
+ }
224
100
 
225
- //const reset = (p, c => Control(k => Step(c, Stack(Nil, Arena(), p, k)))
101
+ function SHIFT(p, body, ks, k) {
226
102
 
227
- function handleMonadic(body) {
228
- const p = _prompt++;
229
- return Control(k => Step(body(p), Stack(Nil, Arena(), p, k)))
230
- }
231
-
232
- // Direct Style Runtime
233
- // --------------------
103
+ // TODO avoid constructing this object
104
+ let meta = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
105
+ let cont = null
234
106
 
235
- // sealed trait Resumption[A, R]
236
- // case class Empty[A]() extends Resumption[A, A]
237
- // case class Segment[A, B, C](head: Stack[B, C], prompt: Prompt, tail: Resumption[A, B]) extends Resumption[A, C]
238
- class Segment {
239
- constructor(frames, prompt, region, backup, tail) {
240
- this.frames = frames;
241
- this.prompt = prompt;
242
- this.region = region;
243
- this.backup = backup;
244
- this.tail = tail;
245
- }
107
+ while (!!meta && meta.prompt !== p) {
108
+ cont = { stack: meta.stack, prompt: meta.prompt, backup: meta.arena.backup(), rest: cont }
109
+ meta = meta.rest
246
110
  }
247
- const Empty = null;
111
+ if (!meta) { throw `Prompt not found ${p}` }
248
112
 
249
- // TODO maybe inline later to save native frames
250
- function handleOrRethrow(prompt, s, rest) {
251
- if (!(s instanceof Suspension)) throw s;
113
+ // package the prompt itself
114
+ cont = { stack: meta.stack, prompt: meta.prompt, backup: meta.arena.backup(), rest: cont }
115
+ meta = meta.rest
252
116
 
253
- const region = currentRegion
254
- const k = new Segment(reverseOnto(s.frames, rest), prompt, region, region.backup(), s.cont)
255
- if (s.prompt === prompt) {
256
- return s.body((value) => rewind(k, () => value))
257
- } else {
258
- throw new Suspension(s.prompt, s.body, Nil, k)
259
- }
117
+ function resumeValue(a, ks, k) {
118
+ return resumeComp((ks, k) => k(a, ks), ks, k)
260
119
  }
261
-
262
- function rewind(k, thunk) {
263
- if (k === Empty) {
264
- return thunk()
265
- } else {
266
- const prompt = k.prompt;
267
- const region = k.region;
268
- let rest = k.frames // the pure frames
269
-
270
- // The trampoline
271
- try {
272
- enterRegion(region);
273
- region.restore(k.backup);
274
-
275
- let curr = rewind(k.tail, thunk)
276
- while (rest !== Nil) {
277
- const f = rest.head
278
- rest = rest.tail
279
- curr = f(curr)
280
- }
281
- return curr
282
- } catch (s) {
283
- return handleOrRethrow(prompt, s, rest)
284
- } finally {
285
- leaveRegion()
286
- }
120
+ function resumeComp(c, ks, k) {
121
+ //console.log("Resuming", ks.arena)
122
+ let meta = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
123
+ let toRewind = cont
124
+ while (!!toRewind) {
125
+ meta = { stack: toRewind.stack, prompt: toRewind.prompt, arena: toRewind.backup(), rest: meta }
126
+ toRewind = toRewind.rest
287
127
  }
288
- }
289
-
290
128
 
291
- // case class Suspend[A, X, Y, R](
292
- // body: Continuation[A, R] => R,
293
- // prompt: Prompt,
294
- // pure: Frames[X, Y],
295
- // cont: Resumption[A, X]
296
- // )
297
- class Suspension {
298
- constructor(p, body, frames, cont) {
299
- this.prompt = p;
300
- this.body = body;
301
- this.frames = frames;
302
- this.cont = cont;
303
- }
129
+ const k2 = meta.stack // TODO instead copy meta here, like elsewhere?
130
+ meta.stack = null
131
+ return () => c(meta, k2)
304
132
  }
305
133
 
306
- // initially the toplevel region.
307
- let currentRegion = global
134
+ let k1 = meta.stack
135
+ meta.stack = null
136
+ return body(resumeValue, resumeComp, meta, k1)
137
+ }
308
138
 
309
- // a stack of regions
310
- let regions = []
311
-
312
- function enterRegion(r) {
313
- regions.push(currentRegion)
314
- currentRegion = r
315
- return r
316
- }
317
-
318
- function leaveRegion() {
319
- const leftRegion = currentRegion
320
- currentRegion = regions.pop()
321
- return leftRegion
139
+ function RUN_TOPLEVEL(comp) {
140
+ try {
141
+ let a = comp(TOPLEVEL_KS, TOPLEVEL_K)
142
+ while (true) { a = a() }
143
+ } catch (e) {
144
+ if (e.computationIsDone) return e.result
145
+ else throw e
322
146
  }
147
+ }
323
148
 
324
- return {
325
- // Common API
326
- // -----------
327
- constructor: (_, tag) => function() {
328
- return { __tag: tag, __data: Array.from(arguments) }
329
- },
330
-
331
- hole: function() { throw "Implementation missing" },
332
-
333
- // Monadic API
334
- // -----------
335
- pure: pure,
336
- callcc: callcc,
337
- capture: capture,
338
- delayed: delayed,
339
- handleMonadic: handleMonadic,
340
- ref: Cell,
341
- state: withState,
342
- shift: shift,
343
- _if: (c, thn, els) => c ? thn() : els(),
344
- withRegion: withRegion,
345
-
346
-
347
- // Direct style API
348
- // ----------------
349
- fresh: function(init) {
350
- return currentRegion.fresh(init)
351
- },
352
-
353
- freshPrompt: function() { return ++_prompt; },
354
-
355
- suspend: function(prompt, body) {
356
- _stacksize = 0;
357
- throw new Suspension(prompt, body, Nil, Empty)
358
- },
359
- suspend_bidirectional: function(prompt, caps, body) {
360
- throw new Suspension(prompt, body, Cons(thunk => thunk.apply(null, caps), Nil), Empty)
361
- },
362
-
363
- // suspension: the raised exception.
364
- push: function(suspension, frame) {
365
- if (!(suspension instanceof Suspension)) throw suspension;
366
- // Assuming `suspension` is a value or variable you want to return
367
- throw new Suspension(suspension.prompt, suspension.body,
368
- Cons(frame, suspension.frames), suspension.cont);
369
- },
370
-
371
- handle: function(prompt, s) {
372
- return handleOrRethrow(prompt, s, Nil)
373
- },
374
-
375
- freshRegion: function() {
376
- return enterRegion(new Arena)
377
- },
378
-
379
- leaveRegion: leaveRegion,
380
-
381
- global: global
382
- }
383
- })()
384
-
385
- Object.assign($effekt, $runtime);
149
+ // trampolines the given computation (like RUN_TOPLEVEL, but doesn't provide continuations)
150
+ function TRAMPOLINE(comp) {
151
+ let a = comp;
152
+ try {
153
+ while (true) {
154
+ a = a()
155
+ }
156
+ } catch (e) {
157
+ if (e.computationIsDone) return e.result
158
+ else throw e
159
+ }
160
+ }
161
+
162
+ // keeps the current trampoline going and dispatches the given task
163
+ function RUN(task) {
164
+ return () => task(TOPLEVEL_KS, TOPLEVEL_K)
165
+ }
166
+
167
+ // aborts the current continuation
168
+ function ABORT(value) {
169
+ throw { computationIsDone: true, result: value }
170
+ }
171
+
172
+
173
+ // "Public API" used in FFI
174
+ // ------------------------
175
+
176
+ /**
177
+ * Captures the current continuation as a WHOLE and makes it available
178
+ * as argument to the passed body. For example:
179
+ *
180
+ * $effekt.capture(k => ... k(42) ...)
181
+ *
182
+ * The body
183
+ *
184
+ * $effekt.capture(k => >>> ... <<<)
185
+ *
186
+ * conceptually runs on the _native_ JS call stack. You can call JS functions,
187
+ * like `setTimeout` etc., but you are not expected or required to return an
188
+ * Effekt value like `$effekt.unit`. If you want to run an Effekt computation
189
+ * like in `io::spawn`, you can use `$effekt.run`.
190
+ *
191
+ * Advanced usage details:
192
+ *
193
+ * The value returned by the function passed to `capture` returns
194
+ * - a function: the returned function will be passed to the
195
+ * Effekt runtime, which performs trampolining.
196
+ * In this case, the Effekt runtime will keep running, though the
197
+ * continuation has been removed.
198
+ *
199
+ * - another value (like `undefined`): the Effekt runtime will terminate.
200
+ */
201
+ $effekt.capture = CAPTURE
202
+
203
+ /**
204
+ * Used to call Effekt function arguments in the JS FFI, like in `io::spawn`.
205
+ *
206
+ * Requires an active Effekt runtime (trampoline).
207
+ */
208
+ $effekt.run = RUN
209
+
210
+ /**
211
+ * Used to call Effekt function arguments in the JS FFI, like in `network::listen`.
212
+ *
213
+ * This function should be used when _no_ Effekt runtime is available. For instance,
214
+ * in callbacks passed to the NodeJS eventloop.
215
+ *
216
+ * If a runtime is available, use `$effekt.run`, instead.
217
+ */
218
+ $effekt.runToplevel = RUN_TOPLEVEL
@@ -1,4 +1,4 @@
1
- <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1727705015"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
1
+ <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1729448099"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
2
2
  <i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
3
3
  <button>
4
4
  <i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
@@ -57,5 +57,5 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
57
57
  <i class="fa fa-linkedin fa-stack-1x fa-inverse" aria-hidden=true></i>
58
58
  <span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><li><a href=https://www.eclipse.org/legal/privacy/>Privacy Policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of Use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action=https://eclipsecon.us6.list-manage.com/subscribe/post method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address"><div><i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></div></div><input type=hidden name=u value=eaf9e1f06f194eadc66788a85>
59
59
  <input type=hidden name=id value=46e57eacf1>
60
- <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1727705015"></script>
60
+ <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1729448099"></script>
61
61
  <script>(function(){})(jQuery,document)</script></div></body></html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@effekt-lang/effekt",
3
3
  "author": "Jonathan Brachthäuser",
4
- "version": "0.4.0",
4
+ "version": "0.6.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/effekt-lang/effekt.git"
@@ -1,11 +0,0 @@
1
- module unsafe/cont
2
-
3
- // The type of a captured continuation
4
- extern type Cont[A, B]
5
-
6
- // we mark this as {io} since pure functions should not take block parameters.
7
- extern io def cont[A, B] { r: A => B / {} }: Cont[A, B] = js "${box r}"
8
-
9
- // This is unsafe if the continuation left the scope of the
10
- // capabilities it closed over
11
- extern async def apply[A, B](k: Cont[A, B], a: A): B / {} = js "${k}(${a})"