dave08
02/21/2023, 11:18 AMSam
02/21/2023, 11:23 AMdave08
02/21/2023, 11:31 AMbind()
to the happy path and have an aggregation of the failures to pass down or raise.phldavies
02/21/2023, 11:39 AMcontext(Raise<List<L>>)
fun <L, R> Iterable<Either<L, R>>.bind() =
separateEither().let { (errors, success) ->
if(errors.isNotEmpty()) raise(errors) else success
}
mapOrAccumulate(myListOfEithers) { it.bind() }
dave08
02/21/2023, 11:43 AMphldavies
02/21/2023, 11:53 AMraise
is that it will interrupt the flow (ala railway-oriented programming) which is why raise
returns Nothing
. I think in this case you'll need to stick with separateEither
, process your rights and then manually propagate your lefts back to the outer layer (or provide a callback down into your use-case)dave08
02/21/2023, 11:55 AMval validResults = someIterable.map { service(it) }.onLeft(::callback).bind()
bind()
would only give the success values (w/o having to actually creating two lists)phldavies
02/21/2023, 12:28 PMval validResults = someIterable.mapNotNull { service(it).onLeft(::callback).getOrNull() }
if you're happy with all failures resulting in an empty listmapNotLeft
has much benefit over mapNotNull { it.getOrNull() }
._filterIsInstance_<Either.Right<T>>()
dave08
02/21/2023, 12:36 PMmapNotLeftOrAccumulate<ServiceError> { service(it).onLeft(::loggingCallback) }
where ServiceError
is the fatal typephldavies
02/21/2023, 12:42 PMraise
or callback
your errors when checking the result, letting fatal errors get caught by the mapOrAccumulate
and cause the .bind()
to raise, and treat non-fatal errors as an alternative result and filter if required. Something like mapOrAccumulate { service(it).recover { if(it.isFatal) raise(it) else null.also { callback(it) } } }.bind().filterNotNull()
dave08
02/21/2023, 12:52 PM"if everything is good, do this with the values, otherwise accumulate and raise all the errors"Oh... so there's no variant of that that wouldn't raise but rather just call a callback... I guess that solution it the way to go then, thanks! I just wonder if I'm not the only one out there who would want some better support for this kind of behaviour in Arrow itself...?
phldavies
02/21/2023, 12:54 PMIor
so can't speak to the semantics of it.mapOrAccumulate
or just map
will depend on if you want the first critical failure, or all critical failuresmapOrAccumulate
is the new validation capability in Arrow 2.x and 1.2.x 😉)simon.vergauwen
02/21/2023, 12:58 PMmapOrAccumulate
& co are already available on the latest alpha and are planned to be released in 1.2.x)dave08
02/21/2023, 12:59 PMmapNotNullOrAccumulate { }
might have been useful for that, but you're right, what you posted DOES cover my use case!
I'm using the latest alpha 😃...phldavies
02/21/2023, 1:00 PM