Łukasz Gendek
02/06/2023, 12:47 PMimport arrow.core.Either
import arrow.core.continuations.Raise
import arrow.core.continuations.either
object DivisionByZero
data class IntegerParseError(val value: String)
context(Raise<IntegerParseError>)
fun parseIntegerCt(a: String) : Int = a.toIntOrNull() ?: raise(IntegerParseError(a))
context(Raise<DivisionByZero>)
fun divideIntegersCt(a: Int, b: Int): Int = if (b == 0)
raise(DivisionByZero)
else
a / b
context(Raise<IntegerParseError>, Raise<DivisionByZero>)
fun divideStrings(a: String, b: String): Int = divideIntegersCt(parseIntegerCt(a), parseIntegerCt(b))
fun parseInteger(a: String) : Either<IntegerParseError, Int> = either { parseIntegerCt(a) }
fun divideIntegers(a: Int, b: Int): Either<DivisionByZero, Int> = either {divideIntegersCt(a, b)}
fun divideStrings(a: String, b: String) : Either<IntegerParseError, Either<DivisionByZero, Int>> {
TODO()
//how to call divideStringsCt and return Either containing all possible cases
//could it be implemented it in a generic way?
}
I am not sure how to implement the divideStrings method, Could you help me?simon.vergauwen
02/06/2023, 12:54 PMcontext(Raise<IntegerParseError>, Raise<DivisionByZero>)
fun divideStrings(a: String, b: String): Int =
While providing the order in which you want the errors to be returned, int his case it should be inferable from the return type.
fun divideStrings(a: String, b: String) : Either<IntegerParseError, Either<DivisionByZero, Int>> = either {
either { divideStrings(a, b) }
}
Are these signatures not conflicting though? 🤔
context(Raise<IntegerParseError>, Raise<DivisionByZero>)
fun divideStrings(a: String, b: String): Int
fun divideStrings(a: String, b: String) : Either<IntegerParseError, Either<DivisionByZero, Int>>
Also not sure what you meant with:
// could it be implemented it in a generic way?
If you were trying to build an example using the other Either
functions you can do it the same as the other one but you'd be required calling bind
.
fun divideStrings(a: String, b: String) : Either<IntegerParseError, Either<DivisionByZero, Int>> = either {
either {
divideIntegers(
parseInteger(a).bind(),
parseInteger(b).bind()
).bind()
}
}
Łukasz Gendek
02/06/2023, 3:59 PMfun divideStrings(a: String, b: String) : Either<IntegerParseError, Either<DivisionByZero, Int>> = either {
either { divideStrings(a, b) }
}
By the generic implementation I meant the code below, but it unfortunately does not compile.simon.vergauwen
02/06/2023, 4:14 PMYoussef Shoaib [MOD]
02/07/2023, 7:48 PM@Suppress("SUBTYPING_BETWEEN_CONTEXT_RECEIVERS")
Łukasz Gendek
02/08/2023, 9:58 AMsimon.vergauwen
02/08/2023, 9:59 AMeither outer@ {
either inner@ {
block(outer, inner)
}
}
TypePlacedHolder<C>
into the argument position of the lambda, or the call sites won't resolve correctly.
@OptIn(ExperimentalContracts::class)
inline fun <A, B, C, R> with(a: A, b: B, c: C, block: context(A, B, C) (TypePlacedHolder<C>) -> R): R {
contract { callsInPlace(block, EXACTLY_ONCE) }
return block(a, b, c, TypePlacedHolder)
}
sealed interface TypePlacedHolder<out A> {
companion object : TypePlacedHolder<Nothing>
}
Łukasz Gendek
02/08/2023, 10:04 AM@Suppress("SUBTYPING_BETWEEN_CONTEXT_RECEIVERS")
public fun <E1, E2, A> eitherC(block: context(Raise<E1>, Raise<E2>)() -> A): Either<E1, Either<E2, A>> = either outer@{
either inner@{
block(this@outer, this@inner)
}
}