I have a list something like this List<Either<Failure, List<MyResult>>>
and would like to flatten it to Either<Failure, List<MyResult>>
using Arrow-kt but everything I've tried seems pretty clunky and ends up traversing the list twice.
It feels like there should be a better way but I can't figure it out.
Here's a contrived example of what I have now:
val things : List<MyThing> = /* some stuff */
val results : List<Either<Failure, List<MyResult>>> = things.map { doThingThatReturnsEither(it) }
val successes : List<MyResult> = results.mapNotNull { it.orNull() }.flatten()
val firstFailure : Failure? = results.mapNotNull { it.swap().orNull() }.firstOrNull()
return firstFailure?.let {it.left()} ?: success.right()
Any suggestions welcome!
Bonus question: is there a way to shortcut things.map { }
if one of them comes back with a Left
?
The function you are looking for is sequence
val res:Either<Failure, List<MyResult>> = results.sequence(Either.applicative())
.fix()
.map { it.fix() }
this will short circuit on the first Failure
(if any) and return it as left, or give you all of MyResult
as list.
the fix()
and map { it.fix() }
is needed because of Arrow's emulation of higher kinded types.