diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 549eb586836..96a112591eb 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -250,6 +250,7 @@ public final class arrow/core/EitherKt { public static final fun bisequenceNullable (Larrow/core/Either;)Larrow/core/Either; public static final fun bisequenceOption (Larrow/core/Either;)Larrow/core/Option; public static final fun bisequenceValidated (Larrow/core/Either;)Larrow/core/Validated; + public static final fun catch (Larrow/core/Either;Lkotlin/jvm/functions/Function2;)Larrow/core/Either; public static final fun combine (Larrow/core/Either;Larrow/typeclasses/Semigroup;Larrow/typeclasses/Semigroup;Larrow/core/Either;)Larrow/core/Either; public static final fun combineAll (Ljava/lang/Iterable;Larrow/typeclasses/Monoid;Larrow/typeclasses/Monoid;)Larrow/core/Either; public static final fun combineK (Larrow/core/Either;Larrow/core/Either;)Larrow/core/Either; @@ -270,6 +271,7 @@ public final class arrow/core/EitherKt { public static final fun leftWiden (Larrow/core/Either;)Larrow/core/Either; public static final fun merge (Larrow/core/Either;)Ljava/lang/Object; public static final fun orNull (Larrow/core/Either;)Ljava/lang/Object; + public static final fun recover (Larrow/core/Either;Lkotlin/jvm/functions/Function2;)Larrow/core/Either; public static final fun redeem (Larrow/core/Either;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public static final fun redeemWith (Larrow/core/Either;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public static final fun replicate (Larrow/core/Either;ILarrow/typeclasses/Monoid;)Larrow/core/Either; @@ -932,6 +934,7 @@ public final class arrow/core/OptionKt { public static final fun none ()Larrow/core/Option; public static final fun or (Larrow/core/Option;Larrow/core/Option;)Larrow/core/Option; public static final fun orElse (Larrow/core/Option;Lkotlin/jvm/functions/Function0;)Larrow/core/Option; + public static final fun recover (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Larrow/core/Option; public static final fun redeem (Larrow/core/Option;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun redeemWith (Larrow/core/Option;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun replicate (Larrow/core/Option;ILarrow/typeclasses/Monoid;)Larrow/core/Option; @@ -2693,6 +2696,7 @@ public abstract interface class arrow/core/continuations/EagerEffectScope { public abstract fun bind (Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public abstract fun ensure (ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2705,6 +2709,7 @@ public final class arrow/core/continuations/EagerEffectScope$DefaultImpls { public static fun bind (Larrow/core/continuations/EagerEffectScope;Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind (Larrow/core/continuations/EagerEffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun catch (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun ensure (Larrow/core/continuations/EagerEffectScope;ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } @@ -2755,8 +2760,11 @@ public abstract interface class arrow/core/continuations/EffectScope { public abstract fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun bind (Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun ensure (ZLkotlin/jvm/functions/Function0;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;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } @@ -2768,8 +2776,11 @@ public final class arrow/core/continuations/EffectScope$DefaultImpls { public static fun bind (Larrow/core/continuations/EffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind (Larrow/core/continuations/EffectScope;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun catch (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun ensure (Larrow/core/continuations/EffectScope;ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun recover (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public final class arrow/core/continuations/EffectScopeKt { @@ -2788,10 +2799,13 @@ public final class arrow/core/continuations/FoldContinuation : arrow/core/contin 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun ensure (ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun getContext ()Lkotlin/coroutines/CoroutineContext; public final fun getRecover ()Lkotlin/jvm/functions/Function2; + public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun resumeWith (Ljava/lang/Object;)V public final fun setRecover (Lkotlin/jvm/functions/Function2;)V public fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2806,6 +2820,7 @@ public final class arrow/core/continuations/IorEagerEffectScope : arrow/core/con public fun bind (Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun ensure (ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2826,12 +2841,15 @@ public final class arrow/core/continuations/IorEffectScope : arrow/core/continua 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun ensure (ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun getLeftState ()Ljava/util/concurrent/atomic/AtomicReference; 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 recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun setLeftState (Ljava/util/concurrent/atomic/AtomicReference;)V public fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } @@ -2844,6 +2862,7 @@ public final class arrow/core/continuations/NullableEagerEffectScope : arrow/cor public fun bind (Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Option;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2851,6 +2870,7 @@ public final class arrow/core/continuations/NullableEagerEffectScope : arrow/cor public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EagerEffectScope;)Larrow/core/continuations/NullableEagerEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; @@ -2880,6 +2900,8 @@ public final class arrow/core/continuations/NullableEffectScope : arrow/core/con 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Option;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2888,6 +2910,8 @@ public final class arrow/core/continuations/NullableEffectScope : arrow/core/con public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EffectScope;)Larrow/core/continuations/NullableEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2900,6 +2924,8 @@ public final class arrow/core/continuations/NullableEffectScope : arrow/core/con public static final fun equals-impl0 (Larrow/core/continuations/EffectScope;Larrow/core/continuations/EffectScope;)Z public fun hashCode ()I public static fun hashCode-impl (Larrow/core/continuations/EffectScope;)I + public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun recover-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public synthetic fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Ljava/lang/Void;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun shift-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Void;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2921,12 +2947,14 @@ public final class arrow/core/continuations/OptionEagerEffectScope : arrow/core/ public fun bind (Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Option;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EagerEffectScope;)Larrow/core/continuations/OptionEagerEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; @@ -2956,6 +2984,8 @@ public final class arrow/core/continuations/OptionEffectScope : arrow/core/conti 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Option;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2963,6 +2993,8 @@ public final class arrow/core/continuations/OptionEffectScope : arrow/core/conti public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EffectScope;)Larrow/core/continuations/OptionEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2975,6 +3007,8 @@ public final class arrow/core/continuations/OptionEffectScope : arrow/core/conti public static final fun equals-impl0 (Larrow/core/continuations/EffectScope;Larrow/core/continuations/EffectScope;)Z public fun hashCode ()I public static fun hashCode-impl (Larrow/core/continuations/EffectScope;)I + public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun recover-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Larrow/core/None;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public synthetic fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun shift-impl (Larrow/core/continuations/EffectScope;Larrow/core/None;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2998,12 +3032,14 @@ public final class arrow/core/continuations/ResultEagerEffectScope : arrow/core/ public fun bind (Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EagerEffectScope;)Larrow/core/continuations/ResultEagerEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EagerEffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; @@ -3032,6 +3068,8 @@ public final class arrow/core/continuations/ResultEffectScope : arrow/core/conti 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Option;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/Validated;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3039,6 +3077,8 @@ public final class arrow/core/continuations/ResultEffectScope : arrow/core/conti public static fun bind-impl (Larrow/core/continuations/EffectScope;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bind-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun bind-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final synthetic fun box-impl (Larrow/core/continuations/EffectScope;)Larrow/core/continuations/ResultEffectScope; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun catch-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3050,6 +3090,8 @@ public final class arrow/core/continuations/ResultEffectScope : arrow/core/conti public static final fun equals-impl0 (Larrow/core/continuations/EffectScope;Larrow/core/continuations/EffectScope;)Z public fun hashCode ()I public static fun hashCode-impl (Larrow/core/continuations/EffectScope;)I + public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun recover-impl (Larrow/core/continuations/EffectScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public synthetic fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun shift-impl (Larrow/core/continuations/EffectScope;Ljava/lang/Throwable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3113,6 +3155,320 @@ public final class arrow/core/continuations/result { public final fun invoke-gIAlu-s (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } +public final class arrow/core/raise/DefaultRaise : arrow/core/raise/Raise { + public fun ()V + public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/Either;)Ljava/lang/Object; + public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)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 catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + 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 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 final class arrow/core/raise/Effect { + public static final fun _fold (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun _foldOrThrow (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1; + public static final fun catch (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2; + public static final fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)Lkotlin/jvm/functions/Function2; + public static final fun either (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public static final fun fold (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun fold (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun fold (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun fold (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun ior (Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; + public static final fun merge (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun merge (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun nullable (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun option (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public static final fun orNull (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun orNull (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun raisedOrRethrow (Ljava/util/concurrent/CancellationException;Larrow/core/raise/DefaultRaise;)Ljava/lang/Object; + public static final fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1; + public static final fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)Lkotlin/jvm/functions/Function2; + public static final fun result (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun toEither (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public static final fun toEither (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toIor (Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; + public static final fun toIor (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toOption (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public static final fun toOption (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public static final fun toOption (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toOption (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toResult (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun toResult (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static final fun toResult (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toResult (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun toValidated (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; + public static final fun toValidated (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class arrow/core/raise/EffectKt { + public static final fun eagerEffect (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; + public static final fun effect (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2; +} + +public final class arrow/core/raise/IorRaise : arrow/core/raise/Raise, arrow/typeclasses/Semigroup { + public fun (Larrow/typeclasses/Semigroup;Ljava/util/concurrent/atomic/AtomicReference;Larrow/core/raise/Raise;)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/Ior;)Ljava/lang/Object; + public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)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 catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + 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 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; + 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 final class arrow/core/raise/NullableRaise : arrow/core/raise/Raise { + public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun attempt-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/Either;)Ljava/lang/Object; + public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)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 static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Either;)Ljava/lang/Object; + public static final fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Option;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Validated;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun bind-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final synthetic fun box-impl (Larrow/core/raise/Raise;)Larrow/core/raise/NullableRaise; + public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun constructor-impl (Larrow/core/raise/Raise;)Larrow/core/raise/Raise; + public static final fun ensure-impl (Larrow/core/raise/Raise;Z)V + public static final fun ensureNotNull-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Ljava/lang/Object; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Larrow/core/raise/Raise;Larrow/core/raise/Raise;)Z + public fun hashCode ()I + public static fun hashCode-impl (Larrow/core/raise/Raise;)I + public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + 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 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; + 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 static fun recover-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun recover-impl (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-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public synthetic fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public fun shift (Ljava/lang/Void;)Ljava/lang/Object; + public static fun shift-impl (Larrow/core/raise/Raise;Ljava/lang/Void;)Ljava/lang/Object; + 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 final class arrow/core/raise/OptionRaise : arrow/core/raise/Raise { + public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun attempt-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/Either;)Ljava/lang/Object; + public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)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 static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Either;)Ljava/lang/Object; + public static final fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Option;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Validated;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final synthetic fun box-impl (Larrow/core/raise/Raise;)Larrow/core/raise/OptionRaise; + public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun constructor-impl (Larrow/core/raise/Raise;)Larrow/core/raise/Raise; + public static final fun ensure-impl (Larrow/core/raise/Raise;Z)V + public static final fun ensureNotNull-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Ljava/lang/Object; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Larrow/core/raise/Raise;Larrow/core/raise/Raise;)Z + public fun hashCode ()I + public static fun hashCode-impl (Larrow/core/raise/Raise;)I + public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + 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 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; + 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 static fun recover-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun recover-impl (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-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun shift (Larrow/core/None;)Ljava/lang/Object; + public synthetic fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public static fun shift-impl (Larrow/core/raise/Raise;Larrow/core/None;)Ljava/lang/Object; + 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 abstract interface class arrow/core/raise/Raise { + public abstract fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Larrow/core/Either;)Ljava/lang/Object; + public abstract fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public abstract fun bind (Larrow/core/Validated;)Ljava/lang/Object; + public abstract fun bind (Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public abstract fun bind (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public abstract fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + 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 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 final class arrow/core/raise/Raise$DefaultImpls { + public static fun attempt (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Larrow/core/Either;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Larrow/core/Validated;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + 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 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 abstract interface annotation class arrow/core/raise/RaiseDSL : java/lang/annotation/Annotation { +} + +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 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 final class arrow/core/raise/ResultRaise : arrow/core/raise/Raise { + public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun attempt-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Larrow/core/Either;)Ljava/lang/Object; + public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)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 static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Either;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/Validated;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/EagerEffect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun bind-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + public static fun bind-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final synthetic fun box-impl (Larrow/core/raise/Raise;)Larrow/core/raise/ResultRaise; + public fun catch (Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Larrow/core/continuations/Effect;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun catch-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun constructor-impl (Larrow/core/raise/Raise;)Larrow/core/raise/Raise; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Larrow/core/raise/Raise;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Larrow/core/raise/Raise;Larrow/core/raise/Raise;)Z + public fun hashCode ()I + public static fun hashCode-impl (Larrow/core/raise/Raise;)I + public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; + 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 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; + 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 static fun recover-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun recover-impl (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-impl (Larrow/core/raise/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public synthetic fun shift (Ljava/lang/Object;)Ljava/lang/Object; + public fun shift (Ljava/lang/Throwable;)Ljava/lang/Object; + public static fun shift-impl (Larrow/core/raise/Raise;Ljava/lang/Throwable;)Ljava/lang/Object; + 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 abstract interface class arrow/typeclasses/Monoid : arrow/typeclasses/Semigroup { public static final field Companion Larrow/typeclasses/Monoid$Companion; public static fun Boolean ()Larrow/typeclasses/Monoid; diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt index f92421675ea..92c02f20d11 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt @@ -9,6 +9,8 @@ import arrow.core.continuations.Eager import arrow.core.continuations.EagerEffect import arrow.core.continuations.Effect import arrow.core.continuations.Token +import arrow.core.raise.Raise +import arrow.core.raise.either import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup import kotlin.contracts.ExperimentalContracts @@ -839,7 +841,7 @@ public sealed class Either { is Left -> ifLeft(value) } } - + @Deprecated( NicheAPI + "Prefer when or fold instead", ReplaceWith("fold({ initial }) { rightOperation(initial, it) }") @@ -1315,7 +1317,7 @@ public sealed class Either { t.nonFatalOrThrow().left() } } - + @Deprecated( RedundantAPI + "Compose catch with flatten instead", ReplaceWith("catch(f).flatten()") @@ -1352,6 +1354,7 @@ public sealed class Either { * @param unrecoverableState the function to apply if [resolve] is in an unrecoverable state. * @return the result of applying the [resolve] function. */ + @Deprecated(NicheAPI + "Prefer using recover, catch and the either DSL to work with errors") @JvmStatic public inline fun resolve( f: () -> Either, @@ -1654,11 +1657,12 @@ public inline fun Either.leftIfNull(default: () -> A): Either Either.contains(elem: B): Boolean = fold({ false }) { it == elem } +@Deprecated( + RedundantAPI + "Prefer the Either DSL, or new recover API", + ReplaceWith("recover { y.bind() }") +) public fun Either.combineK(y: Either): Either = - when (this) { - is Left -> y - else -> this - } + recover { y.bind() } public fun A.left(): Either = Left(this) @@ -1697,32 +1701,43 @@ public inline fun B?.rightIfNotNull(default: () -> A): Either = public inline fun Any?.rightIfNull(default: () -> A): Either = this?.let { default().left() } ?: null.right() - +@Deprecated( + RedundantAPI + "Prefer the new recover API", + ReplaceWith( + "recover { a -> f(a).bind() }", + "arrow.core.recover" + ) +) public inline fun Either.handleErrorWith(f: (A) -> Either): Either { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } - return when (this) { - is Left -> f(this.value) - is Right -> this - } + return recover { a -> f(a).bind() } } +@Deprecated( + RedundantAPI + "Prefer the new recover API", + ReplaceWith( + "recover { a -> f(a) }", + "arrow.core.recover" + ) +) public inline fun Either.handleError(f: (A) -> B): Either { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } - return when (this) { - is Left -> f(value).right() - is Right -> this - } + return recover { a -> f(a) } } +@Deprecated( + RedundantAPI + "Prefer the new recover API", + ReplaceWith( + "map(fa).recover { a -> fe(a) }", + "arrow.core.recover" + ) +) public inline fun Either.redeem(fe: (A) -> C, fa: (B) -> C): Either { contract { callsInPlace(fe, InvocationKind.AT_MOST_ONCE) callsInPlace(fa, InvocationKind.AT_MOST_ONCE) } - return when (this) { - is Left -> fe(value).right() - is Right -> map(fa) - } + return map(fa).recover { a -> fe(a) } } public operator fun , B : Comparable> Either.compareTo(other: Either): Int = @@ -1775,38 +1790,52 @@ public fun Either.widen(): Either = public fun Either.leftWiden(): Either = this -// TODO this will be completely breaking from 1.x.x -> 2.x.x. Only _real_ solution is `inline fun either { }` +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { f(bind(), fb.bind()) }", + "arrow.core.raise.either" + ) +) public fun Either.zip(fb: Either, f: (B, C) -> D): Either { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } - return flatMap { b -> - fb.map { c -> f(b, c) } - } + return either { f(bind(), fb.bind()) } } -public fun Either.zip(fb: Either): Either> = - flatMap { a -> - fb.map { b -> Pair(a, b) } - } +@Deprecated( + "Prefer using the inline arrow.core.raise.either DSL", + ReplaceWith( + "either { Pair(bind(), fb.bind()) }", + "arrow.core.raise.either" + ) +) +public fun Either.zip(fb: Either): Either> = either { + Pair(bind(), fb.bind()) +} +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, map: (B, C, D) -> E, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - c, - d, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit - ) { b, c, d, _, _, _, _, _, _, _ -> map(b, c, d) } + return either { map(bind(), c.bind(), d.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1814,19 +1843,16 @@ public inline fun Either.zip( map: (B, C, D, E) -> F, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - c, - d, - e, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit - ) { b, c, d, e, _, _, _, _, _, _ -> map(b, c, d, e) } + return either { map(bind(), c.bind(), d.bind(), e.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1835,19 +1861,16 @@ public inline fun Either.zip( map: (B, C, D, E, F) -> G, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - c, - d, - e, - f, - Right.unit, - Right.unit, - Right.unit, - Right.unit, - Right.unit - ) { b, c, d, e, f, _, _, _, _, _ -> map(b, c, d, e, f) } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1857,18 +1880,16 @@ public inline fun Either.zip( map: (B, C, D, E, F, G) -> H, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(c, d, e, f, g, Right.unit, Right.unit, Right.unit, Right.unit) { b, c, d, e, f, g, _, _, _, _ -> - map( - b, - c, - d, - e, - f, - g - ) - } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1879,19 +1900,16 @@ public inline fun Either.zip( map: (B, C, D, E, F, G, H) -> I, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(c, d, e, f, g, h, Right.unit, Right.unit, Right.unit) { b, c, d, e, f, g, h, _, _, _ -> - map( - b, - c, - d, - e, - f, - g, - h - ) - } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1903,9 +1921,16 @@ public inline fun Either.zip( map: (B, C, D, E, F, G, H, I) -> J, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(c, d, e, f, g, h, i, Right.unit, Right.unit) { b, c, d, e, f, g, h, i, _, _ -> map(b, c, d, e, f, g, h, i) } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1918,9 +1943,16 @@ public inline fun Either.zip( map: (B, C, D, E, F, G, H, I, J) -> K, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(c, d, e, f, g, h, i, j, Right.unit) { b, c, d, e, f, g, h, i, j, _ -> map(b, c, d, e, f, g, h, i, j) } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind()) } } +@Deprecated( + "Prefer using the inline either DSL", + ReplaceWith( + "either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind(), k.bind()) }", + "arrow.core.raise.either" + ) +) public inline fun Either.zip( c: Either, d: Either, @@ -1934,27 +1966,7 @@ public inline fun Either.zip( map: (B, C, D, E, F, G, H, I, J, K) -> L, ): Either { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return flatMap { bb -> - c.flatMap { cc -> - d.flatMap { dd -> - e.flatMap { ee -> - f.flatMap { ff -> - g.flatMap { gg -> - h.flatMap { hh -> - i.flatMap { ii -> - j.flatMap { jj -> - k.map { kk -> - map(bb, cc, dd, ee, ff, gg, hh, ii, jj, kk) - } - } - } - } - } - } - } - } - } - } + return either { map(bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind(), k.bind()) } } @Deprecated( @@ -1971,6 +1983,10 @@ public fun Either.replicate(n: Int, MB: Monoid): Either = public inline fun Either.ensure(error: () -> A, predicate: (B) -> Boolean): Either = flatMap { b -> b.takeIf(predicate)?.right() ?: error().left() } +@Deprecated( + NicheAPI + "Prefer using a simple fold, or when expression", + ReplaceWith("fold(fa, fb)") +) public inline fun Either.redeemWith(fa: (A) -> Either, fb: (B) -> Either): Either { contract { callsInPlace(fa, InvocationKind.AT_MOST_ONCE) @@ -2058,3 +2074,101 @@ public const val NicheAPI: String = public const val RedundantAPI: String = "This API is considered redundant. If this method is crucial for you, please let us know on the Arrow Github. Thanks!\n https://github.com/arrow-kt/arrow/issues\n" + +/** + * Recover from any [Either.Left] if encountered. + * + * The recover DSL allows you to recover from any [Either.Left] value by: + * - Computing a fallback value [A], and resolve the left type [E] to [Nothing]. + * - Shifting a _new error_ of type [EE] into the [Either.Left] channel. + * + * When providing a fallback value [A], + * the [Either.Left] type is discarded because the error was handled correctly. + * + * ```kotlin + * import arrow.core.Either + * import arrow.core.recover + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val error: Either = Either.Left("error") + * val fallback: Either = error.recover { it.length } + * fallback shouldBe Either.Right(5) + * } + * ``` + * + * + * + * When shifting a new error [EE] into the [Either.Left] channel, + * the [Either.Left] is _transformed_ from [E] to [EE] since we shifted a _new error_. + * + * ```kotlin + * import arrow.core.Either + * import arrow.core.recover + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val error: Either = Either.Left("error") + * val listOfErrors: Either, Int> = error.recover { shift(it.toList()) } + * listOfErrors shouldBe Either.Left(listOf('e', 'r', 'r', 'o', 'r')) + * } + * ``` + * + * + */ +@OptIn(ExperimentalTypeInference::class) +public inline fun Either.recover(@BuilderInference recover: Raise.(E) -> A): Either { + contract { callsInPlace(recover, InvocationKind.AT_MOST_ONCE) } + return when(this) { + is Left -> either { recover(this, value) } + is Right -> this@recover + } +} + +/** + * Catch allows for transforming [Throwable] in the [Either.Left] side. + * This API is the same as [recover], + * but offers the same APIs for working over [Throwable] as [Effect] & [EagerEffect]. + * + * This is useful when working with [Either.catch] since this API offers a `reified` variant. + * The reified version allows you to refine `Throwable` to `T : Throwable`, + * where any `Throwable` not matching the `t is T` predicate will be rethrown. + * + * ```kotlin + * import arrow.core.Either + * import arrow.core.catch + * import io.kotest.assertions.throwables.shouldThrowUnit + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val left: Either = Either.catch { throw RuntimeException("Boom!") } + * + * val caught: Either = left.catch { _: Throwable -> 1 } + * val failure: Either = left.catch { _: Throwable -> shift("failure") } + * + * shouldThrowUnit { + * val caught2: Either = left.catch { _: IllegalStateException -> 1 } + * } + * + * caught shouldBe Either.Right(1) + * failure shouldBe Either.Left("failure") + * } + * ``` + * + * + */ +@OptIn(ExperimentalTypeInference::class) +public inline fun Either.catch(@BuilderInference catch: Raise.(Throwable) -> A): Either { + contract { callsInPlace(catch, InvocationKind.AT_MOST_ONCE) } + return when (this) { + is Left -> either { catch(this, value) } + is Right -> this@catch + } +} + +@JvmName("catchReified") +@OptIn(ExperimentalTypeInference::class) +public inline fun Either.catch(@BuilderInference catch: Raise.(T) -> A): Either { + contract { callsInPlace(catch, InvocationKind.AT_MOST_ONCE) } + return catch { e -> if (e is T) catch(e) else throw e } +} diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 5da868708e6..a79698a0b05 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -2,6 +2,8 @@ package arrow.core import arrow.core.Either.Right +import arrow.core.raise.OptionRaise +import arrow.core.raise.option import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup import kotlin.contracts.ExperimentalContracts @@ -12,7 +14,7 @@ import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic /** - * + * * * If you have worked with Java at all in the past, it is very likely that you have come across a `NullPointerException` at some time (other languages will throw similarly named errors in such a case). Usually this happens because some method returns `null` when you weren't expecting it and, thus, isn't dealing with that possibility in your client code. A value of `null` is often abused to represent an absent optional value. * Kotlin tries to solve the problem by getting rid of `null` values altogether, and providing its own special syntax [Null-safety machinery based on `?`](https://kotlinlang.org/docs/reference/null-safety.html). @@ -457,6 +459,7 @@ public sealed class Option { f() this } + is Some -> this } } @@ -706,6 +709,7 @@ public sealed class Option { None -> None is Some -> Some(b.value.rightIor()) } + is Some -> when (b) { None -> Some(this.value.leftIor()) is Some -> Some(Pair(this.value, b.value).bothIor()) @@ -1017,6 +1021,7 @@ public inline fun Option.ensure(error: () -> Unit, predicate: (A) -> Bool error() None } + is None -> this } } @@ -1103,14 +1108,20 @@ public fun Option>.separateValidated(): Pair, O public fun Option>.sequence(): List> = traverse(::identity) -@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceEither is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Option>.sequenceEither(): Either> = sequence() public fun Option>.sequence(): Either> = traverse(::identity) -@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceValidated is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Option>.sequenceValidated(): Validated> = sequence() @@ -1185,6 +1196,7 @@ public fun Option.combine(SGA: Semigroup, b: Option): Option = is Some -> Some(SGA.run { value.combine(b.value) }) None -> this } + None -> b } @@ -1194,3 +1206,53 @@ public operator fun > Option.compareTo(other: Option): I other.fold({ 1 }, { a2 -> a1.compareTo(a2) }) } ) + +/** + * Recover from any [None] if encountered. + * + * The recover DSL allows you to recover from any [None] value by: + * - Computing a fallback value [A] + * - Shifting a _new error_ of [None] into the [Option]. + * + * ```kotlin + * import arrow.core.Option + * import arrow.core.none + * import arrow.core.Some + * import arrow.core.recover + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val error: Option = none() + * val fallback: Option = error.recover { 5 } + * fallback shouldBe Some(5) + * } + * ``` + * + * + * + * When shifting a new error [None] into the [Option]: + * + * ```kotlin + * import arrow.core.Option + * import arrow.core.none + * import arrow.core.Some + * import arrow.core.recover + * import io.kotest.matchers.shouldBe + * + * fun test() { + * val error: Option = none() + * fun fallback(): Option = Some(5) + * fun failure(): Option = none() + * + * error.recover { fallback().bind() } shouldBe Some(5) + * error.recover { failure().bind() } shouldBe none() + * } + * ``` + * + * + */ +public inline fun Option.recover(recover: OptionRaise.(None) -> A): Option = + when (this@recover) { + is None -> option { recover(this, None) } + is Some -> this@recover + } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/either.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/either.kt index ffeaccf5db9..e18d42e008b 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/either.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/either.kt @@ -11,26 +11,29 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.coroutines.RestrictsSuspension -@Deprecated(deprecateInFavorOfEffectScope, ReplaceWith("EffectScope", "arrow.core.continuations.EffectScope")) +@Deprecated( + "EitherEffect is replaced with arrow.core.raise.Raise", + ReplaceWith("Raise", "arrow.core.raise.Raise") +) public fun interface EitherEffect : Effect> { - + public suspend fun Either.bind(): B = when (this) { is Either.Right -> value is Left -> control().shift(this@bind) } - + public suspend fun Validated.bind(): B = when (this) { is Validated.Valid -> value is Validated.Invalid -> control().shift(Left(value)) } - + public suspend fun Result.bind(transform: (Throwable) -> E): B = fold(::identity) { throwable -> control().shift(transform(throwable).left()) } - + /** * Ensure check if the [value] is `true`, * and if it is it allows the `either { }` binding to continue. @@ -85,34 +88,41 @@ public fun interface EitherEffect : Effect> { * ``` * */ -@Deprecated(deprecateInFavorOfEffectScope) +@Deprecated( + "Replaced by Raise, replace arrow.core.computations.ensureNotNull to arrow.core.raise.ensureNotNull", + ReplaceWith( + "ensureNotNull(value, orLeft)", + "import arrow.core.raise.ensureNotNull" + ) +) @OptIn(ExperimentalContracts::class) // Contracts not available on open functions, so made it top-level. public suspend fun EitherEffect.ensureNotNull(value: B?, orLeft: () -> E): B { contract { returns() implies (value != null) } - + return value ?: orLeft().left().bind() } -@Deprecated(deprecatedInFavorOfEagerEffectScope, ReplaceWith("EagerEffectScope", "arrow.core.continuations.EagerEffectScope")) +@Deprecated( + "RestrictedEitherEffect is replaced with arrow.core.raise.Raise", + ReplaceWith("Raise", "arrow.core.raise.Raise") +) @RestrictsSuspension public fun interface RestrictedEitherEffect : EitherEffect -@Deprecated(deprecateInFavorOfEffectOrEagerEffect, ReplaceWith("either", "arrow.core.continuations.either")) +@Deprecated(eitherDSLDeprecation, ReplaceWith("either", "arrow.core.raise.either")) @Suppress("ClassName") public object either { - @Deprecated(deprecateInFavorOfEagerEffect, ReplaceWith("either.eager(c)", "arrow.core.continuations.either")) + @Deprecated(eitherDSLDeprecation, ReplaceWith("either(c)", "arrow.core.raise.either")) public inline fun eager(crossinline c: suspend RestrictedEitherEffect.() -> A): Either = Effect.restricted(eff = { RestrictedEitherEffect { it } }, f = c, just = { it.right() }) - - @Deprecated(deprecateInFavorOfEffect, ReplaceWith("either(c)", "arrow.core.continuations.either")) + + @Deprecated(eitherDSLDeprecation, ReplaceWith("either(c)", "arrow.core.raise.either")) public suspend inline operator fun invoke(crossinline c: suspend EitherEffect.() -> A): Either = Effect.suspended(eff = { EitherEffect { it } }, f = c, just = { it.right() }) } -internal const val deprecatedInFavorOfEagerEffectScope: String = "Deprecated in favor of Eager Effect DSL: EagerEffectScope" -internal const val deprecateInFavorOfEffectScope: String = "Deprecated in favor of Effect DSL: EffectScope" -internal const val deprecateInFavorOfEffect: String = "Deprecated in favor of the Effect Runtime" -internal const val deprecateInFavorOfEagerEffect: String = "Deprecated in favor of the EagerEffect Runtime" -internal const val deprecateInFavorOfEffectOrEagerEffect: String = "Deprecated in favor of the Effect or EagerEffect Runtime" +private const val eitherDSLDeprecation = + "The either DSL has been moved to arrow.core.raise.either.\n" + + "Replace import arrow.core.computations.* with arrow.core.raise.*" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/eval.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/eval.kt index 20579e4ebf2..4fa6bb4894d 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/eval.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/eval.kt @@ -4,24 +4,28 @@ import arrow.continuations.Effect import arrow.core.Eval import kotlin.coroutines.RestrictsSuspension -@Deprecated(deprecateInFavorOfEffectScope, ReplaceWith("EffectScope", "arrow.core.continuations.EffectScope")) +@Deprecated("EvalEffect is redundant. Use Eval#value directly instead") public fun interface EvalEffect : Effect> { + @Deprecated( + "EvalEffect is redundant. Use Eval#value directly instead", + ReplaceWith("this.value()") + ) public suspend fun Eval.bind(): B = value() } -@Deprecated(deprecatedInFavorOfEagerEffectScope, ReplaceWith("EagerEffectScope", "arrow.core.continuations.EagerEffectScope")) +@Deprecated("RestrictedEvalEffect is redundant. Use Eval#value directly instead") @RestrictsSuspension public fun interface RestrictedEvalEffect : EvalEffect -@Deprecated(deprecateInFavorOfEffectOrEagerEffect) +@Deprecated("EvalEffect is redundant. Use Eval#value directly instead") @Suppress("ClassName") public object eval { - @Deprecated(deprecateInFavorOfEagerEffect, ReplaceWith("eagerEffect(func)", "arrow.core.continuations.eagerEffect")) + @Deprecated("EvalEffect is redundant. Use Eval#value directly instead") public inline fun eager(crossinline func: suspend RestrictedEvalEffect.() -> A): Eval = Effect.restricted(eff = { RestrictedEvalEffect { it } }, f = func, just = Eval.Companion::now) - - @Deprecated(deprecateInFavorOfEffect, ReplaceWith("effect(func)", "arrow.core.continuations.effect")) + + @Deprecated("EvalEffect is redundant. Use Eval#value) directly instead") public suspend inline operator fun invoke(crossinline func: suspend EvalEffect<*>.() -> A): Eval = Effect.suspended(eff = { EvalEffect { it } }, f = func, just = Eval.Companion::now) } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/nullable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/nullable.kt index 883da45cf17..2a27aed11e6 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/nullable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/nullable.kt @@ -7,7 +7,10 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.coroutines.RestrictsSuspension -@Deprecated(deprecateInFavorOfEffectScope) +@Deprecated( + "NullableEffect is replaced with arrow.core.raise.NullableRaise", + ReplaceWith("NullableRaise", "arrow.core.raise.NullableRaise") +) public fun interface NullableEffect : Effect { public suspend fun B?.bind(): B = this ?: control().shift(null) @@ -68,7 +71,13 @@ public fun interface NullableEffect : Effect { * ``` * */ -@Deprecated(deprecateInFavorOfEffectScope, ReplaceWith("ensureNotNull", "arrow.core.continuations.ensureNotNull")) +@Deprecated( + "Replaced by Raise, replace arrow.core.computations.ensureNotNull to arrow.core.raise.ensureNotNull", + ReplaceWith( + "ensureNotNull(value)", + "import arrow.core.raise.ensureNotNull" + ) +) @OptIn(ExperimentalContracts::class) // Contracts not available on open functions, so made it top-level. public suspend fun NullableEffect<*>.ensureNotNull(value: B?): B { contract { @@ -78,18 +87,25 @@ public suspend fun NullableEffect<*>.ensureNotNull(value: B?): B { return value ?: control().shift(null) } -@Deprecated(deprecatedInFavorOfEagerEffectScope) +@Deprecated( + "RestrictedNullableEffect is replaced with arrow.core.raise.NullableRaise", + ReplaceWith("NullableRaise", "arrow.core.raise.NullableRaise") +) @RestrictsSuspension public fun interface RestrictedNullableEffect : NullableEffect -@Deprecated(deprecateInFavorOfEffectOrEagerEffect, ReplaceWith("nullable", "arrow.core.continuations.nullable")) +@Deprecated(nullableDSLDeprecation, ReplaceWith("nullable", "arrow.core.raise.nullable")) @Suppress("ClassName") public object nullable { - @Deprecated(deprecateInFavorOfEagerEffect, ReplaceWith("nullable.eager(func)", "arrow.core.continuations.nullable")) + @Deprecated(nullableDSLDeprecation, ReplaceWith("nullable(func)", "arrow.core.raise.nullable")) public inline fun eager(crossinline func: suspend RestrictedNullableEffect.() -> A?): A? = Effect.restricted(eff = { RestrictedNullableEffect { it } }, f = func, just = { it }) - - @Deprecated(deprecateInFavorOfEffect, ReplaceWith("nullable(func)", "arrow.core.continuations.nullable")) + + @Deprecated(nullableDSLDeprecation, ReplaceWith("nullable(func)", "arrow.core.raise.nullable")) public suspend inline operator fun invoke(crossinline func: suspend NullableEffect<*>.() -> A?): A? = Effect.suspended(eff = { NullableEffect { it } }, f = func, just = { it }) } + +private const val nullableDSLDeprecation = + "The nullable DSL has been moved to arrow.core.raise.nullable.\n" + + "Replace import arrow.core.computations.* with arrow.core.raise.*" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/option.kt index 754bf1eb7c5..778dd8d3408 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/option.kt @@ -8,7 +8,10 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.coroutines.RestrictsSuspension -@Deprecated(deprecateInFavorOfEffectScope, ReplaceWith("EffectScope", "arrow.core.continuations.EffectScope")) +@Deprecated( + "OptionEffect is replaced with arrow.core.raise.OptionRaise", + ReplaceWith("OptionRaise", "arrow.core.raise.OptionRaise") +) public fun interface OptionEffect : Effect> { public suspend fun Option.bind(): B = fold({ control().shift(None) }, ::identity) @@ -66,7 +69,13 @@ public fun interface OptionEffect : Effect> { * ``` * */ -@Deprecated(deprecateInFavorOfEffectScope) +@Deprecated( + "Replaced by Raise, replace arrow.core.computations.ensureNotNull to arrow.core.raise.ensureNotNull", + ReplaceWith( + "ensureNotNull(value)", + "import arrow.core.raise.ensureNotNull" + ) +) @OptIn(ExperimentalContracts::class) // Contracts not available on open functions, so made it top-level. public suspend fun OptionEffect<*>.ensureNotNull(value: B?): B { contract { @@ -76,18 +85,32 @@ public suspend fun OptionEffect<*>.ensureNotNull(value: B?): B { return value ?: (this as OptionEffect).control().shift(None) } -@Deprecated(deprecatedInFavorOfEagerEffectScope, ReplaceWith("EagerEffectScope", "arrow.core.continuations.EagerEffectScope")) -@RestrictsSuspension +@Deprecated( + "RestrictedEitherEffect is replaced with arrow.core.raise.OptionRaise", + ReplaceWith("OptionRaise", "arrow.core.raise.OptionRaise") +)@RestrictsSuspension public fun interface RestrictedOptionEffect : OptionEffect -@Deprecated(deprecateInFavorOfEffectOrEagerEffect, ReplaceWith("option", "arrow.core.continuations.option")) +@Deprecated( + optionDSLDeprecation, + ReplaceWith("option", "arrow.core.raise.option") +) @Suppress("ClassName") public object option { - @Deprecated(deprecateInFavorOfEagerEffect, ReplaceWith("option.eager(func)", "arrow.core.continuations.option")) + @Deprecated( + optionDSLDeprecation, + ReplaceWith("option(func)", "arrow.core.raise.option") + ) public inline fun eager(crossinline func: suspend RestrictedOptionEffect.() -> A): Option = Effect.restricted(eff = { RestrictedOptionEffect { it } }, f = func, just = { Option.fromNullable(it) }) - - @Deprecated(deprecateInFavorOfEffect, ReplaceWith("option(func)", "arrow.core.continuations.option")) - public suspend inline operator fun invoke(crossinline func: suspend OptionEffect<*>.() -> A?): Option = + + @Deprecated( + optionDSLDeprecation, + ReplaceWith("option(func)", "arrow.core.raise.option") + ) public suspend inline operator fun invoke(crossinline func: suspend OptionEffect<*>.() -> A?): Option = Effect.suspended(eff = { OptionEffect { it } }, f = func, just = { Option.fromNullable(it) }) } + +private const val optionDSLDeprecation = + "The option DSL has been moved to arrow.core.raise.option.\n" + + "Replace import arrow.core.computations.* with arrow.core.raise.*" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/result.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/result.kt index 68061797952..99b5bd715c9 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/result.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/computations/result.kt @@ -7,23 +7,26 @@ import arrow.core.identity /** * DSL Receiver Syntax for [result]. */ -@Deprecated("$deprecatedInFavorOfEagerEffectScope\nThis object introduces dangerous behavior and will be removed in the next version: https://github.com/arrow-kt/arrow/issues/2547") +@Deprecated( + "ResultEffect is replaced with arrow.core.raise.ResultRaise", + ReplaceWith("ResultRaise", "arrow.core.raise.ResultRaise") +) public object ResultEffect { - @Deprecated("$deprecatedInFavorOfEagerEffectScope\nThis object introduces dangerous behavior and will be removed in the next version: https://github.com/arrow-kt/arrow/issues/2547") + @Deprecated("This object introduces dangerous behavior.") public fun Result.bind(): A = getOrThrow() - - @Deprecated("$deprecatedInFavorOfEagerEffectScope\nThis object introduces dangerous behavior and will be removed in the next version: https://github.com/arrow-kt/arrow/issues/2547") + + @Deprecated("This object introduces dangerous behavior.") public fun Either.bind(): A = fold({ throw it }, ::identity) - - @Deprecated("$deprecatedInFavorOfEagerEffectScope\nThis object introduces dangerous behavior and will be removed in the next version: https://github.com/arrow-kt/arrow/issues/2547") + + @Deprecated("This object introduces dangerous behavior.") public fun Validated.bind(): A = fold({ throw it }, ::identity) } -@Deprecated(deprecateInFavorOfEffectOrEagerEffect, ReplaceWith("result", "arrow.core.continuations.result")) +@Deprecated(resultDSLDeprecation, ReplaceWith("result", "arrow.core.raise.result")) @Suppress("ClassName") public object result { @@ -54,7 +57,14 @@ public object result { * ``` * */ - @Deprecated(deprecateInFavorOfEffect, ReplaceWith("result.eager(block)", "arrow.core.continuations.result")) + @Deprecated( + resultDSLDeprecation, + ReplaceWith("result { block() }", "arrow.core.raise.result") + ) public inline operator fun invoke(block: ResultEffect.() -> A): Result = kotlin.runCatching { block(ResultEffect) } } + +private const val resultDSLDeprecation = + "The result DSL has been moved to arrow.core.raise.result.\n" + + "Replace import arrow.core.computations.* with arrow.core.raise.*" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffect.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffect.kt index c86e54bd075..ffe657357c6 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffect.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffect.kt @@ -18,6 +18,10 @@ import kotlin.coroutines.RestrictsSuspension * An [effect] computation interoperates with an [EagerEffect] via `bind`. * @see Effect */ +@Deprecated( + "Use the arrow.core.raise.Effect type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick." +) public interface EagerEffect { /** @@ -161,6 +165,11 @@ internal class Eager(val token: Token, val shifted: Any?, val recover: (Any?) -> * ``` * */ +@Deprecated( + "Use the arrow.core.raise.effect DSL instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith("eagerEffect(f)", "arrow.core.raise.eagerEffect") +) public fun eagerEffect(f: suspend EagerEffectScope.() -> A): EagerEffect = DefaultEagerEffect(f) private class DefaultEagerEffect(private val f: suspend EagerEffectScope.() -> A) : EagerEffect { diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffectScope.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffectScope.kt index 2eedc8bf645..4d6c5d77c28 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffectScope.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EagerEffectScope.kt @@ -7,6 +7,7 @@ import arrow.core.Option import arrow.core.Some import arrow.core.Validated import arrow.core.identity +import arrow.core.raise.fold import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.coroutines.RestrictsSuspension @@ -14,6 +15,11 @@ import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmInline /** Context of the [EagerEffect] DSL. */ +@Deprecated( + "Use the arrow.core.raise.Raise type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith("Raise", "arrow.core.raise.Raise") +) @RestrictsSuspension public interface EagerEffectScope { @@ -64,7 +70,10 @@ public interface EagerEffectScope { fold({ r -> left = r }, { a -> right = a }) return if (left === EmptyValue) EmptyValue.unbox(right) else shift(EmptyValue.unbox(left)) } - + + public suspend fun arrow.core.raise.EagerEffect.bind(): B = + fold({ shift(it) }, ::identity) + /** * Folds [Either] into [EagerEffect], by returning [B] or a shift with [R]. * @@ -261,6 +270,11 @@ public interface EagerEffectScope { * ``` * */ +@Deprecated( + "Use the arrow.core.raise.Raise type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith("ensureNotNull(value, shift)", "arrow.core.raise.ensureNotNull") +) @OptIn(ExperimentalContracts::class) public suspend fun EagerEffectScope.ensureNotNull(value: B?, shift: () -> R): B { contract { returns() implies (value != null) } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt index fd3c5daa6a3..247710e1778 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt @@ -630,6 +630,10 @@ import kotlin.coroutines.resumeWithException * ``` * */ +@Deprecated( + "Use the arrow.core.raise.Effect type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick." +) public interface Effect { /** * Runs the suspending computation by creating a [Continuation], and running the `fold` function @@ -658,7 +662,7 @@ public interface Effect { */ public suspend fun fold( recover: suspend (shifted: R) -> B, - transform: suspend (value: A) -> B + transform: suspend (value: A) -> B, ): B /** @@ -668,7 +672,7 @@ public interface Effect { public suspend fun fold( error: suspend (error: Throwable) -> B, recover: suspend (shifted: R) -> B, - transform: suspend (value: A) -> B + transform: suspend (value: A) -> B, ): B = try { fold(recover, transform) @@ -729,9 +733,16 @@ public interface Effect { fold(recover, transform) } + @Deprecated( + "redeemWith is being removed in the Raise API", + ReplaceWith( + "effect { fold(recover, transform).bind() }", + "arrow.core.raise.effect" + ) + ) public fun redeemWith( recover: suspend (R) -> Effect, - transform: suspend (A) -> Effect + transform: suspend (A) -> Effect, ): Effect = effect { fold(recover, transform).bind() } } @@ -868,6 +879,14 @@ internal class FoldContinuation( * ``` * */ +@Deprecated( + "Use the arrow.core.raise.effect DSL instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith( + "effect(f)", + "arrow.core.raise.effect" + ) +) public fun effect(f: suspend EffectScope.() -> A): Effect = DefaultEffect(f) private class DefaultEffect(val f: suspend EffectScope.() -> A) : Effect { diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EffectScope.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EffectScope.kt index 7e9e224d9c2..dbef07205d7 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EffectScope.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/EffectScope.kt @@ -7,11 +7,17 @@ import arrow.core.Option import arrow.core.Some import arrow.core.Validated import arrow.core.identity +import arrow.core.raise.fold import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference /** Context of the [Effect] DSL. */ +@Deprecated( + "Use the arrow.core.raise.Raise type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith("Raise", "arrow.core.raise.Raise") +) public interface EffectScope { /** * Short-circuit the [Effect] computation with value [R]. @@ -30,7 +36,7 @@ public interface EffectScope { * */ public suspend fun shift(r: R): B - + /** * Runs the [Effect] to finish, returning [B] or [shift] in case of [R]. * @@ -56,7 +62,7 @@ public interface EffectScope { * */ public suspend fun Effect.bind(): B = fold(this@EffectScope::shift, ::identity) - + /** * Runs the [EagerEffect] to finish, returning [B] or [shift] in case of [R], * bridging eager computations into suspending. @@ -89,7 +95,13 @@ public interface EffectScope { fold({ r -> left = r }, { a -> right = a }) return if (left === EmptyValue) EmptyValue.unbox(right) else shift(EmptyValue.unbox(left)) } - + + public suspend fun arrow.core.raise.Effect.bind(): B = + fold(this@EffectScope::shift, ::identity) + + public suspend fun arrow.core.raise.EagerEffect.bind(): B = + fold({ shift(it) }, ::identity) + /** * Folds [Either] into [Effect], by returning [B] or a shift with [R]. * @@ -113,7 +125,7 @@ public interface EffectScope { is Either.Left -> shift(value) is Either.Right -> value } - + /** * Folds [Validated] into [Effect], by returning [B] or a shift with [R]. * @@ -137,7 +149,7 @@ public interface EffectScope { is Validated.Valid -> value is Validated.Invalid -> shift(value) } - + /** * Folds [Result] into [Effect], by returning [B] or a transforming [Throwable] into [R] and * shifting the result. @@ -160,7 +172,7 @@ public interface EffectScope { */ public suspend fun Result.bind(transform: (Throwable) -> R): B = fold(::identity) { throwable -> shift(transform(throwable)) } - + /** * Folds [Option] into [Effect], by returning [B] or a transforming [None] into [R] and shifting the * result. @@ -189,7 +201,7 @@ public interface EffectScope { None -> shift(shift()) is Some -> value } - + /** * ensure that condition is `true`, if it's `false` it will `shift` with the provided value [R]. * Monadic version of [kotlin.require]. @@ -213,7 +225,7 @@ public interface EffectScope { */ public suspend fun ensure(condition: Boolean, shift: () -> R): Unit = if (condition) Unit else shift(shift()) - + /** * Encloses an action for which you want to catch any `shift`. * [attempt] is used in combination with [catch]. @@ -226,12 +238,17 @@ public interface EffectScope { * the chance for a later [catch] to change the shifted value. * This is useful to simulate re-throwing of exceptions. */ + @Deprecated( + "Use the arrow.core.raise.Raise type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick. Add missing imports and you're good to go!", + ReplaceWith("effect(f)", "arrow.core.raise.effect") + ) @OptIn(ExperimentalTypeInference::class) public suspend fun attempt( @BuilderInference f: suspend EffectScope.() -> A, ): suspend EffectScope.() -> A = f - + /** * When the [Effect] has shifted with [R] it will [recover] * the shifted value to [A], and when it ran the computation to @@ -259,9 +276,18 @@ public interface EffectScope { * ``` * */ + @Deprecated( + "This method is renamed to recover in the new Raise type." + + "Apply the ReplaceWith refactor, and then a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick. Add missing imports and you're good to go!", + ReplaceWith("recover(f)") + ) public suspend infix fun (suspend EffectScope.() -> A).catch( recover: suspend EffectScope.(E) -> A, ): A = effect(this).fold({ recover(it) }, ::identity) + + public suspend infix fun (suspend EffectScope.() -> A).recover( + recover: suspend EffectScope.(E) -> A, + ): A = effect(this).fold({ recover(it) }, ::identity) } /** @@ -285,6 +311,11 @@ public interface EffectScope { * ``` * */ +@Deprecated( + "Use the arrow.core.raise.Raise type instead, which is more general and can be used to and can be used to raise typed errors or _logical failures_\n" + + "The Raise type is source compatible, a simple find & replace of arrow.core.continuations.* to arrow.core.raise.* will do the trick.", + ReplaceWith("ensureNotNull(value, shift)", "arrow.core.raise.ensureNotNull") +) @OptIn(ExperimentalContracts::class) public suspend fun EffectScope.ensureNotNull(value: B?, shift: () -> R): B { contract { returns() implies (value != null) } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/either.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/either.kt index a03b738ef37..f249fc67893 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/either.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/either.kt @@ -2,11 +2,18 @@ package arrow.core.continuations import arrow.core.Either +@Deprecated(eitherDSLDeprecation, ReplaceWith("either", "arrow.core.raise.either")) @Suppress("ClassName") public object either { + @Deprecated(eitherDSLDeprecation, ReplaceWith("either(f)", "arrow.core.raise.either")) public inline fun eager(noinline f: suspend EagerEffectScope.() -> A): Either = eagerEffect(f).toEither() + @Deprecated(eitherDSLDeprecation, ReplaceWith("either(f)", "arrow.core.raise.either")) public suspend operator fun invoke(f: suspend EffectScope.() -> A): Either = effect(f).toEither() } + +private const val eitherDSLDeprecation = + "The either DSL has been moved to arrow.core.raise.either.\n" + + "Replace import arrow.core.computations.either with arrow.core.raise.either" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/ior.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/ior.kt index 99ff373005a..7c56ee9eb90 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/ior.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/ior.kt @@ -5,8 +5,10 @@ import arrow.core.Ior import arrow.core.identity import arrow.typeclasses.Semigroup +@Deprecated(iorDSLDeprecation, ReplaceWith("ior", "arrow.core.raise.ior")) @Suppress("ClassName") public object ior { + @Deprecated(iorDSLDeprecation, ReplaceWith("ior(semigroup, f)", "arrow.core.raise.ior")) public inline fun eager( semigroup: Semigroup, crossinline f: suspend IorEagerEffectScope.() -> A @@ -18,7 +20,8 @@ public object ior { val leftState = effect.leftState.get() if (leftState === EmptyValue) Ior.Right(res) else Ior.Both(EmptyValue.unbox(leftState), res) }.fold({ Ior.Left(it) }, ::identity) - + + @Deprecated(iorDSLDeprecation, ReplaceWith("ior(semigroup, f)", "arrow.core.raise.ior")) public suspend inline operator fun invoke( semigroup: Semigroup, crossinline f: suspend IorEffectScope.() -> A @@ -31,6 +34,10 @@ public object ior { }.fold({ Ior.Left(it) }, ::identity) } +@Deprecated( + "IorEffectScope is replaced with arrow.core.raise.IorRaise", + ReplaceWith("IorRaise", "arrow.core.raise.IorRaise") +) public class IorEffectScope(semigroup: Semigroup, private val effect: EffectScope) : EffectScope, Semigroup by semigroup { @@ -56,6 +63,10 @@ public class IorEffectScope(semigroup: Semigroup, private val effect: Effe override suspend fun shift(r: E): B = effect.shift(combine(r)) } +@Deprecated( + "IorEagerEffectScope is replaced with arrow.core.raise.IorRaise", + ReplaceWith("IorRaise", "arrow.core.raise.IorRaise") +) public class IorEagerEffectScope(semigroup: Semigroup, private val effect: EagerEffectScope) : EagerEffectScope, Semigroup by semigroup { @@ -81,3 +92,7 @@ public class IorEagerEffectScope(semigroup: Semigroup, private val effect: @Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL") override suspend fun shift(r: E): B = effect.shift(combine(r)) } + +private const val iorDSLDeprecation = + "The ior DSL has been moved to arrow.core.raise.ior.\n" + + "Replace import arrow.core.computations.ior with arrow.core.raise.ior" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/nullable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/nullable.kt index 1a485754b41..4a1c72d3a20 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/nullable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/nullable.kt @@ -5,6 +5,10 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.jvm.JvmInline +@Deprecated( + "NullableEffectScope is replaced with arrow.core.raise.NullableRaise", + ReplaceWith("NullableRaise", "arrow.core.raise.NullableRaise") +) @JvmInline public value class NullableEffectScope(private val cont: EffectScope) : EffectScope { override suspend fun shift(r: Nothing?): B = @@ -23,6 +27,10 @@ public value class NullableEffectScope(private val cont: EffectScope) ensure(value) { null } } +@Deprecated( + "NullableEagerEffectScope is replaced with arrow.core.raise.NullableRaise", + ReplaceWith("NullableRaise", "arrow.core.raise.NullableRaise") +) @JvmInline public value class NullableEagerEffectScope(private val cont: EagerEffectScope) : EagerEffectScope { @Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL") @@ -54,14 +62,21 @@ public suspend fun NullableEagerEffectScope.ensureNotNull(value: B?): B { return ensureNotNull(value) { null } } +@Deprecated(nullableDSLDeprecation, ReplaceWith("nullable", "arrow.core.raise.nullable")) @Suppress("ClassName") public object nullable { + @Deprecated(nullableDSLDeprecation, ReplaceWith("nullable(f)", "arrow.core.raise.nullable")) public inline fun eager(crossinline f: suspend NullableEagerEffectScope.() -> A): A? = eagerEffect { @Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL") f(NullableEagerEffectScope(this)) }.orNull() - + + @Deprecated(nullableDSLDeprecation, ReplaceWith("nullable(f)", "arrow.core.raise.nullable")) public suspend inline operator fun invoke(crossinline f: suspend NullableEffectScope.() -> A): A? = effect { f(NullableEffectScope(this)) }.orNull() } + +private const val nullableDSLDeprecation = + "The nullable DSL has been moved to arrow.core.raise.nullable.\n" + + "Replace import arrow.core.computations.nullable with arrow.core.raise.nullable" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/option.kt index 1e518d0d408..1d31ed25ec3 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/option.kt @@ -51,14 +51,30 @@ public value class OptionEagerEffectScope(private val cont: EagerEffectScope eager(crossinline f: suspend OptionEagerEffectScope.() -> A): Option = eagerEffect { @Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL") f(OptionEagerEffectScope(this)) }.toOption() - + + @Deprecated( + optionDSLDeprecation, + ReplaceWith("option(f)", "arrow.core.raise.option") + ) public suspend inline operator fun invoke(crossinline f: suspend OptionEffectScope.() -> A): Option = effect { f(OptionEffectScope(this)) }.toOption() } + +private const val optionDSLDeprecation = + "The option DSL has been moved to arrow.core.raise.option.\n" + + "Replace import arrow.core.computations.option with arrow.core.raise.option" diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/result.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/result.kt index 9b0d7faa89c..453b8830ab3 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/result.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/result.kt @@ -28,14 +28,27 @@ public value class ResultEagerEffectScope(private val cont: EagerEffectScope eager(crossinline f: suspend ResultEagerEffectScope.() -> A): Result = eagerEffect { @Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL") f(ResultEagerEffectScope(this)) }.toResult() - + + @Deprecated( + resultDSLDeprecation, + ReplaceWith("result(f)", "arrow.core.raise.result") + ) public suspend inline operator fun invoke(crossinline f: suspend ResultEffectScope.() -> A): Result = effect { f(ResultEffectScope(this)) }.toResult() } + +private const val resultDSLDeprecation = + "The result DSL has been moved to arrow.core.raise.result.\n" + + "Replace import arrow.core.computations.* with arrow.core.raise.*" 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 new file mode 100644 index 00000000000..f71e750f7e8 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt @@ -0,0 +1,116 @@ +@file:JvmMultifileClass +@file:JvmName("Effect") +@file:OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class) +package arrow.core.raise + +import arrow.core.Either +import arrow.core.Ior +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +import arrow.core.continuations.AtomicRef +import arrow.core.continuations.updateAndGet +import arrow.core.getOrElse +import arrow.core.identity +import arrow.core.orElse +import arrow.typeclasses.Semigroup +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind.EXACTLY_ONCE +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmInline +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + +public inline fun either(@BuilderInference block: Raise.() -> A): Either { + contract { callsInPlace(block, EXACTLY_ONCE) } + return fold({ block.invoke(this) }, { Either.Left(it) }, { Either.Right(it) }) +} + +public inline fun nullable(block: NullableRaise.() -> A): A? { + contract { callsInPlace(block, EXACTLY_ONCE) } + return fold({ block(NullableRaise(this)) }, { null }, ::identity) +} + +public inline fun result(block: ResultRaise.() -> A): Result { + contract { callsInPlace(block, EXACTLY_ONCE) } + return fold({ block(ResultRaise(this)) }, Result.Companion::failure, Result.Companion::success) +} + +public inline fun option(block: OptionRaise.() -> A): Option { + contract { callsInPlace(block, EXACTLY_ONCE) } + return fold({ block(OptionRaise(this)) }, ::identity, ::Some) +} + +public inline fun ior(semigroup: Semigroup, @BuilderInference block: IorRaise.() -> A): Ior { + contract { callsInPlace(block, EXACTLY_ONCE) } + val state: AtomicRef> = AtomicRef(None) + return fold>( + { block(IorRaise(semigroup, state, this)) }, + { e -> throw e }, + { e -> Ior.Left(state.get().getOrElse { e }) }, + { a -> state.get().fold({ Ior.Right(a) }, { Ior.Both(it, a) }) } + ) +} + +public typealias Null = Nothing? + +@JvmInline +public value class NullableRaise(private val cont: Raise) : Raise { + @RaiseDSL + public fun ensure(value: Boolean): Unit = ensure(value) { null } + override fun raise(r: Nothing?): Nothing = cont.raise(r) + public fun Option.bind(): B = bind { raise(null) } + + public fun B?.bind(): B { + contract { returns() implies (this@bind != null) } + return this ?: raise(null) + } + + public fun ensureNotNull(value: B?): B { + contract { returns() implies (value != null) } + return ensureNotNull(value) { null } + } +} + +@JvmInline +public value class ResultRaise(private val cont: Raise) : Raise { + override fun raise(r: Throwable): Nothing = cont.raise(r) + public fun Result.bind(): B = fold(::identity) { raise(it) } +} + +@JvmInline +public value class OptionRaise(private val cont: Raise) : Raise { + override fun raise(r: None): Nothing = cont.raise(r) + public fun Option.bind(): B = bind { raise(None) } + public fun ensure(value: Boolean): Unit = ensure(value) { None } + + public fun ensureNotNull(value: B?): B { + contract { returns() implies (value != null) } + return ensureNotNull(value) { None } + } +} + +public class IorRaise @PublishedApi internal constructor( + semigroup: Semigroup, + private val state: AtomicRef>, + private val raise: Raise, +) : Raise, Semigroup by semigroup { + + override fun raise(r: E): Nothing = raise.raise(combine(r)) + + public fun Ior.bind(): B = + when (this) { + is Ior.Left -> raise(value) + is Ior.Right -> value + is Ior.Both -> { + combine(leftValue) + rightValue + } + } + + private fun combine(other: E): E = + state.updateAndGet { prev -> + prev.map { e -> e.combine(other) }.orElse { Some(other) } + }.getOrElse { other } +} diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Effect.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Effect.kt new file mode 100644 index 00000000000..fab2f851510 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Effect.kt @@ -0,0 +1,673 @@ +@file:JvmMultifileClass +@file:OptIn(ExperimentalTypeInference::class) +package arrow.core.raise + +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmMultifileClass + +/** + * [Effect] represents a function of `suspend Raise.() -> A`, that short-circuit with a value of `R` or `Throwable`, or completes with a value of `A`. + * + * So [Effect] is defined by `suspend fun fold(recover: suspend (Throwable) -> B, resolve: suspend (R) -> B, transform: suspend (A) -> B): B`, + * to map all values of `R`, `Throwable` and `A` to a value of `B`. + * + * + + * [Writing a program with Effect](#writing-a-program-with-effect) + * [Handling errors](#handling-errors) + * [recover](#recover) + * [catch](#catch) + * [Structured Concurrency](#structured-concurrency) + * [Arrow Fx Coroutines](#arrow-fx-coroutines) + * [parZip](#parzip) + * [parTraverse](#partraverse) + * [raceN](#racen) + * [bracketCase / Resource](#bracketcase--resource) + * [KotlinX](#kotlinx) + * [withContext](#withcontext) + * [async](#async) + * [launch](#launch) + * [Strange edge cases](#strange-edge-cases) + + * + * + * ## Writing a program with Effect + * + * Let's write a small program to read a file from disk, and instead of having the program work exception based we want to + * turn it into a polymorphic type-safe program. + * + * We'll start by defining a small function that accepts a [String], and does some simply validation to check that the path + * is not empty. If the path is empty, we want to program to result in `EmptyPath`. So we're immediately going to see how + * we can raise an error of any arbitrary type `R` by using the function `raise`. The name `raise` comes raising an intterupt, or + * changing, especially unexpectedly, away from the computation and finishing the `Continuation` with `R`. + * + * + * ```kotlin + * object EmptyPath + * + * fun readFile(path: String): Effect = effect { + * if (path.isEmpty()) raise(EmptyPath) else Unit + * } + * ``` + * + * Here we see how we can define an `Effect` which has `EmptyPath` for the raise type `R`, and `Unit` for the success type `A`. + * + * Patterns like validating a [Boolean] is very common, and the [Effect] DSL offers utility functions like [kotlin.require] + * and [kotlin.requireNotNull]. They're named [ensure] and [ensureNotNull] to avoid conflicts with the `kotlin` namespace. + * So let's rewrite the function from above to use the DSL instead. + * + * ```kotlin + * fun readFile2(path: String?): Effect = effect { + * ensureNotNull(path) { EmptyPath } + * ensure(path.isNotEmpty()) { EmptyPath } + * } + * ``` + * + * + * Now that we have the path, we can read from the `File` and return it as a domain model `Content`. + * We also want to take a look at what exceptions reading from a file might occur `FileNotFoundException` & `SecurityError`, + * so lets make some domain errors for those too. Grouping them as a sealed interface is useful since that way we can resolve *all* errors in a type safe manner. + * + * + * ```kotlin + * @JvmInline + * value class Content(val body: List) + * + * sealed interface FileError + * @JvmInline value class SecurityError(val msg: String?) : FileError + * @JvmInline value class FileNotFound(val path: String) : FileError + * object EmptyPath : FileError { + * override fun toString() = "EmptyPath" + * } + * ``` + * + * We can finish our function, but we need to refactor the return type from `Unit` to `Content` and the error type from `EmptyPath` to `FileError`. + * + * ```kotlin + * fun readFile(path: String?): Effect = effect { + * ensureNotNull(path) { EmptyPath } + * ensure(path.isNotEmpty()) { EmptyPath } + * try { + * val lines = File(path).readLines() + * Content(lines) + * } catch (e: FileNotFoundException) { + * raise(FileNotFound(path)) + * } catch (e: SecurityException) { + * raise(SecurityError(e.message)) + * } + * } + * ``` + * + * The `readFile` function defines a `suspend fun` that will return: + * + * - the `Content` of a given `path` + * - a `FileError` + * - An unexpected fatal error (`OutOfMemoryException`) + * + * Since these are the properties of our `Effect` function, we can turn it into a value. + * + * ```kotlin + * suspend fun main() { + * readFile("").toEither() shouldBe Either.Left(EmptyPath) + * readFile("knit.properties").toValidated() shouldBe Validated.Invalid(FileNotFound("knit.properties")) + * readFile("gradle.properties").toIor() shouldBe Ior.Left(FileNotFound("gradle.properties")) + * readFile("README.MD").toOption { None } shouldBe None + * + * readFile("build.gradle.kts").fold({ _: FileError -> null }, { it }) + * .shouldBeInstanceOf() + * .body.shouldNotBeEmpty() + * } + * ``` + * + * + * The functions above are available out of the box, but it's easy to define your own extension functions in terms + * of `fold`. Implementing the `toEither()` operator is as simple as: + * + * + * ```kotlin + * suspend fun Effect.toEither(): Either = + * fold({ Either.Left(it) }) { Either.Right(it) } + * + * suspend fun Effect.toOption(): Option = + * fold(::identity) { Some(it) } + * ``` + * + * + * Adding your own syntax to `Raise` is not advised, yet, but will be easy once "Multiple Receivers" become available. + * + * ``` + * context(Raise) + * suspend fun Either.bind(): A = + * when (this) { + * is Either.Left -> raise(value) + * is Either.Right -> value + * } + * + * context(Raise) + * fun Option.bind(): A = + * fold({ raise(it) }, ::identity) + * ``` + * + * ## Handling errors + * + * An Effect has 2 error channels: `Throwable` and `R` + * There are two separate handlers to transform either of the error channels. + * + * - `recover` to handle, and transform any error of type `R`. + * - `catch` to handle, and transform and error of type `Throwable`. + * + * ### recover + * + * `recover` handles the error of type `R`, + * by providing a new value of type `A`, raising a different error of type `E`, or throwing an exception. + * + * Let's take a look at some examples: + * + * We define a `val failed` of type `Effect`, that represents a failed effect with value "failed". + * + * + * ```kotlin + * val failed: Effect = + * effect { raise("failed") } + * ``` + * + * We can `recover` the failure, and resolve it by providing a default value of `-1` or the length of the `error: String`. + * + * ```kotlin + * val default: Effect = + * failed.recover { -1 } + * + * val resolved: Effect = + * failed.recover { it.length } + * ``` + * + * As you can see the resulting `error` is now of type `Nothing`, since we did not raise any new errors. + * So our `Effect` knows that no short-circuiting will occur during execution. Awesome! + * But it can also infer to any other error type that you might want instead, because it's never going to occur. + * So as you see below, we can even assign our `Effect` to `Effect`, where `E` can be any type. + * + * ```kotlin + * val default2: Effect = default + * val resolved2: Effect = resolved + * ``` + * + * `recover` also allows us to _change_ the error type when we resolve the error of type `R`. + * Below we handle our error of `String` and turn it into `List` using `reversed().toList()`. + * This is a powerful operation, since it allows us to transform our error types across boundaries or layers. + * + * ```kotlin + * val newError: Effect, Int> = + * failed.recover { str -> + * raise(str.reversed().toList()) + * } + * ``` + * + * Finally, since `recover` supports `suspend` we can safely call other `suspend` code and throw `Throwable` into the `suspend` system. + * This is typically undesired, since you should prefer lifting `Throwable` into typed values of `R` to make them compile-time tracked. + * + * ```kotlin + * val newException: Effect = + * failed.recover { str -> throw RuntimeException(str) } + * ``` + * + * ### catch + * + * `catch` gives us the same powers as `recover`, but instead of resolving `R` we're recovering from any unexpected `Throwable`. + * Unexpected, because the expectation is that all `Throwable` get turned into `R` unless it's a fatal/unexpected. + * This operator is useful when you need to work/wrap foreign code, especially Java SDKs or any code that is heavily based on exceptions. + * + * Below we've defined a `foreign` value that represents wrapping a foreign API which might throw `RuntimeException`. + * + * ```kotlin + * val foreign = effect { + * throw RuntimeException("BOOM!") + * } + * ``` + * + * We can `catch` to run the effect recovering from any exception, + * and recover it by providing a default value of `-1` or the length of the [Throwable.message]. + * + * ```kotlin + * val default3: Effect = + * foreign.catch { -1 } + * + * val resolved3: Effect = + * foreign.catch { it.message?.length ?: -1 } + * ``` + * + * A big difference with `recover` is that `catch` **cannot** change the error type of `R` because it doesn't resolve it, so it stays unchanged. + * You can however compose `recover`, and `v` to resolve the error type **and** recover the exception. + * + * ```kotlin + * val default4: Effect = + * foreign + * .recover { -1 } + * .catch { -2 } + * ``` + * + * `catch` however offers an overload that can _refine the exception_. + * Let's say you're wrapping some database interactions that might throw `java.sql.SqlException`, or `org.postgresql.util.PSQLException`, + * then you might only be interested in those exceptions and not `Throwable`. `catch` allows you to install multiple handlers for specific exceptions. + * If the desired exception is not matched, then it stays in the `suspend` exception channel and will be thrown or recovered at a later point. + * + * ```kotlin + * val default5: Effect = + * foreign + * .catch { ex: RuntimeException -> -1 } + * .catch { ex: java.sql.SQLException -> -2 } + * ``` + * + * Finally, since `catch` also supports `suspend` we can safely call other `suspend` code and throw `Throwable` into the `suspend` system. + * This can be useful if refinement of exceptions is not sufficient, for example in the case of `org.postgresql.util.PSQLException` you might want to + * check the `SQLState` to check for a `foreign key violation` and rethrow the exception if not matched. + * + * ```kotlin + * suspend fun java.sql.SQLException.isForeignKeyViolation(): Boolean = true + * + * val rethrown: Effect = + * failed.catch { ex: java.sql.SQLException -> + * if(ex.isForeignKeyViolation()) raise("foreign key violation") + * else throw ex + * } + * ``` + * + * + * + * Note: + * Handling errors can also be done with `try/catch` but this is **not recommended**, it uses `CancellationException` which is used to cancel `Coroutine`s and is advised not to capture in Kotlin. + * The `CancellationException` from `Effect` is `RaiseCancellationException`, this a public type, thus can be distinguished from any other `CancellationException` if necessary. + * + * ## Structured Concurrency + * + * `Effect` relies on `kotlin.cancellation.CancellationException` to `raise` error values of type `R` inside the `Continuation` since it effectively cancels/short-circuits it. + * For this reason `raise` adheres to the same rules as [`Structured Concurrency`](https://kotlinlang.org/docs/coroutines-basics.html#structured-concurrency) + * + * Let's overview below how `raise` behaves with the different concurrency builders from Arrow Fx & KotlinX Coroutines. + * In the examples below we're going to be using a utility to show how _sibling tasks_ get cancelled. + * The utility function show below called `awaitExitCase` will `never` finish suspending, and completes a `Deferred` with the `ExitCase`. + * `ExitCase` is a sealed class that can be a value of `Failure(Throwable)`, `Cancelled(CancellationException)`, or `Completed`. + * Since `awaitExitCase` suspends forever, it can only result in `Cancelled(CancellationException)`. + * + * + * ```kotlin + * suspend fun awaitExitCase(exit: CompletableDeferred): A = + * guaranteeCase(::awaitCancellation) { exitCase -> exit.complete(exitCase) } + * + * ``` + * + * ### Arrow Fx Coroutines + * All operators in Arrow Fx Coroutines run in place, so they have no way of leaking `raise`. + * It's there always safe to compose `effect` with any Arrow Fx combinator. Let's see some small examples below. + * + * #### parZip + * + * ```kotlin + * suspend fun main() { + * val error = "Error" + * val exit = CompletableDeferred() + * effect { + * parZip({ awaitExitCase(exit) }, { raise(error) }) { a: Int, b: Int -> a + b } + * }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + * exit.await().shouldBeTypeOf() + * } + * ``` + * + * + * #### parTraverse + * + * ```kotlin + * suspend fun main() { + * val error = "Error" + * val exits = (0..3).map { CompletableDeferred() } + * effect> { + * (0..4).parTraverse { index -> + * if (index == 4) raise(error) + * else awaitExitCase(exits[index]) + * } + * }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) + * // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran + * exits.forEach { exit -> exit.getOrNull()?.shouldBeTypeOf() } + * } + * ``` + * + * + * `parTraverse` will launch 5 tasks, for every element in `1..5`. + * The last task to get scheduled will `raise` with "error", and it will cancel the other launched tasks before returning. + * + * #### raceN + * + * ```kotlin + * suspend fun main() { + * val error = "Error" + * val exit = CompletableDeferred() + * effect { + * raceN({ awaitExitCase(exit) }) { raise(error) } + * .merge() // Flatten Either result from race into Int + * }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) + * // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran + * exit.getOrNull()?.shouldBeTypeOf() + * } + * ``` + * + * + * `raceN` races `n` suspend functions in parallel, and cancels all participating functions when a winner is found. + * We can consider the function that `raise`s the winner of the race, except with a raised value instead of a successful one. + * So when a function in the race `raise`s, and thus short-circuiting the race, it will cancel all the participating functions. + * + * #### bracketCase / Resource + * + * ```kotlin + * suspend fun main() { + * val error = "Error" + * val exit = CompletableDeferred() + * effect { + * bracketCase( + * acquire = { File("build.gradle.kts").bufferedReader() }, + * use = { reader: BufferedReader -> raise(error) }, + * release = { reader, exitCase -> + * reader.close() + * exit.complete(exitCase) + * } + * ) + * }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + * exit.await().shouldBeTypeOf() + * } + * ``` + * + * + * + * ```kotlin + * suspend fun main() { + * val error = "Error" + * val exit = CompletableDeferred() + * + * suspend fun ResourceScope.bufferedReader(path: String): BufferedReader = + * autoCloseable { File(path).bufferedReader() }.also { + * onRelease { exitCase -> exit.complete(exitCase) } + * } + * + * resourceScope { + * effect { + * val reader = bufferedReader("build.gradle.kts") + * raise(error) + * reader.lineSequence().count() + * }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + * } + * exit.await().shouldBeTypeOf() + * } + * ``` + * + * + * ### KotlinX + * #### withContext + * It's always safe to call `raise` from `withContext` since it runs in place, so it has no way of leaking `raise`. + * When `raise` is called from within `withContext` it will cancel all `Job`s running inside the `CoroutineScope` of `withContext`. + * + * + * ```kotlin + * suspend fun main() { + * val exit = CompletableDeferred() + * effect { + * withContext(Dispatchers.IO) { + * val job = launch { awaitExitCase(exit) } + * val content = readFile("failure").bind() + * job.join() + * content.body.size + * } + * }.fold({ e -> e shouldBe FileNotFound("failure") }, { fail("Int can never be the result") }) + * exit.await().shouldBeInstanceOf() + * } + * ``` + * + * + * #### async + * + * When calling `raise` from `async` you should **always** call `await`, otherwise `raise` can leak out of its scope. + * + * + * ```kotlin + * suspend fun main() { + * val errorA = "ErrorA" + * val errorB = "ErrorB" + * coroutineScope { + * effect { + * val fa = async { raise(errorA) } + * val fb = async { raise(errorB) } + * fa.await() + fb.await() + * }.fold({ error -> error shouldBeIn listOf(errorA, errorB) }, { fail("Int can never be the result") }) + * } + * } + * ``` + * + * + * #### launch + * + * + * ```kotlin + * suspend fun main() { + * val errorA = "ErrorA" + * val errorB = "ErrorB" + * val int = 45 + * effect { + * coroutineScope { + * launch { raise(errorA) } + * launch { raise(errorB) } + * int + * } + * }.fold({ fail("Raise can never finish") }, { it shouldBe int }) + * } + * ``` + * + * + * #### Strange edge cases + * + * **NOTE** + * Capturing `raise` into a lambda, and leaking it outside of `Effect` to be invoked outside will yield unexpected results. + * Below we capture `raise` from inside the DSL, and then invoke it outside its context `Raise`. + * + * + * + * ```kotlin + * effect Unit> { + * suspend { raise("error") } + * }.fold({ }, { leakedRaise -> leakedRaise.invoke() }) + * ``` + * + * The same violation is possible in all DSLs in Kotlin, including Structured Concurrency. + * + * ```kotlin + * val leakedAsync = coroutineScope Deferred> { + * suspend { + * async { + * println("I am never going to run, until I get called invoked from outside") + * } + * } + * } + * + * leakedAsync.invoke().await() + * ``` + * + */ +public typealias Effect = suspend Raise.() -> A + +public inline fun effect(@BuilderInference noinline block: suspend Raise.() -> A): Effect = block + +/** The same behavior and API as [Effect] except without requiring _suspend_. */ +public typealias EagerEffect = Raise.() -> A + +public inline fun eagerEffect(@BuilderInference noinline block: Raise.() -> A): EagerEffect = block diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/ErrorHandlers.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/ErrorHandlers.kt new file mode 100644 index 00000000000..c2cd2589259 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/ErrorHandlers.kt @@ -0,0 +1,110 @@ +@file:JvmMultifileClass +@file:JvmName("Effect") +@file:OptIn(ExperimentalTypeInference::class) +package arrow.core.raise + +import arrow.core.nonFatalOrThrow +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + +/** + * Catch the raised value [E] of the `Effect`. + * You can either return a value a new value of [A], + * or short-circuit the effect by raising with a value of [E], + * or raise an exception into [suspend]. + * + * ```kotlin + * import arrow.core.raise.effect + * import arrow.core.raise.recover + * + * object User + * object Error + * + * val error = effect { raise(Error) } // Raise(error) + * + * val a = error.recover { error -> User } // Success(User) + * val b = error.recover { error -> raise("other-failure") } // Raise(other-failure) + * val c = error.recover { error -> throw RuntimeException("BOOM") } // Exception(BOOM) + * ``` + * + */ +public infix fun Effect.recover(@BuilderInference resolve: suspend Raise.(raised: E) -> A): Effect = + effect { recover(resolve) } + +/** + * Catch any unexpected exceptions, and [resolve] them. + * You can either return a value a new value of [A], + * or short-circuit the effect by raising with a value of [E], + * or raise an exception into [suspend]. + * + * ```kotlin + * import arrow.core.raise.effect + * import arrow.core.raise.catch + * + * object User + * object Error + * + * val exception = effect { throw RuntimeException("BOOM") } // Exception(BOOM) + * + * val a = exception.catch { error -> error.message?.length ?: -1 } // Success(5) + * val b = exception.catch { raise(Error) } // Raise(error) + * val c = exception.catch { throw RuntimeException("other-failure") } // Exception(other-failure) + * ``` + * + */ +public infix fun Effect.catch(@BuilderInference resolve: suspend Raise.(throwable: Throwable) -> A): Effect = + effect { catch(resolve) } + +/** + * A version of [catch] that refines the [Throwable] to [T]. + * This is useful for wrapping foreign code, such as database, network calls, etc. + * + * ```kotlin + * import arrow.core.raise.effect + * import arrow.core.raise.catch + * + * object User + * object Error + * + * val x = effect { + * throw IllegalArgumentException("builder missed args") + * }.catch { raise(Error) } + * ``` + * + * If you don't need an `error` value when wrapping your foreign code you can use `Nothing` to fill the type parameter. + * + * ```kotlin + * val y = effect { + * throw IllegalArgumentException("builder missed args") + * }.catch { raise(Error) } + * ``` + * + */ +@JvmName("catchReified") +public inline infix fun Effect.catch( + @BuilderInference crossinline recover: suspend Raise.(T) -> A, +): Effect = + effect { catch { t: Throwable -> if (t is T) recover(t) else throw t } } + +/** Runs the [Effect] and captures any [nonFatalOrThrow] exception into [Result]. */ +public fun Effect.catch(): Effect> = + effect { + try { + Result.success(invoke()) + } catch (e: Throwable) { + Result.failure(e.nonFatalOrThrow()) + } + } + +public infix fun EagerEffect.recover(@BuilderInference resolve: Raise.(raised: E) -> A): EagerEffect = + eagerEffect { recover(resolve) } + +public infix fun EagerEffect.catch(@BuilderInference recover: Raise.(throwable: Throwable) -> A): EagerEffect = + eagerEffect { catch(recover) } + +@JvmName("catchReified") +public inline infix fun EagerEffect.catch( + @BuilderInference crossinline recover: Raise.(T) -> A, +): EagerEffect = + eagerEffect { catch { t: Throwable -> if (t is T) recover(t) else throw t } } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt new file mode 100644 index 00000000000..f8e0262d56a --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Fold.kt @@ -0,0 +1,122 @@ +@file:JvmMultifileClass +@file:JvmName("Effect") +@file:OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class) +package arrow.core.raise + +import arrow.core.nonFatalOrThrow +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.InvocationKind.AT_MOST_ONCE +import kotlin.contracts.InvocationKind.EXACTLY_ONCE +import kotlin.contracts.contract +import kotlin.coroutines.cancellation.CancellationException +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + +/** + * `invoke` the [Effect] and [fold] the result: + * - _success_ [transform] result of [A] to a value of [B]. + * - _raised_ [recover] from `raised` value of [R] to a value of [B]. + * - _exception_ [error] from [Throwable] by transforming value into [B]. + * + * This method should never be wrapped in `try`/`catch` as it will not throw any unexpected errors, + * it will only result in [CancellationException], or fatal exceptions such as `OutOfMemoryError`. + */ +public suspend fun Effect.fold( + error: suspend (error: Throwable) -> B, + recover: suspend (raised: R) -> B, + transform: suspend (value: A) -> B, +): B { + contract { + callsInPlace(error, AT_MOST_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + return fold({ invoke() }, { error(it) }, { recover(it) }, { transform(it) }) +} + +public suspend fun Effect.fold( + recover: suspend (raised: R) -> B, + transform: suspend (value: A) -> B, +): B { + contract { + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + return fold({ throw it }, recover, transform) +} + +public inline fun EagerEffect.fold( + error: (error: Throwable) -> B, + recover: (raised: R) -> B, + transform: (value: A) -> B, +): B { + contract { + callsInPlace(error, AT_MOST_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + return fold({ invoke(this) }, error, recover, transform) +} + +public inline fun EagerEffect.fold(recover: (R) -> B, transform: (A) -> B): B { + contract { + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + return fold({ throw it }, recover, transform) +} + +@JvmName("_foldOrThrow") +public inline fun fold( + @BuilderInference program: Raise.() -> A, + recover: (raised: R) -> B, + transform: (value: A) -> B, +): B { + contract { + callsInPlace(program, EXACTLY_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + return fold(program, { throw it }, recover, transform) +} + +@JvmName("_fold") +public inline fun fold( + @BuilderInference program: Raise.() -> A, + error: (error: Throwable) -> B, + recover: (raised: R) -> B, + transform: (value: A) -> B, +): B { + contract { + callsInPlace(program, EXACTLY_ONCE) + callsInPlace(error, AT_MOST_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(transform, AT_MOST_ONCE) + } + val raise = DefaultRaise() + return try { + transform(program(raise)) + } catch (e: CancellationException) { + recover(e.raisedOrRethrow(raise)) + } catch (e: Throwable) { + error(e.nonFatalOrThrow()) + } +} + +/** Returns the raised value, rethrows the CancellationException if not our scope */ +@PublishedApi +internal fun CancellationException.raisedOrRethrow(raise: DefaultRaise): R = + if (this is RaiseCancellationException && this.raise === raise) _raised as R + else throw this + +/** Serves as both purposes of a scope-reference token, and a default implementation for Raise. */ +@PublishedApi +internal class DefaultRaise : Raise { + override fun raise(r: Any?): Nothing = throw RaiseCancellationException(r, this) +} + +/** CancellationException is required to cancel coroutines when raising from within them. */ +private class RaiseCancellationException(val _raised: Any?, val raise: Raise) : + CancellationException("Raised Continuation") diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Mappers.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Mappers.kt new file mode 100644 index 00000000000..ef4ebf6fc85 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Mappers.kt @@ -0,0 +1,50 @@ +@file:JvmMultifileClass +@file:JvmName("Effect") +package arrow.core.raise + +import arrow.core.Either +import arrow.core.Ior +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +import arrow.core.Validated +import arrow.core.identity +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + +/** Run the [Effect] by returning [Either.Right] of [A], or [Either.Left] of [E]. */ +public suspend fun Effect.toEither(): Either = either { invoke() } +public fun EagerEffect.toEither(): Either = either { invoke() } + +/** Run the [Effect] by returning [Validated.Valid] of [A], or [Validated.Invalid] of [E]. */ +public suspend fun Effect.toValidated(): Validated = fold({ Validated.Invalid(it) }) { Validated.Valid(it) } +public fun EagerEffect.toValidated(): Validated = fold({ Validated.Invalid(it) }) { Validated.Valid(it) } + +/** Run the [Effect] by returning [Ior.Right] of [A], or [Ior.Left] of [E]. */ +public suspend fun Effect.toIor(): Ior = fold({ Ior.Left(it) }) { Ior.Right(it) } +public fun EagerEffect.toIor(): Ior = fold({ Ior.Left(it) }) { Ior.Right(it) } + +/** Run the [Effect] by returning [A], or `null` if raised with [E]. */ +public suspend fun Effect.orNull(): A? = fold({ _: E -> null }) { it } +public fun EagerEffect.orNull(): A? = fold({ _: E -> null }) { it } + +/** Run the [Effect] by returning [Option] of [A], [orElse] run the fallback lambda and returning its result of [Option] of [A]. */ +public suspend fun Effect.toOption(orElse: suspend (E) -> Option): Option = fold(orElse) { Some(it) } +public fun EagerEffect.toOption(orElse: (E) -> Option): Option = fold(orElse) { Some(it) } + +/** Run the [Effect] by returning [Option] of [A], or [None] if raised with [None]. */ +public suspend fun Effect.toOption(): Option = option { invoke() } +public fun EagerEffect.toOption(): Option = option { invoke() } + +/** Run the [Effect] by returning [Result] of [A], [orElse] run the fallback lambda and returning its result of [Result] of [A]. */ +public suspend fun Effect.toResult(orElse: suspend (E) -> Result): Result = + fold({ orElse(it) }, { Result.success(it) }) +public fun EagerEffect.toResult(orElse: (E) -> Result): Result = + fold({ orElse(it) }, { Result.success(it) }) + +/** Run the [Effect] by returning [Result] of [A], or [Result.Failure] if raised with [Throwable]. */ +public suspend fun Effect.toResult(): Result = result { invoke() } +public fun EagerEffect.toResult(): Result = result { invoke() } + +public suspend fun Effect.merge(): A = fold(::identity, ::identity) +public fun EagerEffect.merge(): A = fold(::identity, ::identity) 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 new file mode 100644 index 00000000000..0f33154da34 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt @@ -0,0 +1,404 @@ +@file:OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class) + +package arrow.core.raise + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +import arrow.core.Validated +import arrow.core.continuations.EffectScope +import arrow.core.identity +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.InvocationKind.AT_MOST_ONCE +import kotlin.contracts.InvocationKind.EXACTLY_ONCE +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName + +@DslMarker +public annotation class RaiseDSL + +/** + * + * + * The [Raise] DSL allows you to work with _logical failures_ of type [R]. + * A _logical failure_ does not necessarily mean that the computation has failed, + * but that it has stopped or _short-circuited_. + * + * The [Raise] DSL allows you to [raise] _logical failure_ of type [R], and you can [recover] from them. + * + * + * ```kotlin + * fun Raise.failure(): Int = raise("failed") + * + * fun Raise.recovered(): Int = + * recover({ failure() }) { _: String -> 1 } + * ``` + * + * + * Above we defined a function `failure` that raises a logical failure of type [String] with value `"failed"`. + * And in the function `recovered` we recover from the failure by providing a fallback value, + * and resolving the error type [String] to [Nothing]. Meaning we can track that we recovered from the error in the type. + * + * Since we defined programs in terms of [Raise] they _seamlessly work with any of the builders_ available in Arrow, + * or any you might build for your custom types. + * + * + * ```kotlin + * suspend fun test() { + * val either: Either = + * either { failure() } + * + * val effect: Effect = + * effect { failure() } + * + * val ior: Ior = + * ior(Semigroup.string()) { failure() } + * + * either shouldBe Either.Left("failed") + * effect.toEither() shouldBe Either.Left("failed") + * ior shouldBe Ior.Left("failed") + * } + * ``` + * + * + * + * And we can apply the same technique to recover from the failures using the [Raise] DSL based error handlers available in Arrow. + * + * + * ```kotlin + * fun test() { + * val either = either { failure() } + * .recover { _: String -> recovered() } + * + * either shouldBe Either.Right(1) + * } + * ``` + * + * + */ +public interface Raise { + + /** Raise a _logical failure_ of type [R] */ + @RaiseDSL + public fun raise(r: R): Nothing + + @Deprecated("Use raise instead", ReplaceWith("raise(r)")) + public fun shift(r: R): B = raise(r) + + public suspend fun arrow.core.continuations.Effect.bind(): B = + fold({ raise(it) }, ::identity) + + // Added for source compatibility with EffectScope / EagerScope + public suspend fun arrow.core.continuations.EagerEffect.bind(): B = + fold({ raise(it) }, ::identity) + + @Deprecated( + "Use recover or effect & recover instead", + ReplaceWith("effect { f() }") + ) + public suspend fun attempt( + @BuilderInference + f: suspend EffectScope.() -> A, + ): arrow.core.continuations.Effect = arrow.core.continuations.effect(f) + + @Deprecated( + "Use recover or effect & recover instead", + ReplaceWith("this.recover { recover() }") + ) + public suspend infix fun arrow.core.continuations.Effect.catch( + recover: suspend Raise.(E) -> A, + ): A = fold({ recover(it) }, ::identity) + + /** + * Invoke an [EagerEffect] inside `this` [Raise] context. + * Any _logical failure_ is raised in `this` [Raise] context, + * and thus short-circuits the computation. + * + * @see [recover] if you want to attempt to recover from any _logical failure_. + */ + public operator fun EagerEffect.invoke(): A = invoke(this@Raise) + public fun EagerEffect.bind(): A = invoke(this@Raise) + + /** + * Invoke an [Effect] inside `this` [Raise] context. + * Any _logical failure_ raised are raised in `this` [Raise] context, + * and thus short-circuits the computation. + * + * @see [recover] if you want to attempt to recover from any _logical failure_. + */ + public suspend operator fun Effect.invoke(): A = invoke(this@Raise) + public suspend fun Effect.bind(): A = invoke(this@Raise) + + /** + * Extract the [Either.Right] value of an [Either]. + * Any encountered [Either.Left] will be raised as a _logical failure_ in `this` [Raise] context. + * You can wrap the [bind] call in [recover] if you want to attempt to recover from any _logical failure_. + * + * + * ```kotlin + * fun test() { + * val one: Either = 1.right() + * val left: Either = Either.Left("failed") + * + * either { + * val x = one.bind() + * val y = recover({ left.bind() }) { failure : String -> 1 } + * x + y + * } shouldBe Either.Right(2) + * } + * ``` + * + * + */ + public fun Either.bind(): A = when (this) { + is Either.Left -> raise(value) + is Either.Right -> value + } + + /* Will be removed in subsequent PRs for Arrow 2.x.x */ + public fun Validated.bind(): A = when (this) { + is Validated.Invalid -> raise(value) + is Validated.Valid -> value + } + + /** + * Extract the [Result.success] value out of [Result], + * because [Result] works with [Throwable] as its error type you need to [transform] [Throwable] to [R]. + * + * Note that this functions can currently not be _inline_ without Context Receivers, + * and thus doesn't allow suspension in its error handler. + * To do so, use [Result.recover] and [bind]. + * + * + * ```kotlin + * suspend fun test() { + * val one: Result = Result.success(1) + * val failure: Result = Result.failure(RuntimeException("Boom!")) + * + * either { + * val x = one.bind { -1 } + * val y = failure.bind { failure: Throwable -> + * raise("Something bad happened: ${failure.message}") + * } + * val z = failure.recover { failure: Throwable -> + * delay(10) + * 1 + * }.bind { raise("Something bad happened: ${it.message}") } + * x + y + z + * } shouldBe Either.Left("Something bad happened: Boom!") + * } + * ``` + * + * + */ + public fun Result.bind(transform: (Throwable) -> R): A = + fold(::identity) { throwable -> raise(transform(throwable)) } + + /** + * Extract the [Some] value out of [Option], + * because [Option] works with [None] as its error type you need to [transform] [None] to [R]. + * + * Note that this functions can currently not be _inline_ without Context Receivers, + * and thus doesn't allow suspension in its error handler. + * To do so, use [Option.recover] and [bind]. + * + * + * ```kotlin + * suspend fun test() { + * val empty: Option = None + * either { + * val x: Int = empty.bind { _: None -> 1 } + * val y: Int = empty.bind { _: None -> raise("Something bad happened: Boom!") } + * val z: Int = empty.recover { _: None -> + * delay(10) + * 1 + * }.bind { raise("Something bad happened: Boom!") } + * x + y + z + * } shouldBe Either.Left("Something bad happened: Boom!") + * } + * ``` + * + * + */ + public fun Option.bind(transform: Raise.(None) -> A): A = + when (this) { + None -> transform(None) + is Some -> value + } + + @RaiseDSL + public suspend infix fun Effect.recover(@BuilderInference resolve: suspend Raise.(E) -> A): A = + recover({ invoke() }) { resolve(it) } + + /** @see [recover] */ + @RaiseDSL + public infix fun EagerEffect.recover(@BuilderInference resolve: Raise.(E) -> A): A = + recover({ invoke() }, resolve) + + /** + * Execute the [Effect] resulting in [A], + * and recover from any _logical error_ of type [E], and [Throwable], by providing a fallback value of type [A], + * or raising a new error of type [R]. + * + * @see [catch] if you don't need to recover from [Throwable]. + */ + @RaiseDSL + public suspend fun Effect.recover( + @BuilderInference action: suspend Raise.() -> A, + @BuilderInference recover: suspend Raise.(E) -> A, + @BuilderInference catch: suspend Raise.(Throwable) -> A, + ): A = fold({ action(this) }, { catch(it) }, { recover(it) }, { it }) + + @RaiseDSL + public suspend fun Effect.catch( + @BuilderInference catch: suspend Raise.(Throwable) -> A, + ): A = fold({ catch(it) }, { raise(it) }, { it }) + + @RaiseDSL + public fun EagerEffect.catch( + @BuilderInference catch: Raise.(Throwable) -> A, + ): A = fold({ catch(it) }, { raise(it) }, { it }) +} + +/** + * Execute the [Raise] context function resulting in [A] or any _logical error_ of type [E], + * and recover by providing a fallback value of type [A] or raising a new error of type [R]. + * + * + * ```kotlin + * suspend fun test() { + * either { + * recover({ raise("failed") }) { str -> str.length } + * } shouldBe Either.Right(6) + * + * either { + * recover({ raise("failed") }) { str -> raise(-1) } + * } shouldBe Either.Left(-1) + * } + * ``` + * + * + */ +@RaiseDSL +public inline fun Raise.recover( + @BuilderInference action: Raise.() -> A, + @BuilderInference recover: Raise.(E) -> A, +): A { + contract { + callsInPlace(action, EXACTLY_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + } + return fold({ action(this) }, { throw it }, { recover(it) }, { it }) +} + +@RaiseDSL +public inline fun Raise.recover( + @BuilderInference action: Raise.() -> A, + @BuilderInference recover: Raise.(E) -> A, + @BuilderInference catch: Raise.(Throwable) -> A, +): A { + contract { + callsInPlace(action, EXACTLY_ONCE) + callsInPlace(recover, AT_MOST_ONCE) + callsInPlace(catch, AT_MOST_ONCE) + } + return fold({ action(this) }, { catch(it) }, { recover(it) }, { it }) +} + +@RaiseDSL +public inline fun Raise.catch( + @BuilderInference action: Raise.() -> A, + @BuilderInference catch: Raise.(Throwable) -> A, +): A { + contract { + callsInPlace(action, EXACTLY_ONCE) + callsInPlace(catch, AT_MOST_ONCE) + } + return fold({ action(this) }, { catch(it) }, { raise(it) }, { it }) +} + +@RaiseDSL +@JvmName("catchReified") +public inline fun Raise.catch( + @BuilderInference action: Raise.() -> A, + @BuilderInference catch: Raise.(T) -> A, +): A { + contract { + callsInPlace(action, EXACTLY_ONCE) + callsInPlace(catch, AT_MOST_ONCE) + } + return catch(action) { t: Throwable -> if (t is T) catch(t) else throw t } +} + +@RaiseDSL +public inline fun Raise.ensure(condition: Boolean, raise: () -> R): Unit { + contract { + callsInPlace(raise, AT_MOST_ONCE) + returns() implies condition + } + return if (condition) Unit else raise(raise()) +} + +@RaiseDSL +public inline fun Raise.ensureNotNull(value: B?, raise: () -> R): B { + contract { + callsInPlace(raise, AT_MOST_ONCE) + returns() implies (value != null) + } + return value ?: raise(raise()) +} diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/NullableSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/NullableSpec.kt index 4c89473b6ed..bf038e10e0c 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/NullableSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/NullableSpec.kt @@ -13,7 +13,7 @@ import io.kotest.property.checkAll class NullableSpec : StringSpec({ "ensure null in nullable computation" { checkAll(Arb.boolean(), Arb.int()) { predicate, i -> - nullable { + nullable.eager { ensure(predicate) i } shouldBe if (predicate) i else null diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-01.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-01.kt new file mode 100644 index 00000000000..b6d7af378af --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-01.kt @@ -0,0 +1,14 @@ +// This file was automatically generated from ErrorHandlers.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEffectError01 + +import arrow.core.raise.effect +import arrow.core.raise.recover + +object User +object Error + +val error = effect { raise(Error) } // Raise(error) + +val a = error.recover { error -> User } // Success(User) +val b = error.recover { error -> raise("other-failure") } // Raise(other-failure) +val c = error.recover { error -> throw RuntimeException("BOOM") } // Exception(BOOM) diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-02.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-02.kt new file mode 100644 index 00000000000..a6bab641af9 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-02.kt @@ -0,0 +1,14 @@ +// This file was automatically generated from ErrorHandlers.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEffectError02 + +import arrow.core.raise.effect +import arrow.core.raise.catch + +object User +object Error + +val exception = effect { throw RuntimeException("BOOM") } // Exception(BOOM) + +val a = exception.catch { error -> error.message?.length ?: -1 } // Success(5) +val b = exception.catch { raise(Error) } // Raise(error) +val c = exception.catch { throw RuntimeException("other-failure") } // Exception(other-failure) diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-03.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-03.kt new file mode 100644 index 00000000000..a3d574108af --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-error-03.kt @@ -0,0 +1,16 @@ +// This file was automatically generated from ErrorHandlers.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEffectError03 + +import arrow.core.raise.effect +import arrow.core.raise.catch + +object User +object Error + +val x = effect { + throw IllegalArgumentException("builder missed args") +}.catch { raise(Error) } + +val y = effect { + throw IllegalArgumentException("builder missed args") +}.catch { raise(Error) } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-55.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-55.kt new file mode 100644 index 00000000000..e2f63254f79 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-55.kt @@ -0,0 +1,12 @@ +// This file was automatically generated from Either.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEither55 + +import arrow.core.Either +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun test() { + val error: Either = Either.Left("error") + val fallback: Either = error.recover { it.length } + fallback shouldBe Either.Right(5) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-56.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-56.kt new file mode 100644 index 00000000000..9080fd10655 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-56.kt @@ -0,0 +1,12 @@ +// This file was automatically generated from Either.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEither56 + +import arrow.core.Either +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun test() { + val error: Either = Either.Left("error") + val listOfErrors: Either, Int> = error.recover { shift(it.toList()) } + listOfErrors shouldBe Either.Left(listOf('e', 'r', 'r', 'o', 'r')) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-57.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-57.kt new file mode 100644 index 00000000000..3f082ae8d3c --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-either-57.kt @@ -0,0 +1,21 @@ +// This file was automatically generated from Either.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleEither57 + +import arrow.core.Either +import arrow.core.catch +import io.kotest.assertions.throwables.shouldThrowUnit +import io.kotest.matchers.shouldBe + +fun test() { + val left: Either = Either.catch { throw RuntimeException("Boom!") } + + val caught: Either = left.catch { _: Throwable -> 1 } + val failure: Either = left.catch { _: Throwable -> shift("failure") } + + shouldThrowUnit { + val caught2: Either = left.catch { _: IllegalStateException -> 1 } + } + + caught shouldBe Either.Right(1) + failure shouldBe Either.Left("failure") +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt new file mode 100644 index 00000000000..dac69a1c753 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt @@ -0,0 +1,14 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption24 + +import arrow.core.Option +import arrow.core.none +import arrow.core.Some +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun test() { + val error: Option = none() + val fallback: Option = error.recover { 5 } + fallback shouldBe Some(5) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt new file mode 100644 index 00000000000..791cc3dda5c --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt @@ -0,0 +1,17 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption25 + +import arrow.core.Option +import arrow.core.none +import arrow.core.Some +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun test() { + val error: Option = none() + fun fallback(): Option = Some(5) + fun failure(): Option = none() + + error.recover { fallback().bind() } shouldBe Some(5) + error.recover { failure().bind() } shouldBe none() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-01.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-01.kt new file mode 100644 index 00000000000..655ca71b031 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-01.kt @@ -0,0 +1,18 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise01 + +import arrow.core.raise.Effect +import arrow.core.raise.effect +import arrow.core.raise.ensureNotNull +import arrow.core.raise.ensure + +object EmptyPath + +fun readFile(path: String): Effect = effect { + if (path.isEmpty()) raise(EmptyPath) else Unit +} + +fun readFile2(path: String?): Effect = effect { + ensureNotNull(path) { EmptyPath } + ensure(path.isNotEmpty()) { EmptyPath } +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-02.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-02.kt new file mode 100644 index 00000000000..7733e37b5a0 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-02.kt @@ -0,0 +1,55 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise02 + +import arrow.core.Either +import arrow.core.Ior +import arrow.core.None +import arrow.core.Validated +import arrow.core.raise.Effect +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.core.raise.toEither +import arrow.core.raise.toValidated +import arrow.core.raise.toIor +import arrow.core.raise.toOption +import arrow.core.raise.ensureNotNull +import arrow.core.raise.ensure +import io.kotest.matchers.collections.shouldNotBeEmpty +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf +import java.io.File +import java.io.FileNotFoundException + +@JvmInline +value class Content(val body: List) + +sealed interface FileError +@JvmInline value class SecurityError(val msg: String?) : FileError +@JvmInline value class FileNotFound(val path: String) : FileError +object EmptyPath : FileError { + override fun toString() = "EmptyPath" +} + +fun readFile(path: String?): Effect = effect { + ensureNotNull(path) { EmptyPath } + ensure(path.isNotEmpty()) { EmptyPath } + try { + val lines = File(path).readLines() + Content(lines) + } catch (e: FileNotFoundException) { + raise(FileNotFound(path)) + } catch (e: SecurityException) { + raise(SecurityError(e.message)) + } +} + +suspend fun main() { + readFile("").toEither() shouldBe Either.Left(EmptyPath) + readFile("knit.properties").toValidated() shouldBe Validated.Invalid(FileNotFound("knit.properties")) + readFile("gradle.properties").toIor() shouldBe Ior.Left(FileNotFound("gradle.properties")) + readFile("README.MD").toOption { None } shouldBe None + + readFile("build.gradle.kts").fold({ _: FileError -> null }, { it }) + .shouldBeInstanceOf() + .body.shouldNotBeEmpty() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-03.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-03.kt new file mode 100644 index 00000000000..d3d3f2b9b26 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-03.kt @@ -0,0 +1,16 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise03 + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +import arrow.core.raise.Effect +import arrow.core.raise.fold +import arrow.core.identity + +suspend fun Effect.toEither(): Either = + fold({ Either.Left(it) }) { Either.Right(it) } + +suspend fun Effect.toOption(): Option = + fold(::identity) { Some(it) } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-04.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-04.kt new file mode 100644 index 00000000000..6fa5fe86c21 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-04.kt @@ -0,0 +1,55 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise04 + +import arrow.core.raise.Effect +import arrow.core.raise.effect +import arrow.core.raise.recover +import arrow.core.raise.catch + +val failed: Effect = + effect { raise("failed") } + +val default: Effect = + failed.recover { -1 } + +val resolved: Effect = + failed.recover { it.length } + +val default2: Effect = default +val resolved2: Effect = resolved + +val newError: Effect, Int> = + failed.recover { str -> + raise(str.reversed().toList()) + } + +val newException: Effect = + failed.recover { str -> throw RuntimeException(str) } + +val foreign = effect { + throw RuntimeException("BOOM!") +} + +val default3: Effect = + foreign.catch { -1 } + +val resolved3: Effect = + foreign.catch { it.message?.length ?: -1 } + +val default4: Effect = + foreign + .recover { -1 } + .catch { -2 } + +val default5: Effect = + foreign + .catch { ex: RuntimeException -> -1 } + .catch { ex: java.sql.SQLException -> -2 } + +suspend fun java.sql.SQLException.isForeignKeyViolation(): Boolean = true + +val rethrown: Effect = + failed.catch { ex: java.sql.SQLException -> + if(ex.isForeignKeyViolation()) raise("foreign key violation") + else throw ex + } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-05.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-05.kt new file mode 100644 index 00000000000..1f0e3c079ab --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-05.kt @@ -0,0 +1,25 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise05 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.guaranteeCase +import arrow.fx.coroutines.parZip +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeTypeOf +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.awaitCancellation + +suspend fun awaitExitCase(exit: CompletableDeferred): A = + guaranteeCase(::awaitCancellation) { exitCase -> exit.complete(exitCase) } + + suspend fun main() { + val error = "Error" + val exit = CompletableDeferred() + effect { + parZip({ awaitExitCase(exit) }, { raise(error) }) { a: Int, b: Int -> a + b } + }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + exit.await().shouldBeTypeOf() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-06.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-06.kt new file mode 100644 index 00000000000..56f4bfaae96 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-06.kt @@ -0,0 +1,32 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise06 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.guaranteeCase +import arrow.fx.coroutines.parTraverse +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeTypeOf +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.awaitCancellation + +suspend fun awaitExitCase(exit: CompletableDeferred): A = + guaranteeCase(::awaitCancellation) { exitCase -> exit.complete(exitCase) } + +suspend fun CompletableDeferred.getOrNull(): A? = + if (isCompleted) await() else null + +suspend fun main() { + val error = "Error" + val exits = (0..3).map { CompletableDeferred() } + effect> { + (0..4).parTraverse { index -> + if (index == 4) raise(error) + else awaitExitCase(exits[index]) + } + }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) + // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran + exits.forEach { exit -> exit.getOrNull()?.shouldBeTypeOf() } +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-07.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-07.kt new file mode 100644 index 00000000000..4cfab8f778c --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-07.kt @@ -0,0 +1,31 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise07 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.core.merge +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.guaranteeCase +import arrow.fx.coroutines.raceN +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeTypeOf +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.awaitCancellation + +suspend fun awaitExitCase(exit: CompletableDeferred): A = + guaranteeCase(::awaitCancellation) { exitCase -> exit.complete(exitCase) } + +suspend fun CompletableDeferred.getOrNull(): A? = + if (isCompleted) await() else null + +suspend fun main() { + val error = "Error" + val exit = CompletableDeferred() + effect { + raceN({ awaitExitCase(exit) }) { raise(error) } + .merge() // Flatten Either result from race into Int + }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) + // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran + exit.getOrNull()?.shouldBeTypeOf() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-08.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-08.kt new file mode 100644 index 00000000000..7f52b2e77e1 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-08.kt @@ -0,0 +1,29 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise08 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.bracketCase +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeTypeOf +import kotlinx.coroutines.CompletableDeferred +import java.io.BufferedReader +import java.io.File + +suspend fun main() { + val error = "Error" + val exit = CompletableDeferred() + effect { + bracketCase( + acquire = { File("build.gradle.kts").bufferedReader() }, + use = { reader: BufferedReader -> raise(error) }, + release = { reader, exitCase -> + reader.close() + exit.complete(exitCase) + } + ) + }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + exit.await().shouldBeTypeOf() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-09.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-09.kt new file mode 100644 index 00000000000..9c10cee48f5 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-09.kt @@ -0,0 +1,34 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise09 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.ResourceScope +import arrow.fx.coroutines.autoCloseable +import arrow.fx.coroutines.resourceScope +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeTypeOf +import kotlinx.coroutines.CompletableDeferred +import java.io.BufferedReader +import java.io.File + +suspend fun main() { + val error = "Error" + val exit = CompletableDeferred() + + suspend fun ResourceScope.bufferedReader(path: String): BufferedReader = + autoCloseable { File(path).bufferedReader() }.also { + onRelease { exitCase -> exit.complete(exitCase) } + } + + resourceScope { + effect { + val reader = bufferedReader("build.gradle.kts") + raise(error) + reader.lineSequence().count() + }.fold({ it shouldBe error }, { fail("Int can never be the result") }) + } + exit.await().shouldBeTypeOf() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-10.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-10.kt new file mode 100644 index 00000000000..2b6cb033364 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-10.kt @@ -0,0 +1,59 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise10 + +import arrow.core.raise.Effect +import arrow.core.raise.effect +import arrow.core.raise.fold +import arrow.core.raise.ensureNotNull +import arrow.core.raise.ensure +import arrow.fx.coroutines.ExitCase +import arrow.fx.coroutines.guaranteeCase +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileNotFoundException + +@JvmInline +value class Content(val body: List) + +sealed interface FileError +@JvmInline value class SecurityError(val msg: String?) : FileError +@JvmInline value class FileNotFound(val path: String) : FileError +object EmptyPath : FileError { + override fun toString() = "EmptyPath" +} + +fun readFile(path: String?): Effect = effect { + ensureNotNull(path) { EmptyPath } + ensure(path.isNotEmpty()) { EmptyPath } + try { + val lines = File(path).readLines() + Content(lines) + } catch (e: FileNotFoundException) { + raise(FileNotFound(path)) + } catch (e: SecurityException) { + raise(SecurityError(e.message)) + } +} + +suspend fun awaitExitCase(exit: CompletableDeferred): A = + guaranteeCase(::awaitCancellation) { exitCase -> exit.complete(exitCase) } + +suspend fun main() { + val exit = CompletableDeferred() + effect { + withContext(Dispatchers.IO) { + val job = launch { awaitExitCase(exit) } + val content = readFile("failure").bind() + job.join() + content.body.size + } + }.fold({ e -> e shouldBe FileNotFound("failure") }, { fail("Int can never be the result") }) + exit.await().shouldBeInstanceOf() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-11.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-11.kt new file mode 100644 index 00000000000..977cdcbf0df --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-11.kt @@ -0,0 +1,21 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise11 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import io.kotest.assertions.fail +import io.kotest.matchers.collections.shouldBeIn +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope + +suspend fun main() { + val errorA = "ErrorA" + val errorB = "ErrorB" + coroutineScope { + effect { + val fa = async { raise(errorA) } + val fb = async { raise(errorB) } + fa.await() + fb.await() + }.fold({ error -> error shouldBeIn listOf(errorA, errorB) }, { fail("Int can never be the result") }) + } +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-12.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-12.kt new file mode 100644 index 00000000000..023cc118777 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-12.kt @@ -0,0 +1,22 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise12 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import io.kotest.assertions.fail +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +suspend fun main() { + val errorA = "ErrorA" + val errorB = "ErrorB" + val int = 45 + effect { + coroutineScope { + launch { raise(errorA) } + launch { raise(errorB) } + int + } + }.fold({ fail("Raise can never finish") }, { it shouldBe int }) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-13.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-13.kt new file mode 100644 index 00000000000..f60a06a4235 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-13.kt @@ -0,0 +1,25 @@ +// This file was automatically generated from Effect.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaise13 + +import arrow.core.raise.effect +import arrow.core.raise.fold +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope + +suspend fun main() { + + effect Unit> { + suspend { raise("error") } + }.fold({ }, { leakedRaise -> leakedRaise.invoke() }) + + val leakedAsync = coroutineScope Deferred> { + suspend { + async { + println("I am never going to run, until I get called invoked from outside") + } + } + } + + leakedAsync.invoke().await() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-01.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-01.kt new file mode 100644 index 00000000000..8ce9d79d137 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-01.kt @@ -0,0 +1,10 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl01 + +import arrow.core.raise.Raise +import arrow.core.raise.recover + +fun Raise.failure(): Int = raise("failed") + +fun Raise.recovered(): Int = + recover({ failure() }) { _: String -> 1 } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-02.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-02.kt new file mode 100644 index 00000000000..fd3c48ac2ad --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-02.kt @@ -0,0 +1,30 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl02 + +import arrow.core.Either +import arrow.core.Ior +import arrow.core.raise.Effect +import arrow.core.raise.Raise +import arrow.core.raise.either +import arrow.core.raise.effect +import arrow.core.raise.ior +import arrow.core.raise.toEither +import arrow.typeclasses.Semigroup +import io.kotest.matchers.shouldBe + +fun Raise.failure(): Int = raise("failed") + +suspend fun test() { + val either: Either = + either { failure() } + + val effect: Effect = + effect { failure() } + + val ior: Ior = + ior(Semigroup.string()) { failure() } + + either shouldBe Either.Left("failed") + effect.toEither() shouldBe Either.Left("failed") + ior shouldBe Ior.Left("failed") +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-03.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-03.kt new file mode 100644 index 00000000000..b899d1dc504 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-03.kt @@ -0,0 +1,20 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl03 + +import arrow.core.Either +import arrow.core.raise.Raise +import arrow.core.raise.either +import arrow.core.raise.recover +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun Raise.failure(): Int = raise("failed") + +fun Raise.recovered(): Int = recover({ failure() }) { _: String -> 1 } + +fun test() { + val either = either { failure() } + .recover { _: String -> recovered() } + + either shouldBe Either.Right(1) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-04.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-04.kt new file mode 100644 index 00000000000..d4787a5d48d --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-04.kt @@ -0,0 +1,19 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl04 + +import arrow.core.Either +import arrow.core.right +import arrow.core.raise.either +import arrow.core.raise.recover +import io.kotest.matchers.shouldBe + +fun test() { + val one: Either = 1.right() + val left: Either = Either.Left("failed") + + either { + val x = one.bind() + val y = recover({ left.bind() }) { failure : String -> 1 } + x + y + } shouldBe Either.Right(2) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-05.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-05.kt new file mode 100644 index 00000000000..bd7dd603842 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-05.kt @@ -0,0 +1,25 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl05 + +import arrow.core.Either +import arrow.core.raise.either +import arrow.core.raise.recover +import kotlinx.coroutines.delay +import io.kotest.matchers.shouldBe + +suspend fun test() { + val one: Result = Result.success(1) + val failure: Result = Result.failure(RuntimeException("Boom!")) + + either { + val x = one.bind { -1 } + val y = failure.bind { failure: Throwable -> + raise("Something bad happened: ${failure.message}") + } + val z = failure.recover { failure: Throwable -> + delay(10) + 1 + }.bind { raise("Something bad happened: ${it.message}") } + x + y + z + } shouldBe Either.Left("Something bad happened: Boom!") +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-06.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-06.kt new file mode 100644 index 00000000000..91b3169be00 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-06.kt @@ -0,0 +1,23 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl06 + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.recover +import arrow.core.raise.either +import kotlinx.coroutines.delay +import io.kotest.matchers.shouldBe + +suspend fun test() { + val empty: Option = None + either { + val x: Int = empty.bind { _: None -> 1 } + val y: Int = empty.bind { _: None -> raise("Something bad happened: Boom!") } + val z: Int = empty.recover { _: None -> + delay(10) + 1 + }.bind { raise("Something bad happened: Boom!") } + x + y + z + } shouldBe Either.Left("Something bad happened: Boom!") +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-07.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-07.kt new file mode 100644 index 00000000000..f1a29105f21 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-raise-dsl-07.kt @@ -0,0 +1,17 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleRaiseDsl07 + +import arrow.core.Either +import arrow.core.raise.either +import arrow.core.raise.recover +import io.kotest.matchers.shouldBe + +suspend fun test() { + either { + recover({ raise("failed") }) { str -> str.length } + } shouldBe Either.Right(6) + + either { + recover({ raise("failed") }) { str -> raise(-1) } + } shouldBe Either.Left(-1) +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/EitherKnitTest.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/EitherKnitTest.kt index 2f7c47e6987..3fbc6f9fe87 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/EitherKnitTest.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/EitherKnitTest.kt @@ -40,6 +40,18 @@ class EitherKnitTest : StringSpec({ arrow.core.examples.exampleEither51.test() } + "ExampleEither55" { + arrow.core.examples.exampleEither55.test() + } + + "ExampleEither56" { + arrow.core.examples.exampleEither56.test() + } + + "ExampleEither57" { + arrow.core.examples.exampleEither57.test() + } + }) { override fun timeout(): Long = 1000 } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt new file mode 100644 index 00000000000..6794020b59d --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt @@ -0,0 +1,17 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.test + +import io.kotest.core.spec.style.StringSpec + +class OptionKnitTest : StringSpec({ + "ExampleOption24" { + arrow.core.examples.exampleOption24.test() + } + + "ExampleOption25" { + arrow.core.examples.exampleOption25.test() + } + +}) { + override fun timeout(): Long = 1000 +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/RaiseKnitTest.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/RaiseKnitTest.kt new file mode 100644 index 00000000000..45cd92ebfa1 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/RaiseKnitTest.kt @@ -0,0 +1,33 @@ +// This file was automatically generated from Raise.kt by Knit tool. Do not edit. +package arrow.core.examples.test + +import io.kotest.core.spec.style.StringSpec + +class RaiseKnitTest : StringSpec({ + "ExampleRaiseDsl02" { + arrow.core.examples.exampleRaiseDsl02.test() + } + + "ExampleRaiseDsl03" { + arrow.core.examples.exampleRaiseDsl03.test() + } + + "ExampleRaiseDsl04" { + arrow.core.examples.exampleRaiseDsl04.test() + } + + "ExampleRaiseDsl05" { + arrow.core.examples.exampleRaiseDsl05.test() + } + + "ExampleRaiseDsl06" { + arrow.core.examples.exampleRaiseDsl06.test() + } + + "ExampleRaiseDsl07" { + arrow.core.examples.exampleRaiseDsl07.test() + } + +}) { + override fun timeout(): Long = 1000 +} 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 0b0d3c76173..d98842ebab0 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 @@ -561,9 +561,12 @@ public final class arrow/fx/coroutines/ScopedRaise : arrow/core/continuations/Ef 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 fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun ensure (ZLkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; + public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun shift (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; }