Created
December 15, 2022 17:12
-
-
Save Atternatt/6eb18c2bdb622ecfe00c3e6d64c4e8d4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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