---- (off topic from the previous question) --- Le...
# arrow
d
---- (off topic from the previous question) --- Let's say I have a function like this:
fun doSomething(name:String): Either<FailReason,Int>
and I have a
names:List<String>
. I could do
val result:List<Either<FailReason,Int>> = names.map { doSomething(it) }
which is going to give me a list of
Either
instances. Fine. Now let's assume I want the iteration to stop upon the first case that
doSomething()
returns a left. This could be done using a sequence like this:
Copy code
val result2:Either<FailReason,Int> = names.asSequence().map { doSomething(it) }.first { it is Either.Left }
but it's going to return the first left that fails, or the right that results from the last call to
doSomething()
. All intermediate "right" values will be discarded. What if I wanted it to return
Either<FailReason,List<Int>>
? Essentially, return the first left (terminating any subsequent calls to
doSomething()
), or a list of all the rights? Does Arrow provide any help here? (Also I'm not looking for a solution involving while loops or mutable variables.)
Here's one possible solution:
Copy code
fun <F,A,B> Sequence<F>.shortCircuitEither(fn: (F) -> Either<A,B>): Either<A,List<B>> {
        val items = mutableListOf<B>()
        this.forEach {item ->
            fn(item).fold(
                { return it.left() },
                { items.add(it) }
            )
        }
        return items.right()
    }
Usage:
val result =names.asSequence().shortCircuitEither { doSomething(it) }
Result will be Either a left value containing the first fail, or a List of all the right values.
p
what you’re looking for is called
sequence
, which is a specialised
traverse
names.traverse(Either.applicative()) { doSomething(it) }
that returns
Either<Error, List<Bla>>
if
doSomething
returns
Either<Error, Bla>
if you already have a
List<Either<Error, Bla>>
just call
sequence(Either.applicative())
d
ah thanks!
@pakoito follow on question...
traverse
doesn't actually return an
Either
, everything's wrapped in a
Kind
. Example:
Copy code
val numbers = listOf(3,5,0,1,10)
fun fn(a:Int):Either<FailReason, Int> = if (a == 0) FailReason.left() else a.right()
val traverseResult:Kind<EitherPartialOf<FailReason>, Kind<ForListK, Int>> =
        numbers.traverse(Either.applicative(), ::fn)
So the problem is it's a Kind of an Either with the right of the Either as another Kind. In order to convert all that stuff back into a normal either I could do this:
Copy code
val resultAsEither:Either<FailReason, List<Int>> = traverseResult.fix().flatMap{ it.fix().right() }
but is there a better way?
p
not at the moment, no
traverseResult.fix().map{ it.fix() }
that. It’s not better, just shorter.
👍 1