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
