Skip to content

Instantly share code, notes, and snippets.

@d-plaindoux
Last active December 3, 2020 08:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d-plaindoux/aa1730a67b003deee86f9974882b1086 to your computer and use it in GitHub Desktop.
Save d-plaindoux/aa1730a67b003deee86f9974882b1086 to your computer and use it in GitHub Desktop.
// Inspired by https://gist.github.com/tanmatra/3c2cec5d5d4345bea7a5f7c105af7238
import Effects.Companion.withEffects
import io.smallibs.utils.Await
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.reflect.KClass
class Effects(var effects: List<Effect<*, *>>) {
data class Effect<E : Any, O>(val klass: KClass<E>, val code: (E) -> (Continuation<O>) -> Unit) {
fun apply(a: E, cont: Continuation<O>): Unit =
code(a)(cont)
}
inline infix fun <reified E : Any, O> effect(noinline code: (E) -> (Continuation<O>) -> Unit): Effects {
effects += Effect(E::class, code)
return this
}
suspend fun <E : Any, O> perform(action: E): O = suspendCoroutine { cont ->
for (anEffect in effects) {
@Suppress("UNCHECKED_CAST")
if (anEffect.klass.isInstance(action)) {
val effect = anEffect as? Effect<E, O>
if (effect != null) {
return@suspendCoroutine effect.apply(action, cont)
}
}
}
throw RuntimeException("No effect found") // TODO(It's also an effect)
}
infix fun handle(block: suspend Effects.() -> Any): Job =
GlobalScope.launch { this@Effects.block() }
companion object {
fun withEffects(block: Effects.() -> Effects): Effects = Effects(listOf()).block()
}
}
object Main {
data class printString(val text: String)
class readString()
fun main() {
withEffects {
effect { p: printString ->
{ k: Continuation<Unit> ->
println(p.text)
k.resume(Unit)
}
}
effect { p: readString ->
{ k: Continuation<String> ->
k.resume("Hello")
}
}
} handle {
val name: String = perform(readString())
perform(printString("Hello $name"))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment