Skip to content

Instantly share code, notes, and snippets.

@Atternatt
Created December 15, 2022 17:12
Show Gist options
  • Save Atternatt/6eb18c2bdb622ecfe00c3e6d64c4e8d4 to your computer and use it in GitHub Desktop.
Save Atternatt/6eb18c2bdb622ecfe00c3e6d64c4e8d4 to your computer and use it in GitHub Desktop.
//region DSL
class ExecutionCancelationException(val failure: Any?) : RuntimeException()
interface ExecutionScope<in F> {
fun fail(f: F): Nothing = throw ExecutionCancelationException(f)
}
sealed interface Result<out F, out R>
data class Success<out R>(val result: R) : Result<Nothing, R>
data class Fail<out F>(val fail: F) : Result<F, Nothing>
internal interface Execution<out F, out R> {
fun <B> resolve(
ifFail: (F) -> B,
ifSuccess: (R) -> B
): B
}
private class DefaultExecution<F, R>(private val scope: ExecutionScope<F>.() -> R) :
Execution<F, R> {
override fun <B> resolve(ifFail: (F) -> B, ifSuccess: (R) -> B): B {
return try {
ifSuccess(scope(object : ExecutionScope<F> {}))
} catch (resultCancellation: ExecutionCancelationException) {
ifFail(resultCancellation.failure as F)
}
}
}
fun <F, R> result(scope: ExecutionScope<F>.() -> R): Result<F, R> = DefaultExecution(scope).resolve(
ifSuccess = { Success(it) },
ifFail = { Fail(it) }
)
//endregion
context(ExecutionScope<String>)
fun sum(a: Int, b: Int): Int {
return if (a < 0 || b < 0) fail("Both arguments need to be positive")
else a + b
}
//testing functions that ar scoped under ExecutionScope
fun testSum(a: Int, b: Int): Result<String, Int> = result {
val sum1 = sum(a,b)
val sum2 = sum(sum1, b)
sum2
}
fun div(a: Int, b: Int): Result<String, Int> = result {
if (b == 0) fail("Division by 0")
a.div(b)
}
//nesting functions that return Result
fun testDiv(a: Int, b: Int): Result<String, Int> = result {
val firstDiv by div(a, b)
val secondDiv by div(firstDiv, b)
secondDiv
}
context(ExecutionScope<F>)
private operator fun <F, R> Result<F, R>.getValue(
nothing: Nothing?,
property: KProperty<*>
): R =
when (this) {
is Fail -> fail(fail)
is Success -> result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment