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.