diff --git a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api index 48fb6fcfc4..b964bc8884 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api +++ b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api @@ -151,6 +151,13 @@ public final class arrow/fx/coroutines/ExitCase$Failure : arrow/fx/coroutines/Ex public fun toString ()Ljava/lang/String; } +public final class arrow/fx/coroutines/FailureValue { + public static final field INSTANCE Larrow/fx/coroutines/FailureValue; + public final fun bindNel (Larrow/core/raise/RaiseAccumulate;Ljava/lang/Object;)Ljava/lang/Object; + public final fun failureValue (Ljava/lang/Object;)Ljava/lang/Object; + public final fun mightFail (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + public final class arrow/fx/coroutines/FlowExtensions { public static final fun fixedRate (JZLkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/flow/Flow; public static synthetic fun fixedRate$default (JZLkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow; diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParMap.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParMap.kt index 3238337d69..99ceab4cb2 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParMap.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParMap.kt @@ -3,9 +3,10 @@ package arrow.fx.coroutines import arrow.core.raise.RaiseAccumulate import arrow.core.Either import arrow.core.NonEmptyList -import arrow.core.flattenOrAccumulate +import arrow.core.mapOrAccumulate import arrow.core.raise.Raise -import arrow.core.raise.either +import arrow.fx.coroutines.FailureValue.bindNel +import arrow.fx.coroutines.FailureValue.mightFail import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -59,16 +60,13 @@ public suspend fun Iterable.parMapOrAccumulate( transform: suspend ScopedRaiseAccumulate.(A) -> B ): Either> = coroutineScope { - val semaphore = Semaphore(concurrency) - map { - async(context) { - either { - semaphore.withPermit { - transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) - } - } + parMap(context, concurrency) { + mightFail { + transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) } - }.awaitAll().flattenOrAccumulate(combine) + }.mapOrAccumulate(combine) { maybeFailure -> + bindNel(maybeFailure) + } } public suspend fun Iterable.parMapOrAccumulate( @@ -77,13 +75,13 @@ public suspend fun Iterable.parMapOrAccumulate( transform: suspend ScopedRaiseAccumulate.(A) -> B ): Either> = coroutineScope { - map { - async(context) { - either { - transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) - } + parMap(context) { + mightFail { + transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) } - }.awaitAll().flattenOrAccumulate(combine) + }.mapOrAccumulate(combine) { maybeFailure -> + bindNel(maybeFailure) + } } public suspend fun Iterable.parMapOrAccumulate( @@ -92,16 +90,13 @@ public suspend fun Iterable.parMapOrAccumulate( transform: suspend ScopedRaiseAccumulate.(A) -> B ): Either, List> = coroutineScope { - val semaphore = Semaphore(concurrency) - map { - async(context) { - either { - semaphore.withPermit { - transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) - } - } + parMap(context, concurrency) { + mightFail { + transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) } - }.awaitAll().flattenOrAccumulate() + }.mapOrAccumulate { maybeFailure -> + bindNel(maybeFailure) + } } public suspend fun Iterable.parMapOrAccumulate( @@ -109,11 +104,11 @@ public suspend fun Iterable.parMapOrAccumulate( transform: suspend ScopedRaiseAccumulate.(A) -> B ): Either, List> = coroutineScope { - map { - async(context) { - either { - transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) - } + parMap(context) { + mightFail { + transform(ScopedRaiseAccumulate(this, this@coroutineScope), it) } - }.awaitAll().flattenOrAccumulate() + }.mapOrAccumulate { maybeFailure -> + bindNel(maybeFailure) + } } diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParZipOrAccumulate.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParZipOrAccumulate.kt index 08e1760630..b7e0601339 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParZipOrAccumulate.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/ParZipOrAccumulate.kt @@ -1,10 +1,10 @@ package arrow.fx.coroutines -import arrow.core.Either import arrow.core.NonEmptyList -import arrow.core.getOrElse import arrow.core.raise.Raise -import arrow.core.raise.either +import arrow.core.raise.zipOrAccumulate +import arrow.fx.coroutines.FailureValue.bindNel +import arrow.fx.coroutines.FailureValue.mightFail import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope @@ -27,10 +27,10 @@ public suspend inline fun Raise.parZipOrAccumulate( ): C = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b -> - Either.zipOrAccumulate(a, b) { aa, bb -> f(aa, bb) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate(combine, { bindNel(a) }, { bindNel(b) }) { aa, bb -> f(aa, bb) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -48,10 +48,10 @@ public suspend inline fun Raise>.parZipOrAccumulate ): C = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b -> - Either.zipOrAccumulate(a, b) { aa, bb -> f(aa, bb) }.bind() + zipOrAccumulate({ bindNel(a) }, { bindNel(b) }) { aa, bb -> f(aa, bb) } } //endregion @@ -75,11 +75,11 @@ public suspend inline fun Raise.parZipOrAccumulate( ): D = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c -> - Either.zipOrAccumulate(a, b, c) { aa, bb, cc -> f(aa, bb, cc) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate(combine, { bindNel(a) }, { bindNel(b) }, { bindNel(c) }) { aa, bb, cc -> f(aa, bb, cc) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -99,11 +99,15 @@ public suspend inline fun Raise>.parZipOrAccumul ): D = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c -> - Either.zipOrAccumulate(a, b, c) { aa, bb, cc -> f(aa, bb, cc) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) } + ) { aa, bb, cc -> f(aa, bb, cc) } } //endregion @@ -129,12 +133,18 @@ public suspend inline fun Raise.parZipOrAccumulate( ): F = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d -> - Either.zipOrAccumulate(a, b, c, d) { aa, bb, cc, dd -> f(aa, bb, cc, dd) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) } + ) { aa, bb, cc, dd -> f(aa, bb, cc, dd) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -156,12 +166,17 @@ public suspend inline fun Raise>.parZipOrAccu ): F = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d -> - Either.zipOrAccumulate(a, b, c, d) { aa, bb, cc, dd -> f(aa, bb, cc, dd) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) } + ) { aa, bb, cc, dd -> f(aa, bb, cc, dd) } } //endregion @@ -189,13 +204,20 @@ public suspend inline fun Raise.parZipOrAccumulate( ): G = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f -> - Either.zipOrAccumulate(a, b, c, d, f) { aa, bb, cc, dd, ff -> f(aa, bb, cc, dd, ff) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) } + ) { aa, bb, cc, dd, ff -> f(aa, bb, cc, dd, ff) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -219,13 +241,19 @@ public suspend inline fun Raise>.parZipOrA ): G = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f -> - Either.zipOrAccumulate(a, b, c, d, f) { aa, bb, cc, dd, ff -> f(aa, bb, cc, dd, ff) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) } + ) { aa, bb, cc, dd, ff -> f(aa, bb, cc, dd, ff) } } //endregion @@ -255,14 +283,22 @@ public suspend inline fun Raise.parZipOrAccumulate( ): H = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g -> - Either.zipOrAccumulate(a, b, c, d, f, g) { aa, bb, cc, dd, ff, gg -> f(aa, bb, cc, dd, ff, gg) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) } + ) { aa, bb, cc, dd, ff, gg -> f(aa, bb, cc, dd, ff, gg) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -288,14 +324,21 @@ public suspend inline fun Raise>.parZip ): H = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g -> - Either.zipOrAccumulate(a, b, c, d, f, g) { aa, bb, cc, dd, ff, gg -> f(aa, bb, cc, dd, ff, gg) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) } + ) { aa, bb, cc, dd, ff, gg -> f(aa, bb, cc, dd, ff, gg) } } //endregion @@ -327,15 +370,24 @@ public suspend inline fun Raise.parZipOrAccumulat ): I = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fh(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fh(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g, h -> - Either.zipOrAccumulate(a, b, c, d, f, g, h) { aa, bb, cc, dd, ff, gg, hh -> f(aa, bb, cc, dd, ff, gg, hh) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) } + ) { aa, bb, cc, dd, ff, gg, hh -> f(aa, bb, cc, dd, ff, gg, hh) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -363,15 +415,23 @@ public suspend inline fun Raise>.par ): I = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fh(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fh(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g, h -> - Either.zipOrAccumulate(a, b, c, d, f, g, h) { aa, bb, cc, dd, ff, gg, hh -> f(aa, bb, cc, dd, ff, gg, hh) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) } + ) { aa, bb, cc, dd, ff, gg, hh -> f(aa, bb, cc, dd, ff, gg, hh) } } //endregion @@ -405,16 +465,26 @@ public suspend inline fun Raise.parZipOrAccumu ): J = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fi(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fi(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g, h, i -> - Either.zipOrAccumulate(a, b, c, d, f, g, h, i) { aa, bb, cc, dd, ff, gg, hh, ii -> f(aa, bb, cc, dd, ff, gg, hh, ii) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) }, + { bindNel(i) } + ) { aa, bb, cc, dd, ff, gg, hh, ii -> f(aa, bb, cc, dd, ff, gg, hh, ii) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -444,16 +514,25 @@ public suspend inline fun Raise>. ): J = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fi(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fi(ScopedRaiseAccumulate(this, this@parZip)) } }, ) { a, b, c, d, f, g, h, i -> - Either.zipOrAccumulate(a, b, c, d, f, g, h, i) { aa, bb, cc, dd, ff, gg, hh, ii -> f(aa, bb, cc, dd, ff, gg, hh, ii) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) }, + { bindNel(i) } + ) { aa, bb, cc, dd, ff, gg, hh, ii -> f(aa, bb, cc, dd, ff, gg, hh, ii) } } //endregion @@ -489,17 +568,28 @@ public suspend inline fun Raise.parZipOrAcc ): K = parZip( context, - { either { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fi(ScopedRaiseAccumulate(this, this@parZip)) } }, - { either { fj(ScopedRaiseAccumulate(this, this@parZip)) } } + { mightFail { fa(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fb(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fc(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fd(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { ff(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fg(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fh(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fi(ScopedRaiseAccumulate(this, this@parZip)) } }, + { mightFail { fj(ScopedRaiseAccumulate(this, this@parZip)) } } ) { a, b, c, d, f, g, h, i, j -> - Either.zipOrAccumulate(a, b, c, d, f, g, h, i, j) { aa, bb, cc, dd, ff, gg, hh, ii, jj -> f(aa, bb, cc, dd, ff, gg, hh, ii, jj) }.getOrElse { raise(it.reduce(combine)) } + zipOrAccumulate( + combine, + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) }, + { bindNel(i) }, + { bindNel(j) } + ) { aa, bb, cc, dd, ff, gg, hh, ii, jj -> f(aa, bb, cc, dd, ff, gg, hh, ii, jj) } } public suspend inline fun Raise>.parZipOrAccumulate( @@ -531,16 +621,26 @@ public suspend inline fun Raise - Either.zipOrAccumulate(a, b, c, d, f, g, h, i, j) { aa, bb, cc, dd, ff, gg, hh, ii, jj -> f(aa, bb, cc, dd, ff, gg, hh, ii, jj) }.bind() + zipOrAccumulate( + { bindNel(a) }, + { bindNel(b) }, + { bindNel(c) }, + { bindNel(d) }, + { bindNel(f) }, + { bindNel(g) }, + { bindNel(h) }, + { bindNel(i) }, + { bindNel(j) } + ) { aa, bb, cc, dd, ff, gg, hh, ii, jj -> f(aa, bb, cc, dd, ff, gg, hh, ii, jj) } } //endregion diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/predef.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/predef.kt index d033195a84..4e47a5cb79 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/predef.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/predef.kt @@ -1,5 +1,13 @@ package arrow.fx.coroutines +import arrow.core.NonEmptyList +import arrow.core.raise.Raise +import arrow.core.raise.RaiseAccumulate +import arrow.core.raise.recover +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + /** * Gets current system time in milliseconds since certain moment in the past, * only delta between two subsequent calls makes sense. @@ -9,3 +17,23 @@ package arrow.fx.coroutines * For Javascript it relies on `new Date().getTime()` */ public expect fun timeInMillis(): Long + +@OptIn(ExperimentalContracts::class) +@PublishedApi +internal object FailureValue { + private class Failure(val error: Any?) + fun failureValue(error: Any?): Any? = Failure(error) + + @Suppress("UNCHECKED_CAST") + fun RaiseAccumulate.bindNel(value: Any?): T = + withNel { + if (value is Failure) raise(value.error as NonEmptyList) else value as T + } + + inline fun mightFail(block: Raise.() -> T): Any? { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } + return recover(block, ::failureValue) + } +}