I receive an Either<E, List<A>>
from a function call and need to transform the List<A>
into a List<B>
. The transformation of each A returns an Either<E,B>
, so that my result is an Either<E, List<Either<E,B>>>
. How can I turn the Either<E, List<Either<E,B>>>
into an Either<E, List<B>>
,
- if all transformation succeeded (Should result in
Either.Left
, if a single transformation fails) - create an
Either<E,List<B>>
containing all Bs, for which the transformation succeeded and ignoring failed AtoB transformations
A little code snippet below:
fun getListOfA(): Either<Exception, List<A>> {
TODO()
}
fun A.transformAtoB(): Either<Exception, B> {
TODO()
}
fun getListB(): Either<Exception, List<B>> {
return getListOfA().map {
// this is now Either<Exception, List<Either<Exception, B>>>
listOfA -> listOfA.map { it.transformAtoB() }
// ????? => Either<E, List<B>>
}
}
CodePudding user response:
There is a function called traverseEither
that allows you to do these kind of operations.
public inline fun <E, A, B> Iterable<A>.traverseEither(f: (A) -> Either<E, B>): Either<E, List<B>>
For every value of A
in the Iterable
it will call f
, and if all the results are Either.Right
then it will result in Either.Right<List<B>>
and otherwise it will result in the first Either.Left<E>
it encounters.
So we can rewrite your snippet:
fun getListOfA(): Either<Exception, List<A>> = TODO()
fun A.transformAtoB(): Either<Exception, B> = TODO()
fun getListB(): Either<Exception, List<B>> =
getListOfA().flatMap { listOfA ->
// this is now Either<Exception, List<Either<Exception, B>>>
listOfA.traverseEither { it.transformAtoB() }
}
It also exists for Validated
, Option
etc https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/kotlin.collections.-iterable/index.html#extensions-for-kotlincollectionsiterable
And you can also find parallel variants inside Arrow Fx Coroutines