dnowak
05/05/2020, 10:27 AMList<IO<Either<E,A>>>
and I want to stop on first success. How to do this with Arrow?simon.vergauwen
05/05/2020, 10:47 AMtraverse
on List
with EitherT.applicative(IO.applicative())
.
And it should return you the shape EitherT<ForIO, E, List<A>>
by calling value()
you should be able to extract.
IO<Either<E, List,A>>
simon.vergauwen
05/05/2020, 10:48 AMListK
is probably easiest.
I can share a snippet later.dnowak
05/05/2020, 11:16 AMdnowak
05/05/2020, 11:16 AMimport arrow.Kind
import arrow.core.Either
import arrow.core.ForListK
import arrow.core.extensions.list.traverse.traverse
import arrow.core.left
import arrow.core.right
import arrow.fx.ForIO
import <http://arrow.fx.IO|arrow.fx.IO>
import <http://arrow.fx.extensions.io|arrow.fx.extensions.io>.monad.monad
import arrow.fx.fix
import arrow.mtl.EitherT
import arrow.mtl.extensions.eithert.applicative.applicative
import arrow.mtl.value
data class Error(val message: String)
data class Result(val result: String)
fun evaluate(value: Int): IO<Either<Error, Result>> = IO {
if ((value % 5) == 2) {
Result("Success: $value").right()
} else {
Error("Error: $value").left()
}
}
fun main() {
val list: List<IO<Either<Error, Result>>> = List(10) { index -> evaluate(index) }
val result: IO<Either<Error, Kind<ForListK, Result>>> = list.traverse(EitherT.applicative<Error, ForIO>(IO.monad())) {
EitherT(it)
}.value().fix()
val runResult: Either<Error, Kind<ForListK, Result>> = result.unsafeRunSync()
println(runResult)
}
dnowak
05/05/2020, 11:17 AMsimon.vergauwen
05/05/2020, 11:18 AMsimon.vergauwen
05/05/2020, 11:19 AMhandleErrorWith
as composition instead, right? So the first success returns, and they execute in order.simon.vergauwen
05/05/2020, 11:22 AMval ios: List<IO<Either<E, A>>> = TODO()
val eitherT: List<EitherT<ForIO, E, A>> = ios.map { EitherT }
val ioEA: IO<Either<E, A>> = eitherT.fold(EitherT.raiseError(RuntimeException("Initial error")) { acc, a ->
acc.handleErrorwith { a }
}.value()
simon.vergauwen
05/05/2020, 11:23 AMhandleErrorWith
calls.
So you can provide a list
of IO<Either<E, A>>
and it’ll return the first successful Either<E, A>
.simon.vergauwen
05/05/2020, 11:23 AMhandleErrorWith
🙂dnowak
05/05/2020, 12:31 PMsimon.vergauwen
05/05/2020, 12:31 PMdnowak
05/05/2020, 12:41 PMimport arrow.core.Either
import arrow.core.left
import arrow.core.right
import arrow.fx.ForIO
import <http://arrow.fx.IO|arrow.fx.IO>
import <http://arrow.fx.extensions.io|arrow.fx.extensions.io>.monad.monad
import arrow.mtl.EitherT
import arrow.mtl.extensions.eithert.applicativeError.raiseError
data class Error(val message: String)
data class Result(val result: String)
fun evaluate(value: Int): IO<Either<Error, Result>> = IO {
if ((value % 5) == 2) {
Result("Success: $value").right()
} else {
Error("Error: $value").left()
}
}
val ios: List<IO<Either<Error, Result>>> = List(10) { index -> evaluate(index) }
val eitherT: List<EitherT<Error, ForIO, Result>> = ios.map { io -> EitherT(io) }
val ioEA: IO<Either<Error, Result>> = eitherT.fold(EitherT.raiseError(IO.monad(), Error("Initial"))) { acc, a ->
acc.handleErrorwith { a }
}.value().fix()
fun main() {
val result = ioEA.unsafeRunSync()
println(result)
}
simon.vergauwen
05/05/2020, 1:27 PMEitherT
is still missing some useful operator like handleErrorWith
. So I used the one from the underlying IO
directly.dnowak
05/05/2020, 1:43 PMsimon.vergauwen
05/05/2020, 1:43 PMsimon.vergauwen
05/05/2020, 1:44 PMdnowak
05/05/2020, 1:58 PMdnowak
05/05/2020, 1:58 PMval initial = EitherT
.applicativeError<Error, ForIO>(IO.monad())
.raiseError<Error>(Error("Initial error")) as arrow.mtl.EitherT<Error, ForIO, Result>
dnowak
05/05/2020, 2:00 PMLeft(Error(message=Initial))
simon.vergauwen
05/05/2020, 2:00 PMfun <A, F, B> EitherT.Companion.raiseError(a: A): EitherT<A, ForIO, B> = EitherT(IO.just(a.left())
simon.vergauwen
05/05/2020, 2:01 PMdnowak
05/05/2020, 2:14 PMdnowak
05/05/2020, 2:16 PMsimon.vergauwen
05/05/2020, 2:32 PMEitherT
that short-circuits on Throwable
and E
. For example handleBothWith
.
fun <A, B> EitherT<A, IOPartialOf<Nothing>, B>.handleBothWith(
f: (Either<Throwable, A>) -> EitherT<A, IOPartialOf<Nothing>, B>
): EitherT<A, IOPartialOf<Nothing>, B> =
EitherT(value().fix().attempt().flatMap {
when (it) {
is Either.Left -> f(it)
is Either.Right -> when (val bb = it.b) {
is Either.Left -> f(Either.Right(bb.a))
is Either.Right -> EitherT(IO.just(bb))
}
}.value()
})
simon.vergauwen
05/05/2020, 2:33 PMThrowable
and Error
while folding and the first success B
will finish the chain.