davec
04/24/2020, 9:34 PMfun 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:
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.)davec
04/24/2020, 10:05 PMfun <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) }
davec
04/24/2020, 10:21 PMpakoito
04/25/2020, 3:00 AMsequence
, which is a specialised traverse
pakoito
04/25/2020, 3:00 AMnames.traverse(Either.applicative()) { doSomething(it) }
pakoito
04/25/2020, 3:01 AMEither<Error, List<Bla>>
if doSomething
returns Either<Error, Bla>
pakoito
04/25/2020, 3:02 AMList<Either<Error, Bla>>
just call sequence(Either.applicative())
davec
04/25/2020, 6:25 PMdavec
04/28/2020, 10:44 PMtraverse
doesn't actually return an Either
, everything's wrapped in a Kind
. Example:
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)
davec
04/28/2020, 10:45 PMdavec
04/28/2020, 10:51 PMval resultAsEither:Either<FailReason, List<Int>> = traverseResult.fix().flatMap{ it.fix().right() }
davec
04/28/2020, 10:52 PMpakoito
04/28/2020, 11:34 PMpakoito
04/28/2020, 11:34 PMtraverseResult.fix().map{ it.fix() }
pakoito
04/28/2020, 11:34 PM