You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What would you like to see?
I want to have a more readable alternative to zipOrAccumulate, when doing error accumulation.
either {
val a:ValidatedNel<String, String> ="coo".validNel()
val b:ValidatedNel<String, String> ="kie".validNel()
val c:ValidatedNel<String, String> ="mesomerism".validNel()
ensureAllValid(a, b)
a.value
b.value
//c.value // does not compile
a.value + b.value
} shouldBeEqual "cookie".right()
Motivation:
Currently, zipOrAccumulate works by taking in a number of lambdas whose return values are zipped using another trailing lambda (happy path). Arrow Docs
zipOrAccumulate's flaws are:
much wrapping with lambdas
potential "redeclaration" of validated variables in the zip function
happy path is indented (less readable)
Furthermore this aligns well with current Either DSL (e.g. ensure).
Suggestion:
Use Kotlin contracts to declare a certain variables as valid if they are otherwise accumulate and combine their errors.
Concrete solution's implementation:
suspendinlinefun <ERROR, ACC_ERROR, reified A, reified B> EffectScope<ACC_ERROR>.ensureAllValid(a:ValidatedNel<ERROR, A>, b:ValidatedNel<ERROR, B>, noinline mapAccErrors: (Nel<ERROR>) ->ACC_ERROR) {
contract {
returns() implies (a isValid<A> && b isValid<B>)
}
ensureAllValidInternal(nonEmptyListOf(a, b), mapAccErrors)
}
suspendinlinefun <ERROR, reified A, reified B> EffectScope<Nel<ERROR>>.ensureAllValid(a:ValidatedNel<ERROR, A>, b:ValidatedNel<ERROR, B>) {
contract {
returns() implies (a isValid<A> && b isValid<B>)
}
ensureAllValidInternal(nonEmptyListOf(a, b), ::identity)
}
@PublishedApi
internalsuspendfun <ERROR, ACC_ERROR> EffectScope<ACC_ERROR>.ensureAllValidInternal(
all:Nel<ValidatedNel<ERROR, Any?>>,
mapAccErrors: (Nel<ERROR>) ->ACC_ERROR,
) {
val invalids = all.filterIsInstance<Invalid<Nel<ERROR>>>().toNonEmptyListOrNone()
.getOrElse { return }
val accumulatedErrors = invalids
.flatMap { it.value }
.let(mapAccErrors)
shift<Nothing>(accumulatedErrors)
}
This of course would need to be repetitively scaled to a certain number of arguments. The example given consider just two arguments.
Current Limitations:
contracts still experimental
contracts are unstable and unreliable at the time being
in some cases I had compiler errors and had to recompile the entire project (I haven't figured out in detail yet, what the exact cause is)
The text was updated successfully, but these errors were encountered:
If I understand correctly, what you want here is kind of "accumulate as much as possible" scenario. The shape of zipOrAccumulate ensures that all the validations can be independently executed, but this is no longer possible to guarantee if we're just using a block.
@serras I'm afraid you didn't get the point. The observed behavior of my proposal should be the same as for zipOrAccumulate, just another syntax so to speak. After the ensureAllValid call - as the name suggests - all variables passed as parameters are guaranteed to be Valid. Also, in what sense do you mean independent?
As Validated has been deprecated and will be removed, I think your example could be rewritten using EitherNel, right? And ensureAllRight would be your magic ingredient for that one point where all Eithers are checked. Maybe it should more be like a bindAll? But that one would return a bunch of values as a return value which could be destructured?
@Zordid
Greetings from Munich,
Yes, as Validated is deprecated, this can be transferred to EitherNel, afaik.
bindAll is slightly different. All Iterable's elements would have to be of type A which is a heavy restriction. Also, destructuring implies redeclaring all variables which often times (at least for me) results in duplicate names (one for the original and one for the validated). Thus, I view my proposal as much more convenient.
What version are you currently using? V1.2
What would you like to see?
I want to have a more readable alternative to zipOrAccumulate, when doing error accumulation.
Motivation:
Currently, zipOrAccumulate works by taking in a number of lambdas whose return values are zipped using another trailing lambda (happy path).
Arrow Docs
zipOrAccumulate's flaws are:
Furthermore this aligns well with current Either DSL (e.g. ensure).
Suggestion:
Use Kotlin contracts to declare a certain variables as valid if they are otherwise accumulate and combine their errors.
Concrete solution's implementation:
This of course would need to be repetitively scaled to a certain number of arguments. The example given consider just two arguments.
Current Limitations:
The text was updated successfully, but these errors were encountered: