From 04c76bdcd3ad5eb93fdaaea0811c19885db4c991 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Mon, 17 Jul 2023 19:42:56 +0200 Subject: [PATCH 1/4] ignoreErrors for Raise --- arrow-libs/core/arrow-core/api/arrow-core.api | 26 ++++++++++++ .../kotlin/arrow/core/raise/Builders.kt | 40 +++++++++++++++++++ .../kotlin/arrow/core/raise/NullableSpec.kt | 16 ++++++++ 3 files changed, 82 insertions(+) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 57c2e23b366..2d0d8535a87 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -3333,6 +3333,30 @@ public final class arrow/core/raise/DefaultRaise : arrow/core/raise/Raise { public abstract interface annotation class arrow/core/raise/ExperimentalTraceApi : java/lang/annotation/Annotation { } +public final class arrow/core/raise/IgnoreErrorsRaise : arrow/core/raise/Raise { + public fun (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function0;)V + public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/Either;)Ljava/lang/Object; + public final fun bind (Larrow/core/Option;)Ljava/lang/Object; + public fun bind (Larrow/core/Validated;)Ljava/lang/Object; + public fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun bind (Ljava/lang/Object;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bindAll (Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; + public fun bindAll (Ljava/lang/Iterable;)Ljava/util/List; + public fun bindAll (Ljava/util/Map;)Ljava/util/Map; + public fun bindAll-1TN0_VU (Ljava/util/Set;)Ljava/util/Set; + public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun ensure (Z)V + public final fun ensureNotNull (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 raise (Ljava/lang/Object;)Ljava/lang/Void; + public fun shift (Ljava/lang/Object;)Ljava/lang/Object; +} + public final class arrow/core/raise/IorRaise : arrow/core/raise/Raise { public fun (Lkotlin/jvm/functions/Function2;Ljava/util/concurrent/atomic/AtomicReference;Larrow/core/raise/Raise;)V public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3381,6 +3405,7 @@ public final class arrow/core/raise/NullableRaise : arrow/core/raise/Raise { public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun ensure (Z)V public final fun ensureNotNull (Ljava/lang/Object;)Ljava/lang/Object; + public final fun ignoreErrors (Lkotlin/jvm/functions/Function1;)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 synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; @@ -3411,6 +3436,7 @@ public final class arrow/core/raise/OptionRaise : arrow/core/raise/Raise { public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun ensure (Z)V public final fun ensureNotNull (Ljava/lang/Object;)Ljava/lang/Object; + public final fun ignoreErrors (Lkotlin/jvm/functions/Function1;)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 raise (Larrow/core/None;)Ljava/lang/Void; diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt index 47d9a1788ed..dee08bf844a 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt @@ -94,6 +94,36 @@ public inline fun ior(noinline combineError: (Error, Error) -> Error, ) } +/** + * Implementation of [Raise] that ignores errors. + */ +public class IgnoreErrorsRaise( + private val raise: Raise, + private val error: () -> N +) : Raise { + @RaiseDSL + override fun raise(r: Any?): Nothing = + raise.raise(error()) + + @RaiseDSL + public fun ensure(value: Boolean): Unit = ensure(value) { null } + + @RaiseDSL + public fun Option.bind(): A = getOrElse { raise(null) } + + @RaiseDSL + public fun A?.bind(): A { + contract { returns() implies (this@bind != null) } + return this ?: raise(null) + } + + @RaiseDSL + public fun ensureNotNull(value: A?): A { + contract { returns() implies (value != null) } + return ensureNotNull(value) { null } + } +} + public typealias Null = Nothing? /** @@ -136,6 +166,11 @@ public class NullableRaise(private val raise: Raise) : Raise by rais null -> recover() else -> nullable } + + @RaiseDSL + public inline fun ignoreErrors( + @BuilderInference block: IgnoreErrorsRaise.() -> A, + ): A = block(IgnoreErrorsRaise(this) { null }) } /** @@ -219,6 +254,11 @@ public class OptionRaise(private val raise: Raise) : Raise by raise is None -> recover() is Some -> option.value } + + @RaiseDSL + public inline fun ignoreErrors( + @BuilderInference block: IgnoreErrorsRaise.() -> A, + ): A = block(IgnoreErrorsRaise(this) { None }) } /** diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt index 90054ec9b62..8daff82393d 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt @@ -69,6 +69,22 @@ class NullableSpec : StringSpec({ } shouldBe "1" } + "binding either in nullable" { + nullable { + val number = Either.Right("s".length) + val string = number.map(Int::toString).bind() + string + } shouldBe "1" + } + + "binding either in nullable, ignore errors" { + nullable { + val number = Either.Right("s".length) as Either + val string = ignoreErrors { number.map(Int::toString).bind() } + string + } shouldBe "1" + } + "short circuit option" { nullable { val number = Some("s".length) From 93d2129931c0d17cf86b14540018c8fbbfac2a82 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Tue, 18 Jul 2023 09:44:43 +0200 Subject: [PATCH 2/4] Update arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt Co-authored-by: Simon Vergauwen --- .../src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt index 8daff82393d..68d3e99bf1e 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt @@ -79,7 +79,7 @@ class NullableSpec : StringSpec({ "binding either in nullable, ignore errors" { nullable { - val number = Either.Right("s".length) as Either + val number: Either = Either.Right("s".length) val string = ignoreErrors { number.map(Int::toString).bind() } string } shouldBe "1" From 37e3210671a9935a821349d6c02e812e9b1bcb26 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Tue, 18 Jul 2023 10:32:37 +0200 Subject: [PATCH 3/4] Update arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt --- .../src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt index 68d3e99bf1e..8daff82393d 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/NullableSpec.kt @@ -79,7 +79,7 @@ class NullableSpec : StringSpec({ "binding either in nullable, ignore errors" { nullable { - val number: Either = Either.Right("s".length) + val number = Either.Right("s".length) as Either val string = ignoreErrors { number.map(Int::toString).bind() } string } shouldBe "1" From 6aae1a78bafcff269d2d8395fd27049cfc7376ee Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Tue, 18 Jul 2023 21:07:14 +0200 Subject: [PATCH 4/4] Docs for ignoreErrors --- .../commonMain/kotlin/arrow/core/raise/Builders.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt index dee08bf844a..3acfc9fdaae 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt @@ -95,7 +95,8 @@ public inline fun ior(noinline combineError: (Error, Error) -> Error, } /** - * Implementation of [Raise] that ignores errors. + * Implementation of [Raise] used by `ignoreErrors`. + * You should never use this directly. */ public class IgnoreErrorsRaise( private val raise: Raise, @@ -167,6 +168,10 @@ public class NullableRaise(private val raise: Raise) : Raise by rais else -> nullable } + /** + * Introduces a scope where you can [bind] errors of any type, + * but no information is saved in the [raise] case. + */ @RaiseDSL public inline fun ignoreErrors( @BuilderInference block: IgnoreErrorsRaise.() -> A, @@ -255,6 +260,10 @@ public class OptionRaise(private val raise: Raise) : Raise by raise is Some -> option.value } + /** + * Introduces a scope where you can [bind] errors of any type, + * but no information is saved in the [raise] case. + */ @RaiseDSL public inline fun ignoreErrors( @BuilderInference block: IgnoreErrorsRaise.() -> A,