Youssef Shoaib [MOD]
04/24/2024, 12:21 AM@Composable fun <T> Reset<List<T>>.yield(x: T) = shift { k -> listOf(x) + k(Unit) }
reset<Int> {
maybe {
val value by shift { k -> k(5) }
val value2 by shift { k -> k(value + 1) }
value2
}
} * 2 shouldBe 12
reset {
maybe {
val value by shift { k -> k(k(4)) }
value * 2
}
} + 1 shouldBe 17
reset {
maybe {
yield(1).bind()
yield(2).bind()
yield(3).bind()
emptyList()
}
} shouldBe listOf(1, 2, 3)
All of this was done with the help of coroutines and Compose. All without any dirty tricks with cloning continuations or anything. Only annoying things about it are:
• You need to call bind
or by
on the shift
• You need to surround the body of reset in maybe
• You need to surround any side-effect or heavy-calculation in an effect
block
The first 2 issues are Compose limitations around throwing exceptions, but in theory they should be supported eventually
The 3rd one is unavoidable due to how compose works. Everything inside shift
or effect
will run the proper number of times, but anything outside will run as many times as the continuation is run. It's annoying, but again merely surrounding your code in effect
fixes the issue.