Issue
I've been using kotlin arrow quite a bit recently, and I've ran into a specific use case that has me stuck.
Let's say I have a collection of some object that I want to convert to another datatype using a convert function. Let's also say that this convert function has an ability to fail-- but instead of throwing an exception, it will just return an Either, where Either.Left()
is a failure and Either.Right()
is the mapped object. What is the best way to handle this use case? Some sample code below:
val list: Collection<Object> // some collection
val eithers: List<Either<ConvertError, NewObject>> = list.map { convert(it) } // through some logic, convert each object in the collection
val desired: Either<ConvertError, Collection<NewObject>> = eithers.map { ??? }
fun convert(o: Object) : Either<ConvertError, NewObject> { ... }
Essentially, I'd like to call a mapping function on a collection of data, and if any of the mappings respond with a failure, I'd like to have an Either.Left()
containing the error. And then otherwise, I'd like the Either.Right()
to contain all of the mapped objects.
Any ideas for a clean way to do this? Ideally, I'd like to make a chain of function calls, but have the ability to percolate an error up through the function calls.
Solution
You can use Arrow's computation blocks to unwrap Either
inside map
like so:
import arrow.core.Either
import arrow.core.computations.either
val list: ListObject> // some collection
val eithers: List<Either<ConvertError, NewObject>> = list.map { convert(it) } // through some logic, convert each object in the collection
val desired: Either<ConvertError, Collection<NewObject>> = either.eager {
eithers.map { convert(it).bind() }
}
fun convert(o: Object) : Either<ConvertError, NewObject> { ... }
Here bind()
will either unwrap Either
into NewObject
in the case Either
is Right
, or it will exit the either.eager
block in case it finds Left
with ConvertError
. Here we're using the eager { }
variant since we're assigning it to a val
immediately. The main suspend fun either { }
block supports suspend
functions inside but is itself also a suspend
function.
This is an alternative to the traverse
operator.
The traverse
operation will be simplified in Arrow 0.12.0 to the following:
import arrow.core.traverseEither
eithers.traverseEither(::convert)
The traverse
operator is also available in Arrow Fx Coroutines with support for traversing in parallel, and some powerful derivatives of this operation.
import arrow.fx.coroutines.parTraverseEither
eithers.parTraverseEither(Dispatcheres.IO, ::convert)
Answered By - nomisRev
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.