From cac4b48c9054bbfc560d31434df1286c6cc16cbf Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Tue, 6 Feb 2024 16:44:29 +0000 Subject: [PATCH 1/2] Add FailureValue --- .../api/arrow-fx-coroutines.api | 11 + .../kotlin/arrow/fx/coroutines/ParMap.kt | 59 ++-- .../arrow/fx/coroutines/ParZipOrAccumulate.kt | 314 ++++++++++++------ .../kotlin/arrow/fx/coroutines/predef.kt | 27 ++ 4 files changed, 272 insertions(+), 139 deletions(-) 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..3245b1f0df 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,17 @@ 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 Companion Larrow/fx/coroutines/FailureValue$Companion; + public fun (Ljava/lang/Object;)V + public final fun getError ()Ljava/lang/Object; +} + +public final class arrow/fx/coroutines/FailureValue$Companion { + public final fun bindNel (Larrow/core/raise/RaiseAccumulate;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..0f4da64688 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.Companion.bindNel +import arrow.fx.coroutines.FailureValue.Companion.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..99ae038a16 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.Companion.bindNel +import arrow.fx.coroutines.FailureValue.Companion.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..663b8d21a7 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,22 @@ package arrow.fx.coroutines * For Javascript it relies on `new Date().getTime()` */ public expect fun timeInMillis(): Long + +@PublishedApi +internal class FailureValue(val error: Any?) { + @OptIn(ExperimentalContracts::class) + companion object { + @Suppress("UNCHECKED_CAST") + fun RaiseAccumulate.bindNel(value: Any?): T = + withNel { + if (value is FailureValue) 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) + } + } +} From 76372d609e78369ae954193634832391f0d8ed54 Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Wed, 7 Feb 2024 03:06:19 +0000 Subject: [PATCH 2/2] Reduce ABI of FailureValue --- .../api/arrow-fx-coroutines.api | 8 ++---- .../kotlin/arrow/fx/coroutines/ParMap.kt | 4 +-- .../arrow/fx/coroutines/ParZipOrAccumulate.kt | 4 +-- .../kotlin/arrow/fx/coroutines/predef.kt | 27 ++++++++++--------- 4 files changed, 20 insertions(+), 23 deletions(-) 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 3245b1f0df..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 @@ -152,13 +152,9 @@ public final class arrow/fx/coroutines/ExitCase$Failure : arrow/fx/coroutines/Ex } public final class arrow/fx/coroutines/FailureValue { - public static final field Companion Larrow/fx/coroutines/FailureValue$Companion; - public fun (Ljava/lang/Object;)V - public final fun getError ()Ljava/lang/Object; -} - -public final class arrow/fx/coroutines/FailureValue$Companion { + 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; } 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 0f4da64688..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 @@ -5,8 +5,8 @@ import arrow.core.Either import arrow.core.NonEmptyList import arrow.core.mapOrAccumulate import arrow.core.raise.Raise -import arrow.fx.coroutines.FailureValue.Companion.bindNel -import arrow.fx.coroutines.FailureValue.Companion.mightFail +import arrow.fx.coroutines.FailureValue.bindNel +import arrow.fx.coroutines.FailureValue.mightFail import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll 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 99ae038a16..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 @@ -3,8 +3,8 @@ package arrow.fx.coroutines import arrow.core.NonEmptyList import arrow.core.raise.Raise import arrow.core.raise.zipOrAccumulate -import arrow.fx.coroutines.FailureValue.Companion.bindNel -import arrow.fx.coroutines.FailureValue.Companion.mightFail +import arrow.fx.coroutines.FailureValue.bindNel +import arrow.fx.coroutines.FailureValue.mightFail import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope 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 663b8d21a7..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 @@ -18,21 +18,22 @@ import kotlin.contracts.contract */ public expect fun timeInMillis(): Long +@OptIn(ExperimentalContracts::class) @PublishedApi -internal class FailureValue(val error: Any?) { - @OptIn(ExperimentalContracts::class) - companion object { - @Suppress("UNCHECKED_CAST") - fun RaiseAccumulate.bindNel(value: Any?): T = - withNel { - if (value is FailureValue) raise(value.error as NonEmptyList) else value as T - } +internal object FailureValue { + private class Failure(val error: Any?) + fun failureValue(error: Any?): Any? = Failure(error) - inline fun mightFail(block: Raise.() -> T): Any? { - contract { - callsInPlace(block, InvocationKind.AT_MOST_ONCE) - } - return recover(block, ::FailureValue) + @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) } }