diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 96a112591eb..ffaf06e8eac 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -3171,11 +3171,15 @@ public final class arrow/core/raise/DefaultRaise : arrow/core/raise/Raise { public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public final class arrow/core/raise/Effect { @@ -3239,6 +3243,7 @@ public final class arrow/core/raise/IorRaise : arrow/core/raise/Raise, arrow/typ public fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public fun maybeCombine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun raise (Ljava/lang/Object;)Ljava/lang/Void; @@ -3246,6 +3251,9 @@ public final class arrow/core/raise/IorRaise : arrow/core/raise/Raise, arrow/typ public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public final class arrow/core/raise/NullableRaise : arrow/core/raise/Raise { @@ -3288,6 +3296,8 @@ public final class arrow/core/raise/NullableRaise : arrow/core/raise/Raise { public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static fun mapOrAccumulate-impl (Larrow/core/raise/Raise;Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun raise (Ljava/lang/Void;)Ljava/lang/Void; public static fun raise-impl (Larrow/core/raise/Raise;Ljava/lang/Void;)Ljava/lang/Void; @@ -3303,6 +3313,12 @@ public final class arrow/core/raise/NullableRaise : arrow/core/raise/Raise { public fun toString ()Ljava/lang/String; public static fun toString-impl (Larrow/core/raise/Raise;)Ljava/lang/String; public final synthetic fun unbox-impl ()Larrow/core/raise/Raise; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public final class arrow/core/raise/OptionRaise : arrow/core/raise/Raise { @@ -3344,6 +3360,8 @@ public final class arrow/core/raise/OptionRaise : arrow/core/raise/Raise { public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static fun mapOrAccumulate-impl (Larrow/core/raise/Raise;Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public fun raise (Larrow/core/None;)Ljava/lang/Void; public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; public static fun raise-impl (Larrow/core/raise/Raise;Larrow/core/None;)Ljava/lang/Void; @@ -3359,6 +3377,12 @@ public final class arrow/core/raise/OptionRaise : arrow/core/raise/Raise { public fun toString ()Ljava/lang/String; public static fun toString-impl (Larrow/core/raise/Raise;)Ljava/lang/String; public final synthetic fun unbox-impl ()Larrow/core/raise/Raise; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public abstract interface class arrow/core/raise/Raise { @@ -3376,11 +3400,15 @@ public abstract interface class arrow/core/raise/Raise { public abstract fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public abstract fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public abstract fun raise (Ljava/lang/Object;)Ljava/lang/Void; public abstract fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public abstract fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public abstract fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public abstract fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public final class arrow/core/raise/Raise$DefaultImpls { @@ -3398,10 +3426,14 @@ public final class arrow/core/raise/Raise$DefaultImpls { public static fun catch (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun mapOrAccumulate (Larrow/core/raise/Raise;Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static fun recover (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun recover (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun recover (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun shift (Larrow/core/raise/Raise;Ljava/lang/Object;)Ljava/lang/Object; + public static fun zipOrAccumulate (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public static fun zipOrAccumulate (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public static fun zipOrAccumulate (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public abstract interface annotation class arrow/core/raise/RaiseDSL : java/lang/annotation/Annotation { @@ -3411,8 +3443,13 @@ public final class arrow/core/raise/RaiseKt { public static final fun catch (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun ensure (Larrow/core/raise/Raise;ZLkotlin/jvm/functions/Function0;)V public static final fun ensureNotNull (Larrow/core/raise/Raise;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public static final fun mapErrorNel (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun mapOrAccumulate (Larrow/core/raise/Raise;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun recover (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun recover (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static final fun zipOrAccumulate (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public static final fun zipOrAccumulate (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public static final fun zipOrAccumulate (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public final class arrow/core/raise/ResultRaise : arrow/core/raise/Raise { @@ -3452,6 +3489,8 @@ public final class arrow/core/raise/ResultRaise : arrow/core/raise/Raise { public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun mapOrAccumulate (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static fun mapOrAccumulate-impl (Larrow/core/raise/Raise;Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun raise (Ljava/lang/Throwable;)Ljava/lang/Void; public static fun raise-impl (Larrow/core/raise/Raise;Ljava/lang/Throwable;)Ljava/lang/Void; @@ -3467,6 +3506,12 @@ public final class arrow/core/raise/ResultRaise : arrow/core/raise/Raise { public fun toString ()Ljava/lang/String; public static fun toString-impl (Larrow/core/raise/Raise;)Ljava/lang/String; public final synthetic fun unbox-impl ()Larrow/core/raise/Raise; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public fun zipOrAccumulate (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function5;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)Ljava/lang/Object; + public static fun zipOrAccumulate-impl (Larrow/core/raise/Raise;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; } public abstract interface class arrow/typeclasses/Monoid : arrow/typeclasses/Semigroup { diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt index 0f33154da34..6ac9bc57cae 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt @@ -3,12 +3,17 @@ package arrow.core.raise import arrow.core.Either +import arrow.core.EmptyValue +import arrow.core.NonEmptyList import arrow.core.None import arrow.core.Option import arrow.core.Some import arrow.core.Validated import arrow.core.continuations.EffectScope +import arrow.core.emptyCombine import arrow.core.identity +import arrow.core.nel +import arrow.typeclasses.Semigroup import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind.AT_MOST_ONCE @@ -308,6 +313,89 @@ public interface Raise { public fun EagerEffect.catch( @BuilderInference catch: Raise.(Throwable) -> A, ): A = fold({ catch(it) }, { raise(it) }, { it }) + + /** + * Accumulate the errors from running both [action1] and [action2] + * using the given [semigroup]. + */ + @RaiseDSL + public fun zipOrAccumulate( + semigroup: Semigroup<@UnsafeVariance R>, + @BuilderInference action1: Raise.() -> A, + @BuilderInference action2: Raise.() -> B, + @BuilderInference block: Raise.(A, B) -> C + ): C { + val result1 = recover(action1) { e1 -> + // try to execute the second + recover(action2) { e2 -> raise(semigroup.run { e1 + e2 }) } + // if the second succeeds, just raise the first one + raise(e1) + } + return block(result1, action2()) + } + + /** + * Accumulate the errors from running [action1], [action2], and [action3] + * using the given [semigroup]. + */ + @RaiseDSL + public fun zipOrAccumulate( + semigroup: Semigroup<@UnsafeVariance R>, + @BuilderInference action1: Raise.() -> A, + @BuilderInference action2: Raise.() -> B, + @BuilderInference action3: Raise.() -> C, + @BuilderInference block: Raise.(A, B, C) -> D + ): D = zipOrAccumulate( + semigroup, + { zipOrAccumulate(semigroup, action1, action2) { x, y -> x to y } }, + action3 + ) { xy, z -> block(xy.first, xy.second, z) } + + /** + * Accumulate the errors from running [action1], [action2], [action3], and [action4] + * using the given [semigroup]. + */ + @RaiseDSL + public fun zipOrAccumulate( + semigroup: Semigroup<@UnsafeVariance R>, + @BuilderInference action1: Raise.() -> A, + @BuilderInference action2: Raise.() -> B, + @BuilderInference action3: Raise.() -> C, + @BuilderInference action4: Raise.() -> D, + @BuilderInference block: Raise.(A, B, C, D) -> E + ): E = zipOrAccumulate( + semigroup, + { zipOrAccumulate(semigroup, action1, action2, action3) { x, y, z -> Triple(x, y, z) } }, + action4 + ) { xyz, z -> block(xyz.first, xyz.second, xyz.third, z) } + + /** + * Accumulate the errors obtained by executing the [block] + * over every element of [this] using the given [semigroup]. + */ + @RaiseDSL + public fun Iterable.mapOrAccumulate( + semigroup: Semigroup<@UnsafeVariance R>, + @BuilderInference block: Raise.(A) -> B + ): List { + // this could be implemented using [zipOrAccumulate], + // but we can have a faster implementation using [MutableList] + var error: Any? = EmptyValue + val results = mutableListOf() + forEach { + fold({ + block(it) + }, { newError -> + error = semigroup.emptyCombine(error, newError) + }, { + results.add(it) + }) + } + when (val e = error) { + is EmptyValue -> return results + else -> raise(EmptyValue.unbox(e)) + } + } } /** @@ -402,3 +490,70 @@ public inline fun Raise.ensureNotNull(value: B?, raise: () -> R) } return value ?: raise(raise()) } + +@RaiseDSL +public inline fun Raise>.mapErrorNel( + crossinline block: Raise.() -> A +): A = recover(block) { raise(it.nel()) } + +/** + * Accumulate the errors obtained by executing the [block] + * over every element of [list]. + */ +@RaiseDSL +public inline fun Raise>.mapOrAccumulate( + list: Iterable, + @BuilderInference crossinline block: Raise.(A) -> B +): List = + list.mapOrAccumulate(Semigroup.nonEmptyList()) { elt -> mapErrorNel { block(elt) } } + +/** + * Accumulate the errors from running both [action1] and [action2]. + */ +@RaiseDSL +public inline fun Raise>.zipOrAccumulate( + @BuilderInference crossinline action1: Raise.() -> A, + @BuilderInference crossinline action2: Raise.() -> B, + @BuilderInference crossinline block: Raise.(A, B) -> C +): C = zipOrAccumulate( + Semigroup.nonEmptyList(), + { mapErrorNel(action1) }, + { mapErrorNel(action2) }, + { x, y -> mapErrorNel { block(x, y) } } +) + +/** + * Accumulate the errors from running [action1], [action2], and [action3]. + */ +@RaiseDSL +public inline fun Raise>.zipOrAccumulate( + @BuilderInference crossinline action1: Raise.() -> A, + @BuilderInference crossinline action2: Raise.() -> B, + @BuilderInference crossinline action3: Raise.() -> C, + @BuilderInference crossinline block: Raise.(A, B, C) -> D +): D = zipOrAccumulate( + Semigroup.nonEmptyList(), + { mapErrorNel(action1) }, + { mapErrorNel(action2) }, + { mapErrorNel(action3) }, + { x, y, z -> mapErrorNel { block(x, y, z) } } +) + +/** + * Accumulate the errors from running [action1], [action2], [action3], and [action4]. + */ +@RaiseDSL +public inline fun Raise>.zipOrAccumulate( + @BuilderInference crossinline action1: Raise.() -> A, + @BuilderInference crossinline action2: Raise.() -> B, + @BuilderInference crossinline action3: Raise.() -> C, + @BuilderInference crossinline action4: Raise.() -> D, + @BuilderInference crossinline block: Raise.(A, B, C, D) -> E +): E = zipOrAccumulate( + Semigroup.nonEmptyList(), + { mapErrorNel(action1) }, + { mapErrorNel(action2) }, + { mapErrorNel(action3) }, + { mapErrorNel(action4) }, + { x, y, z, u -> mapErrorNel { block(x, y, z, u) } } +)