Skip to content

Commit e6a3736

Browse files
Add DIY Binder example (#999)
I quickly sketched this after talking to @jiribenes about how we could potentially add custom implementations of something like `while` with binders. (He said I should add it as an example.): ```effekt effect lookupX(): Int def whil{ cond: [R]{ => R / lookupX }{ => R } => R }{ body: => Unit / lookupX }: Unit = { cond{ body(); whil{cond}{body} }{ () } } def main() = { var x = Some(12) // desugared cond def cond[R]{thn: => R / lookupX}{els: => R} = { if(x is Some(y)){ try { thn() } with lookupX{ () => resume(y) } } else { els() } } whil{ cond }{ println(do lookupX()) x = Some(do lookupX() - 1) if (do lookupX() == 0) { x = None() } } x = Some(12) whil{ cond }{ println(do lookupX()) x = Some(do lookupX() - 1) if (do lookupX() == 0) { x = None() } } } ``` Surprisingly (to me), this generates reasonable JS: ```javascript function main_2(ks_8, k_7) { const x_2 = ks_8.arena.fresh(new Some_0(12)); function whil_worker_6(ks_9, k_5) { whil_worker_7: while (true) { const s_3 = x_2.value; switch (s_3.__tag) { case 1: const y_3 = s_3.value_0; const tmp_5 = $effekt.println(('' + y_3)); x_2.set(new Some_0((y_3 - (1)))); if (y_3 === (0)) { x_2.set(new None_0()); /* prepare call */ continue whil_worker_7; } else { /* prepare call */ continue whil_worker_7; } break; default: return () => k_5($effekt.unit, ks_9); } } } return whil_worker_6(ks_8, (_1, ks_10) => { function whil_worker_8(ks_11, k_6) { whil_worker_9: while (true) { const s_4 = x_2.value; switch (s_4.__tag) { case 1: const y_4 = s_4.value_0; const tmp_6 = $effekt.println(('' + y_4)); x_2.set(new Some_0((y_4 - (1)))); if (y_4 === (0)) { x_2.set(new None_0()); /* prepare call */ continue whil_worker_9; } else { /* prepare call */ continue whil_worker_9; } break; default: return () => k_6($effekt.unit, ks_11); } } } return whil_worker_8(ks_10, (tmp_7, ks_12) => () => k_7(tmp_7, ks_12)); }); } ```
1 parent 7347c5a commit e6a3736

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

effekt/jvm/src/test/scala/effekt/core/VMTests.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,21 @@ class VMTests extends munit.FunSuite {
819819
shifts = 0,
820820
resumes = 0
821821
)),
822+
examplesDir / "pos" / "diy_binder.effekt" -> Some(Summary(
823+
staticDispatches = 28,
824+
dynamicDispatches = 0,
825+
patternMatches = 28,
826+
branches = 26,
827+
pushedFrames = 1,
828+
poppedFrames = 1,
829+
allocations = 30,
830+
closures = 0,
831+
variableReads = 28,
832+
variableWrites = 29,
833+
resets = 0,
834+
shifts = 0,
835+
resumes = 0
836+
)),
822837
)
823838

824839
val testFiles: Seq[(File, Option[Summary])] =

examples/pos/diy_binder.check

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
12
2+
11
3+
10
4+
9
5+
8
6+
7
7+
6
8+
5
9+
4
10+
3
11+
2
12+
1
13+
0
14+
12
15+
11
16+
10
17+
9
18+
8
19+
7
20+
6
21+
5
22+
4
23+
3
24+
2
25+
1
26+
0

examples/pos/diy_binder.effekt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
effect lookupX(): Int
2+
3+
// With parametric polymorphism on effects, this could be
4+
// def whil[E: EffectSet]{ cond: [R]{ => R / E }{ => R } => R }{ body: => Unit / E }: Unit
5+
def whil{ cond: [R]{ => R / lookupX }{ => R } => R }{ body: => Unit / lookupX }: Unit = {
6+
cond{ body(); whil{cond}{body} }{ () }
7+
}
8+
9+
def main() = {
10+
var x = Some(12)
11+
// desugared cond
12+
def cond[R]{thn: => R / lookupX}{els: => R} = {
13+
if(x is Some(y)){
14+
try { thn() } with lookupX{ () => resume(y) }
15+
} else { els() }
16+
}
17+
whil{ cond }{
18+
println(do lookupX())
19+
x = Some(do lookupX() - 1)
20+
if (do lookupX() == 0) {
21+
x = None()
22+
}
23+
}
24+
x = Some(12)
25+
whil{ cond }{
26+
println(do lookupX())
27+
x = Some(do lookupX() - 1)
28+
if (do lookupX() == 0) {
29+
x = None()
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)