diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index a845e787fe7..fed348d74a4 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -57,6 +57,7 @@ public final class arrow/core/Const$Companion { } public final class arrow/core/ConstKt { + public static final field ConstDeprecation Ljava/lang/String; public static final fun combine (Larrow/core/Const;Larrow/typeclasses/Semigroup;Larrow/core/Const;)Larrow/core/Const; public static final fun compareTo (Larrow/core/Const;Larrow/core/Const;)I public static final fun const (Ljava/lang/Object;)Larrow/core/Const; @@ -283,6 +284,7 @@ public final class arrow/core/EitherKt { 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/core/Either;Lkotlin/jvm/functions/Function2;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; @@ -585,10 +587,13 @@ public final class arrow/core/IorKt { public static final fun bisequenceOption (Larrow/core/Ior;)Larrow/core/Option; public static final fun bisequenceValidated (Larrow/core/Ior;Larrow/typeclasses/Semigroup;)Larrow/core/Validated; public static final fun bothIor (Lkotlin/Pair;)Larrow/core/Ior; + public static final fun combine (Larrow/core/Ior;Larrow/core/Ior;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Larrow/core/Ior; public static final fun combine (Larrow/core/Ior;Larrow/typeclasses/Semigroup;Larrow/typeclasses/Semigroup;Larrow/core/Ior;)Larrow/core/Ior; public static final fun compareTo (Larrow/core/Ior;Larrow/core/Ior;)I public static final fun flatMap (Larrow/core/Ior;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; + public static final fun flatMap (Larrow/core/Ior;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; public static final fun flatten (Larrow/core/Ior;Larrow/typeclasses/Semigroup;)Larrow/core/Ior; + public static final fun flatten (Larrow/core/Ior;Lkotlin/jvm/functions/Function2;)Larrow/core/Ior; public static final synthetic fun getOrElse (Larrow/core/Ior;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun getOrElse (Larrow/core/Ior;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun leftIor (Ljava/lang/Object;)Larrow/core/Ior; @@ -658,6 +663,7 @@ public final class arrow/core/IterableKt { public static final fun rightPadZip (Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/List; public static final fun rightPadZip (Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun salign (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Ljava/lang/Iterable;)Ljava/lang/Iterable; + public static final fun salign (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Ljava/lang/Iterable;)Ljava/lang/Iterable; public static final fun separateEither (Ljava/lang/Iterable;)Lkotlin/Pair; public static final fun separateIor (Ljava/lang/Iterable;)Lkotlin/Pair; public static final fun separateValidated (Ljava/lang/Iterable;)Lkotlin/Pair; @@ -713,6 +719,7 @@ public final class arrow/core/MapKt { public static final fun align (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; public static final fun align (Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun combine (Ljava/util/Map;Larrow/typeclasses/Semigroup;Ljava/util/Map;)Ljava/util/Map; + public static final fun combine (Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function2;)Ljava/util/Map; public static final fun combineAll (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;)Ljava/util/Map; public static final fun filterMap (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun filterOption (Ljava/util/Map;)Ljava/util/Map; @@ -788,6 +795,7 @@ public final class arrow/core/NonEmptyList : kotlin/collections/AbstractList { public final fun plus (Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; public final fun plus (Ljava/lang/Object;)Larrow/core/NonEmptyList; public final fun plus (Ljava/util/List;)Larrow/core/NonEmptyList; + public final fun salign (Larrow/core/NonEmptyList;Lkotlin/jvm/functions/Function2;)Larrow/core/NonEmptyList; public final fun salign (Larrow/typeclasses/Semigroup;Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; public final fun toList ()Ljava/util/List; public fun toString ()Ljava/lang/String; @@ -981,6 +989,7 @@ public final class arrow/core/Option$Companion { } public final class arrow/core/OptionKt { + public static final fun combine (Larrow/core/Option;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Larrow/core/Option; public static final fun combine (Larrow/core/Option;Larrow/typeclasses/Semigroup;Larrow/core/Option;)Larrow/core/Option; public static final fun combineAll (Larrow/core/Option;Larrow/typeclasses/Monoid;)Ljava/lang/Object; public static final fun combineAll (Ljava/lang/Iterable;Larrow/typeclasses/Monoid;)Larrow/core/Option; @@ -1579,6 +1588,7 @@ public final class arrow/core/SequenceKt { public static final fun rightPadZip (Lkotlin/sequences/Sequence;Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; public static final fun rightPadZip (Lkotlin/sequences/Sequence;Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; public static final fun salign (Lkotlin/sequences/Sequence;Larrow/typeclasses/Semigroup;Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; + public static final fun salign (Lkotlin/sequences/Sequence;Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; public static final fun separateEither (Lkotlin/sequences/Sequence;)Lkotlin/Pair; public static final fun separateValidated (Lkotlin/sequences/Sequence;)Lkotlin/Pair; public static final fun sequence (Lkotlin/sequences/Sequence;)Larrow/core/Either; @@ -2877,6 +2887,7 @@ public final class arrow/core/continuations/FoldContinuation : arrow/core/contin public final class arrow/core/continuations/IorEagerEffectScope : arrow/core/continuations/EagerEffectScope, arrow/typeclasses/Semigroup { public fun (Larrow/typeclasses/Semigroup;Larrow/core/continuations/EagerEffectScope;)V + public fun append (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun bind (Larrow/core/Ior;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2897,6 +2908,7 @@ public final class arrow/core/continuations/IorEagerEffectScope : arrow/core/con public final class arrow/core/continuations/IorEffectScope : arrow/core/continuations/EffectScope, arrow/typeclasses/Semigroup { public fun (Larrow/typeclasses/Semigroup;Larrow/core/continuations/EffectScope;)V + public fun append (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/Either;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun bind (Larrow/core/Ior;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3246,8 +3258,8 @@ public final class arrow/core/raise/DefaultRaise : arrow/core/raise/Raise { public fun shift (Ljava/lang/Object;)Ljava/lang/Object; } -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 final class arrow/core/raise/IorRaise : arrow/core/raise/Raise { + public fun (Lkotlin/jvm/functions/Function2;Ljava/util/concurrent/atomic/AtomicReference;Larrow/core/raise/Raise;)V public fun attempt (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun bind (Larrow/core/Either;)Ljava/lang/Object; public final fun bind (Larrow/core/Ior;)Ljava/lang/Object; @@ -3259,11 +3271,8 @@ public final class arrow/core/raise/IorRaise : arrow/core/raise/Raise, arrow/typ 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/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -3465,7 +3474,7 @@ public final class arrow/core/raise/RaiseKt { public static final fun getOrElse (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun getOrNull (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun getOrNull (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 ior (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; public static final fun mapOrAccumulate (Larrow/core/raise/Raise;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun mapOrAccumulate (Larrow/core/raise/Raise;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun merge (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; @@ -3604,6 +3613,7 @@ public final class arrow/typeclasses/Monoid$Companion { } public final class arrow/typeclasses/Monoid$DefaultImpls { + public static fun append (Larrow/typeclasses/Monoid;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public static fun combineAll (Larrow/typeclasses/Monoid;Ljava/util/Collection;)Ljava/lang/Object; public static fun combineAll (Larrow/typeclasses/Monoid;Ljava/util/List;)Ljava/lang/Object; public static fun fold (Larrow/typeclasses/Monoid;Ljava/util/Collection;)Ljava/lang/Object; @@ -3612,6 +3622,10 @@ public final class arrow/typeclasses/Monoid$DefaultImpls { public static fun plus (Larrow/typeclasses/Monoid;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; } +public final class arrow/typeclasses/MonoidKt { + public static final field MonoidDeprecation Ljava/lang/String; +} + public abstract interface class arrow/typeclasses/Semigroup { public static final field Companion Larrow/typeclasses/Semigroup$Companion; public static fun Boolean ()Larrow/typeclasses/Semigroup; @@ -3619,6 +3633,7 @@ public abstract interface class arrow/typeclasses/Semigroup { public static fun Integer ()Larrow/typeclasses/Semigroup; public static fun Long ()Larrow/typeclasses/Semigroup; public static fun Short ()Larrow/typeclasses/Semigroup; + public abstract fun append (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public abstract fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public static fun constant (Larrow/typeclasses/Semigroup;)Larrow/typeclasses/Semigroup; public static fun either (Larrow/typeclasses/Semigroup;Larrow/typeclasses/Semigroup;)Larrow/typeclasses/Semigroup; @@ -3658,6 +3673,8 @@ public final class arrow/typeclasses/Semigroup$Companion { public final class arrow/typeclasses/Semigroup$Companion$NonEmptyListSemigroup : arrow/typeclasses/Semigroup { public static final field INSTANCE Larrow/typeclasses/Semigroup$Companion$NonEmptyListSemigroup; + public fun append (Larrow/core/NonEmptyList;Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; + public synthetic fun append (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun combine (Larrow/core/NonEmptyList;Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; public synthetic fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun maybeCombine (Larrow/core/NonEmptyList;Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; @@ -3667,10 +3684,16 @@ public final class arrow/typeclasses/Semigroup$Companion$NonEmptyListSemigroup : } public final class arrow/typeclasses/Semigroup$DefaultImpls { + public static fun append (Larrow/typeclasses/Semigroup;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public static fun maybeCombine (Larrow/typeclasses/Semigroup;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public static fun plus (Larrow/typeclasses/Semigroup;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; } +public final class arrow/typeclasses/SemigroupKt { + public static final field SemigroupDeprecation Ljava/lang/String; + public static final fun combine (Larrow/typeclasses/Semigroup;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +} + public abstract interface class arrow/typeclasses/Semiring { public static final field Companion Larrow/typeclasses/Semiring$Companion; public static fun Byte ()Larrow/typeclasses/Semiring; @@ -3704,5 +3727,6 @@ public final class arrow/typeclasses/Semiring$DefaultImpls { public final class arrow/typeclasses/SemiringKt { public static final field DoubleInstanceDeprecation Ljava/lang/String; public static final field FloatInstanceDeprecation Ljava/lang/String; + public static final field SemiringDeprecation Ljava/lang/String; } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Const.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Const.kt index 7dacd6d6809..1ea06bf172c 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Const.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Const.kt @@ -2,7 +2,10 @@ package arrow.core import arrow.typeclasses.Semigroup -@Deprecated("Const is deprecated in Arrow Core and will be removed in 2.x.x. \n If Const is crucial for you, please let us know on the Arrow Github. Thanks!\n" + " https://github.com/arrow-kt/arrow/issues\n") +public const val ConstDeprecation: String = + "Const is deprecated in Arrow Core and will be removed in 2.x.x. \n If Const is crucial for you, please let us know on the Arrow Github. Thanks!\n" + " https://github.com/arrow-kt/arrow/issues\n" + +@Deprecated(ConstDeprecation) public data class Const(private val value: A) { @Suppress("UNCHECKED_CAST") 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 198cfef509f..25d5f24f21c 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 @@ -6,15 +6,15 @@ import arrow.core.Either.Companion.resolve import arrow.core.Either.Left import arrow.core.Either.Right import arrow.core.Either.Right.Companion.unit -import arrow.core.computations.ResultEffect.bind -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.MonoidDeprecation import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -907,10 +907,10 @@ public sealed class Either { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("fold({ MN.empty() }) { b -> MN.run { MN.empty().combine(f(b)) } }") + ReplaceWith(" fold({ MN.empty() }, f)") ) public fun foldMap(MN: Monoid, f: (B) -> C): C = - fold({ MN.empty() }) { b -> MN.run { MN.empty().combine(f(b)) } } + fold({ MN.empty() }, f) @Deprecated( NicheAPI + "Prefer when or fold instead", @@ -921,10 +921,10 @@ public sealed class Either { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("MN.run { fold({ empty().combine(f(it)) }, { empty().combine(g(it)) }) }") + ReplaceWith("fold(f, g)") ) public inline fun bifoldMap(MN: Monoid, f: (A) -> C, g: (B) -> C): C = - MN.run { fold({ empty().combine(f(it)) }, { empty().combine(g(it)) }) } + fold(f, g) /** * Swap the generic parameters [A] and [B] of this [Either]. @@ -2292,19 +2292,43 @@ public operator fun , B : Comparable> Either.compareT { b1 -> other.fold({ 1 }, { b2 -> b1.compareTo(b2) }) } ) +/** + * Combine two [Either] values. + * If both are [Right] then combine both [B] values using [combineRight] or if both are [Left] then combine both [A] values using [combineLeft], + * otherwise it returns the `this` or fallbacks to [other] in case `this` is [Left]. + */ +public fun Either.combine(other: Either, combineLeft: (A, A) -> A, combineRight: (B, B) -> B): Either = + when (val one = this) { + is Left -> when (other) { + is Left -> Left(combineLeft(one.value, other.value)) + is Right -> one + } + + is Right -> when (other) { + is Left -> other + is Right -> Right(combineRight(one.value, other.value)) + } + } + @Deprecated( - RedundantAPI + "Prefer zipOrAccumulate", - ReplaceWith("Either.zipOrAccumulate({ a, bb -> SGA.run { a.combine(bb) } }, this, b) { a, bb -> SGB.run { a.combine(bb) } }") + SemigroupDeprecation, + ReplaceWith( + "combine(b, SGA::combine, SGB::combine)", + "arrow.typeclasses.combine" + ) ) public fun Either.combine(SGA: Semigroup, SGB: Semigroup, b: Either): Either = - Either.zipOrAccumulate({ a, bb -> SGA.run { a.combine(bb) } }, this, b) { a, bb -> SGB.run { a.combine(bb) } } + combine(b, SGA::combine, SGB::combine) @Deprecated( - RedundantAPI + "Prefer explicit fold instead", - ReplaceWith("fold(Monoid.either(MA, MB))", "arrow.core.fold", "arrow.typeclasses.Monoid") + MonoidDeprecation, + ReplaceWith( + "fold, Either>(MB.empty().right()) { x, y -> Either.zipOrAccumulate(MA::combine, x, y, MB::combine) }", + "arrow.typeclasses.combine" + ) ) public fun Iterable>.combineAll(MA: Monoid, MB: Monoid): Either = - fold(Monoid.either(MA, MB)) + fold, Either>(MB.empty().right()) { x, y -> Either.zipOrAccumulate(MA::combine, x, y, MB::combine) } /** * Given [B] is a sub type of [C], re-type this value from Either to Either @@ -2510,10 +2534,13 @@ public inline fun Either.zip( @Deprecated( NicheAPI + "Prefer using the Either DSL, or map", - ReplaceWith("if (n <= 0) Right(MB.empty()) else map { b -> List(n) { b }.fold(MB) }") + ReplaceWith( + "map { b -> List(n) { b }.fold(MB.empty(), MB::combine) }", + "arrow.typeclasses.combine" + ) ) public fun Either.replicate(n: Int, MB: Monoid): Either = - if (n <= 0) Right(MB.empty()) else map { b -> List(n) { b }.fold(MB) } + map { b -> List(n) { b }.fold(MB.empty(), MB::combine) } @Deprecated( RedundantAPI + "Prefer if-else statement inside either DSL, or replace with explicit flatMap", diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Endo.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Endo.kt index 7530906e9c2..89df2d31f24 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Endo.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Endo.kt @@ -3,6 +3,7 @@ package arrow.core /** * The monoid of endomorphisms under composition. */ +@Deprecated("Semigroup, and Monoid are being deprecated. Use regular function composition instead.") public data class Endo(val f: (A) -> A) { public fun combine(g: Endo): Endo = diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Ior.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Ior.kt index e7509c72747..8db72a25126 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Ior.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Ior.kt @@ -1,4 +1,5 @@ @file:OptIn(ExperimentalContracts::class) + package arrow.core import arrow.core.Ior.Both @@ -10,6 +11,8 @@ import arrow.core.raise.nullable import arrow.core.raise.option import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -77,7 +80,7 @@ public sealed class Ior { * Ior.Both("venus", "fly-trap").isLeft // Result: false * } * ``` - * + * */ @Deprecated( RedundantAPI + "Use isLeft()", @@ -98,7 +101,7 @@ public sealed class Ior { * Ior.Both("venus", "fly-trap").isBoth // Result: true * } * ``` - * + * */ @Deprecated( @@ -114,7 +117,7 @@ public sealed class Ior { contract { returns(true) implies (this@Ior is Ior.Left) returns(false) implies (this@Ior is Ior.Right) - returns(false) implies (this@Ior is Ior.Both) + returns(false) implies (this@Ior is Ior.Both) } return this@Ior is Ior.Left } @@ -125,7 +128,7 @@ public sealed class Ior { contract { returns(true) implies (this@Ior is Ior.Right) returns(false) implies (this@Ior is Ior.Left) - returns(false) implies (this@Ior is Ior.Both) + returns(false) implies (this@Ior is Ior.Both) } return this@Ior is Ior.Right } @@ -136,7 +139,7 @@ public sealed class Ior { contract { returns(false) implies (this@Ior is Ior.Right) returns(false) implies (this@Ior is Ior.Left) - returns(true) implies (this@Ior is Ior.Both) + returns(true) implies (this@Ior is Ior.Both) } return this@Ior is Ior.Both } @@ -159,6 +162,7 @@ public sealed class Ior { true -> Both(a, b) false -> Left(a) } + false -> when (b != null) { true -> Right(b) false -> null @@ -189,14 +193,16 @@ public sealed class Ior { * ``` */ @JvmStatic - @Deprecated(RedundantAPI + "Prefer explicitly creating lambdas", + @Deprecated( + RedundantAPI + "Prefer explicitly creating lambdas", ReplaceWith("{ it.map(f) }") ) public fun lift(f: (B) -> C): (Ior) -> Ior = { it.map(f) } @JvmStatic - @Deprecated(RedundantAPI + "Prefer explicitly creating lambdas", + @Deprecated( + RedundantAPI + "Prefer explicitly creating lambdas", ReplaceWith("{ it.map(fb).mapLeft(fa) }") ) public fun lift(fa: (A) -> C, fb: (B) -> D): (Ior) -> Ior = @@ -267,7 +273,7 @@ public sealed class Ior { callsInPlace(g, InvocationKind.AT_MOST_ONCE) } return MN.run { - fold({ f(it) },{ g(it) },{ a,b -> f(a).combine(g(b)) }) + fold({ f(it) }, { g(it) }, { a, b -> f(a).combine(g(b)) }) } } @@ -284,7 +290,7 @@ public sealed class Ior { * Ior.Both(12, "power").map { "flower $it" } // Result: Both(12, "flower power") * } * ``` - * + * */ public inline fun map(f: (B) -> D): Ior { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } @@ -309,7 +315,7 @@ public sealed class Ior { * Ior.Both(12, "power").bimap ({ it * 2 }, { b -> "flower $b" }) // Result: Both("flower power", 24) * } * ``` - * + * */ @Deprecated( NicheAPI + "Prefer using the Either DSL, or map + mapLeft", @@ -361,7 +367,7 @@ public sealed class Ior { * Ior.Both("left", "right").swap() // Result: Both("right", "left") * } * ``` - * + * */ public fun swap(): Ior = fold( { Right(it) }, @@ -395,7 +401,7 @@ public sealed class Ior { * println("both = $both") * } * ``` - * + * */ @Deprecated( "padNull is being renamed to toPair to be more consistent with the Kotlin Standard Library naming", @@ -429,7 +435,7 @@ public sealed class Ior { * Ior.Both("power", 12).toEither() // Result: Either.Right(12) * } * ``` - * + * */ public fun toEither(): Either = fold({ Either.Left(it) }, { Either.Right(it) }, { _, b -> Either.Right(b) }) @@ -452,7 +458,7 @@ public sealed class Ior { * println("both = $both") * } * ``` - * + * */ @Deprecated( "orNull is being renamed to getOrNull to be more consistent with the Kotlin Standard Library naming", @@ -491,7 +497,7 @@ public sealed class Ior { * println("both = $both") * } * ``` - * + * */ public fun leftOrNull(): A? { contract { @@ -515,14 +521,16 @@ public sealed class Ior { * Ior.Both(12, "power").toValidated() // Result: Valid("power") * } * ``` - * + * */ @Deprecated( NicheAPI + "Prefer using fold", - ReplaceWith("this.fold({ Invalid(it) }, { Valid(it) }, { _, b -> Valid(b) })", + ReplaceWith( + "this.fold({ Invalid(it) }, { Valid(it) }, { _, b -> Valid(b) })", "arrow.core.Validated", "arrow.core.Valid", - "arrow.core.Invalid") + "arrow.core.Invalid" + ) ) public fun toValidated(): Validated = fold({ Invalid(it) }, { Valid(it) }, { _, b -> Valid(b) }) @@ -567,10 +575,12 @@ public sealed class Ior { @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> fa(a).map { it.leftIor() } }, { b -> fb(b).map { it.rightIor() } },{ a, b -> fa(a).align(fb(b)) })", + ReplaceWith( + "fold({ a -> fa(a).map { it.leftIor() } }, { b -> fb(b).map { it.rightIor() } },{ a, b -> fa(a).align(fb(b)) })", "arrow.core.leftIor", "arrow.core.rightIor", - "arrow.core.align") + "arrow.core.align" + ) ) public inline fun bicrosswalk( fa: (A) -> Iterable, @@ -584,10 +594,12 @@ public sealed class Ior { @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("this.fold>( { a -> fa(a).mapValues { it.value.leftIor() } },{ b -> fb(b).mapValues { it.value.rightIor() } },{ a, b -> fa(a).align(fb(b)) })", + ReplaceWith( + "this.fold>( { a -> fa(a).mapValues { it.value.leftIor() } },{ b -> fb(b).mapValues { it.value.rightIor() } },{ a, b -> fa(a).align(fb(b)) })", "arrow.core.leftIor", "arrow.core.rightIor", - "arrow.core.align") + "arrow.core.align" + ) ) public inline fun bicrosswalkMap( fa: (A) -> Map, @@ -615,8 +627,10 @@ public sealed class Ior { @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> fa(a).zip(fb(b)) { aa, c -> Ior.Both(aa, c) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> fa(a).zip(fb(b)) { aa, c -> Ior.Both(aa, c) } })", + "arrow.core.Ior" + ) ) public inline fun bitraverse(fa: (A) -> Iterable, fb: (B) -> Iterable): List> = fold( @@ -628,9 +642,11 @@ public sealed class Ior { @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> either { Ior.Both(fa(a).bind(), fb(b).bind())} })", + ReplaceWith( + "fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> either { Ior.Both(fa(a).bind(), fb(b).bind())} })", "arrow.core.Ior", - "arrow.core.raise.either") + "arrow.core.raise.either" + ) ) public inline fun bitraverseEither( fa: (A) -> Either, @@ -639,14 +655,16 @@ public sealed class Ior { fold( { a -> fa(a).map { Left(it) } }, { b -> fb(b).map { Right(it) } }, - { a, b -> either { Both(fa(a).bind(), fb(b).bind())} } + { a, b -> either { Both(fa(a).bind(), fb(b).bind()) } } ) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> option { Ior.Both(fa(a).bind(), fb(b).bind())} })", + ReplaceWith( + "fold({ a -> fa(a).map { Ior.Left(it) } },{ b -> fb(b).map { Ior.Right(it) } },{ a, b -> option { Ior.Both(fa(a).bind(), fb(b).bind())} })", "arrow.core.Ior", - "arrow.core.raise.option") + "arrow.core.raise.option" + ) ) public inline fun bitraverseOption( fa: (A) -> Option, @@ -655,13 +673,15 @@ public sealed class Ior { fold( { a -> fa(a).map { Left(it) } }, { b -> fb(b).map { Right(it) } }, - { a, b -> option { Both(fa(a).bind(), fb(b).bind())} } + { a, b -> option { Both(fa(a).bind(), fb(b).bind()) } } ) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> fa(a)?.let { Ior.Left(it) } },{ b -> fb(b)?.let { Ior.Right(it) } }, { a, b -> nullable { Ior.Both( fa(a).bind(), fb(b).bind()) } })", - "arrow.core.Ior", "arrow.core.raise.nullable") + ReplaceWith( + "fold({ a -> fa(a)?.let { Ior.Left(it) } },{ b -> fb(b)?.let { Ior.Right(it) } }, { a, b -> nullable { Ior.Both( fa(a).bind(), fb(b).bind()) } })", + "arrow.core.Ior", "arrow.core.raise.nullable" + ) ) public inline fun bitraverseNullable( fa: (A) -> C?, @@ -670,15 +690,17 @@ public sealed class Ior { fold( { a -> fa(a)?.let { Left(it) } }, { b -> fb(b)?.let { Right(it) } }, - { a, b -> nullable{ Both( fa(a).bind(), fb(b).bind()) } } + { a, b -> nullable { Both(fa(a).bind(), fb(b).bind()) } } ) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("this.fold({ a -> fa(a).map { Ior.Left(it) } }, { b -> fb(b).map { Ior.Right(it) } }, { a, b -> fa(a).zip(SA, fb(b)) { aa, c -> Ior.Both(aa, c) } })", - "arrow.core.Ior") + ReplaceWith( + "this.fold({ a -> fa(a).map { Ior.Left(it) } }, { b -> fb(b).map { Ior.Right(it) } }, { a, b -> fa(a).zip(SA, fb(b)) { aa, c -> Ior.Both(aa, c) } })", + "arrow.core.Ior" + ) ) -public inline fun bitraverseValidated( + public inline fun bitraverseValidated( SA: Semigroup, fa: (A) -> Validated, fb: (B) -> Validated @@ -691,8 +713,10 @@ public inline fun bitraverseValidated( @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ emptyList() },{ b -> fa(b).map { Ior.Right(it) } },{ a, b -> fa(b).map { Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ emptyList() },{ b -> fa(b).map { Ior.Right(it) } },{ a, b -> fa(b).map { Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public inline fun crosswalk(fa: (B) -> Iterable): List> = fold( @@ -703,8 +727,10 @@ public inline fun bitraverseValidated( @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ emptyMap() },{ b -> fa(b).mapValues { Ior.Right(it.value)} },{ a, b -> fa(b).mapValues { Ior.Both(a, it.value) })", - "arrow.core.Ior") + ReplaceWith( + "fold({ emptyMap() },{ b -> fa(b).mapValues { Ior.Right(it.value)} },{ a, b -> fa(b).mapValues { Ior.Both(a, it.value) })", + "arrow.core.Ior" + ) ) public inline fun crosswalkMap(fa: (B) -> Map): Map> = fold( @@ -715,8 +741,10 @@ public inline fun bitraverseValidated( @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Ior.Left(a) },{ b -> fa(b)?.let { Ior.Right(it) } },{ a, b -> fa(b)?.let { Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> Ior.Left(a) },{ b -> fa(b)?.let { Ior.Right(it) } },{ a, b -> fa(b)?.let { Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public inline fun crosswalkNull(ior: Ior, fa: (B) -> C?): Ior? = ior.fold( @@ -750,7 +778,7 @@ public inline fun bitraverseValidated( * left.exists { it > 10 } // Result: false * } * ``` - * + * */ @Deprecated( NicheAPI + "Prefer using fold, or map + getOrElse", @@ -848,7 +876,6 @@ public inline fun bitraverseValidated( } - @Deprecated( NicheAPI + "Prefer using isLeft", ReplaceWith("isLeft()") @@ -875,8 +902,10 @@ public inline fun bitraverseValidated( @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> listOf(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> listOf(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -892,15 +921,17 @@ public inline fun bitraverseValidated( @Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) public inline fun traverseEither(fa: (B) -> Either): Either> = fold( - { a -> Either.Right(Left(a)) }, - { b -> fa(b).map { Right(it) } }, - { a, b -> fa(b).map { Both(a, it) } }) + { a -> Either.Right(Left(a)) }, + { b -> fa(b).map { Right(it) } }, + { a, b -> fa(b).map { Both(a, it) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Either.Right(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", + ReplaceWith( + "fold({ a -> Either.Right(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", "arrow.core.Either", - "arrow.core.Ior") + "arrow.core.Ior" + ) ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -915,9 +946,11 @@ public inline fun bitraverseValidated( @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Some(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", + ReplaceWith( + "fold({ a -> Some(Ior.Left(a)) }, { b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", "arrow.core.Ior", - "arrow.core.Some") + "arrow.core.Some" + ) ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -933,14 +966,16 @@ public inline fun bitraverseValidated( @Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) public inline fun traverseOption(fa: (B) -> Option): Option> = fold( - { a -> Some(Left(a)) }, - { b -> fa(b).map { Right(it) } }, - { a, b -> fa(b).map { Both(a, it) } }) + { a -> Some(Left(a)) }, + { b -> fa(b).map { Right(it) } }, + { a, b -> fa(b).map { Both(a, it) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Ior.Left(a) }, {b -> fa(b)?.let { Ior.Right(it) } }, { a, b -> fa(b)?.let { Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> Ior.Left(a) }, {b -> fa(b)?.let { Ior.Right(it) } }, { a, b -> fa(b)?.let { Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public inline fun traverseNullable(fa: (B) -> C?): Ior? { contract { callsInPlace(fa, InvocationKind.AT_MOST_ONCE) } @@ -955,9 +990,12 @@ public inline fun bitraverseValidated( @OverloadResolutionByLambdaReturnType @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Valid(Ior.Left(a)) }, {b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", - "arrow.core.Ior") - )public inline fun traverse(fa: (B) -> Validated): Validated> { + ReplaceWith( + "fold({ a -> Valid(Ior.Left(a)) }, {b -> fa(b).map { Ior.Right(it) } }, { a, b -> fa(b).map { Ior.Both(a, it) } })", + "arrow.core.Ior" + ) + ) + public inline fun traverse(fa: (B) -> Validated): Validated> { contract { callsInPlace(fa, InvocationKind.AT_MOST_ONCE) } return fold( { a -> Valid(Left(a)) }, @@ -969,9 +1007,9 @@ public inline fun bitraverseValidated( @Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) public inline fun traverseValidated(fa: (B) -> Validated): Validated> = fold( - { a -> Valid(Left(a)) }, - { b -> fa(b).map { Right(it) } }, - { a, b -> fa(b).map { Both(a, it) } }) + { a -> Valid(Left(a)) }, + { b -> fa(b).map { Right(it) } }, + { a, b -> fa(b).map { Both(a, it) } }) @Deprecated( NicheAPI + "Prefer using map", @@ -980,22 +1018,27 @@ public inline fun bitraverseValidated( public fun void(): Ior = map { } } +@Deprecated( + "$SemigroupDeprecation.", + ReplaceWith("flatMap(SA::combine, f)", "arrow.typeclasses.combine") +) +public inline fun Ior.flatMap(SG: Semigroup, f: (B) -> Ior): Ior = + flatMap(SG::combine, f) + /** * Binds the given function across [Ior.Right]. * * @param f The function to bind across [Ior.Right]. */ -public inline fun Ior.flatMap(SG: Semigroup, f: (B) -> Ior): Ior = +public inline fun Ior.flatMap(combine: (A, A) -> A, f: (B) -> Ior): Ior = when (this) { is Left -> this is Right -> f(value) - is Both -> with(SG) { - f(this@flatMap.rightValue).fold( - { a -> Left(this@flatMap.leftValue.combine(a)) }, - { d -> Both(this@flatMap.leftValue, d) }, - { ll, rr -> Both(this@flatMap.leftValue.combine(ll), rr) } - ) - } + is Both -> f(rightValue).fold( + { a -> Left(combine(leftValue, a)) }, + { d -> Both(leftValue, d) }, + { ll, rr -> Both(combine(leftValue, ll), rr) } + ) } @Deprecated( @@ -1003,12 +1046,12 @@ public inline fun Ior.flatMap(SG: Semigroup, f: (B) -> Ior Ior.getOrElse(default: () -> B): B { - contract {callsInPlace(default, InvocationKind.AT_MOST_ONCE) } + contract { callsInPlace(default, InvocationKind.AT_MOST_ONCE) } return fold({ default() }, ::identity, { _, b -> b }) } public inline fun Ior.getOrElse(default: (A) -> B): B { - contract {callsInPlace(default, InvocationKind.AT_MOST_ONCE) } + contract { callsInPlace(default, InvocationKind.AT_MOST_ONCE) } return fold(default, ::identity) { _, b -> b } } @@ -1021,112 +1064,138 @@ public fun A.rightIor(): Ior = Ior.Right(this) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> a.zip(b) { aa, c -> Ior.Both(aa, c) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> a.zip(b) { aa, c -> Ior.Both(aa, c) } })", + "arrow.core.Ior" + ) ) public fun Ior, Iterable>.bisequence(): List> = - fold({a -> a.map { Left(it) } }, - { b -> b.map{ Right(it) } }, - { a, b -> a.zip(b) { aa, c -> Both(aa, c) } }) + fold({ a -> a.map { Left(it) } }, + { b -> b.map { Right(it) } }, + { a, b -> a.zip(b) { aa, c -> Both(aa, c) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> either { Ior.Both(a.bind(), b.bind()) } })", + ReplaceWith( + "fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> either { Ior.Both(a.bind(), b.bind()) } })", "arrow.core.Ior", - "arrow.core.raise.either") + "arrow.core.raise.either" + ) ) public fun Ior, Either>.bisequenceEither(): Either> = - fold({ a -> a.map{ Left(it) } }, - { b -> b.map{ Right(it) } }, - { a, b -> either { Both(a.bind(), b.bind()) } }) + fold({ a -> a.map { Left(it) } }, + { b -> b.map { Right(it) } }, + { a, b -> either { Both(a.bind(), b.bind()) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> option { Both(a.bind(), b.bind()) } })", + ReplaceWith( + "fold({ a -> a.map { Ior.Left(it) } }, {b -> b.map{ Ior.Right(it) } }, { a, b -> option { Both(a.bind(), b.bind()) } })", "arrow.core.Ior", - "arrow.core.raise.option") + "arrow.core.raise.option" + ) ) public fun Ior, Option>.bisequenceOption(): Option> = - fold({ a -> a.map{ Left(it) } }, - { b -> b.map{ Right(it) } }, - { a, b -> option { Both(a.bind(), b.bind()) } }) + fold({ a -> a.map { Left(it) } }, + { b -> b.map { Right(it) } }, + { a, b -> option { Both(a.bind(), b.bind()) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> a?.let{ Ior.Left(it) } }, {b -> b?.let{ Ior.Right(it) } }, { a, b -> nullable { Ior.Both(a.bind(), b.bind()) } })", + ReplaceWith( + "fold({ a -> a?.let{ Ior.Left(it) } }, {b -> b?.let{ Ior.Right(it) } }, { a, b -> nullable { Ior.Both(a.bind(), b.bind()) } })", "arrow.core.Ior", - "arrow.core.raise.nullable") + "arrow.core.raise.nullable" + ) ) public fun Ior.bisequenceNullable(): Ior? = fold( - { a -> a?.let{ Left(it) } }, - { b -> b?.let{ Right(it) } }, - { a, b -> nullable { Both(a.bind(), b.bind()) } }) + { a -> a?.let { Left(it) } }, + { b -> b?.let { Right(it) } }, + { a, b -> nullable { Both(a.bind(), b.bind()) } }) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("this.fold({ a -> fa(a).map { Ior.Left(it) } }, { b -> fb(b).map { Ior.Right(it) } }, { a, b -> fa(a).zip(SA, fb(b)) { aa, c -> Ior.Both(aa, c) } })", - "arrow.core.Ior") + ReplaceWith( + "this.fold({ a -> fa(a).map { Ior.Left(it) } }, { b -> fb(b).map { Ior.Right(it) } }, { a, b -> fa(a).zip(SA, fb(b)) { aa, c -> Ior.Both(aa, c) } })", + "arrow.core.Ior" + ) ) public fun Ior, Validated>.bisequenceValidated(SA: Semigroup): Validated> = bitraverseValidated(SA, ::identity, ::identity) +@Deprecated( + "$SemigroupDeprecation", + ReplaceWith("combine(other, SA::combine, SB::combine)", "arrow.typeclasses.combine") +) public fun Ior.combine(SA: Semigroup, SB: Semigroup, other: Ior): Ior = - with(SA) { - with(SB) { - when (val a = this@combine) { - is Ior.Left -> when (other) { - is Ior.Left -> Ior.Left(a.value + other.value) - is Ior.Right -> Ior.Both(a.value, other.value) - is Ior.Both -> Ior.Both(a.value + other.leftValue, other.rightValue) - } - is Ior.Right -> when (other) { - is Ior.Left -> Ior.Both(other.value, a.value) - is Ior.Right -> Ior.Right(a.value + other.value) - is Ior.Both -> Ior.Both(other.leftValue, a.value + other.rightValue) - } - is Ior.Both -> when (other) { - is Ior.Left -> Ior.Both(a.leftValue + other.value, a.rightValue) - is Ior.Right -> Ior.Both(a.leftValue, a.rightValue + other.value) - is Ior.Both -> Ior.Both(a.leftValue + other.leftValue, a.rightValue + other.rightValue) - } - } + combine(other, SA::combine, SB::combine) + +public fun Ior.combine(other: Ior, combineA: (A, A) -> A, combineB: (B, B) -> B): Ior = + when (this) { + is Ior.Left -> when (other) { + is Ior.Left -> Ior.Left(combineA(value, other.value)) + is Ior.Right -> Ior.Both(value, other.value) + is Ior.Both -> Ior.Both(combineA(value, other.leftValue), other.rightValue) + } + + is Ior.Right -> when (other) { + is Ior.Left -> Ior.Both(other.value, value) + is Ior.Right -> Ior.Right(combineB(value, other.value)) + is Ior.Both -> Ior.Both(other.leftValue, combineB(value, other.rightValue)) + } + + is Ior.Both -> when (other) { + is Ior.Left -> Ior.Both(combineA(leftValue, other.value), rightValue) + is Ior.Right -> Ior.Both(leftValue, combineB(rightValue, other.value)) + is Ior.Both -> Ior.Both(combineA(leftValue, other.leftValue), combineB(rightValue, other.rightValue)) } } +public inline fun Ior>.flatten(combine: (A, A) -> A): Ior = + flatMap(combine, ::identity) + @Suppress("NOTHING_TO_INLINE") +@Deprecated( + "$SemigroupDeprecation.", + ReplaceWith("flatten(SA::combine)", "arrow.typeclasses.combine") +) public inline fun Ior>.flatten(SA: Semigroup): Ior = flatMap(SA, ::identity) @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("if (n <= 0) Ior.Right>(emptyList())\n" + - " else when (this) {\n" + - " is Ior.Right -> Ior.Right>(List(n) { value })\n" + - " is Ior.Left -> this\n" + - " is Ior.Both -> map { List(n) { rightValue } }.mapLeft{ List(n - 1) { leftValue }.fold(leftValue) { acc, a -> SA.run> { acc + a } } }\n" + - " }","arrow.core.Ior") + ReplaceWith( + "if (n <= 0) Ior.Right>(emptyList())\n" + + " else when (this) {\n" + + " is Ior.Right -> Ior.Right>(List(n) { value })\n" + + " is Ior.Left -> this\n" + + " is Ior.Both -> map { List(n) { rightValue } }.mapLeft{ List(n - 1) { leftValue }.fold(leftValue) { acc, a -> SA.run> { acc + a } } }\n" + + " }", "arrow.core.Ior" + ) ) public fun Ior.replicate(SA: Semigroup, n: Int): Ior> = if (n <= 0) Ior.Right(emptyList()) else when (this) { is Ior.Right -> Ior.Right(List(n) { value }) is Ior.Left -> this - is Ior.Both -> map { List(n) { rightValue } }.mapLeft{ List(n - 1) { leftValue }.fold(leftValue) { acc, a -> SA.run { acc + a } } } + is Ior.Both -> map { List(n) { rightValue } }.mapLeft { List(n - 1) { leftValue }.fold(leftValue) { acc, a -> SA.run { acc + a } } } } @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("if (n <= 0) Ior.Right(MB.empty())\n" + - " else when (this) {\n" + - " is Ior.Right -> Ior.Right(MB.run { List(n) { value }.fold() })\n" + - " is Ior.Left -> this\n" + - " is Ior.Both -> map { MB.run { List(n) { rightValue }.fold() } }.mapLeft {\n" + - " List(n - 1) { leftValue }.fold(\n" + - " leftValue\n" + - " ) { acc, a -> SA.run { acc + a } }\n" + - " }\n" + - " }", "arrow.core.Ior") + ReplaceWith( + "if (n <= 0) Ior.Right(MB.empty())\n" + + " else when (this) {\n" + + " is Ior.Right -> Ior.Right(MB.run { List(n) { value }.fold() })\n" + + " is Ior.Left -> this\n" + + " is Ior.Both -> map { MB.run { List(n) { rightValue }.fold() } }.mapLeft {\n" + + " List(n - 1) { leftValue }.fold(\n" + + " leftValue\n" + + " ) { acc, a -> SA.run { acc + a } }\n" + + " }\n" + + " }", "arrow.core.Ior" + ) ) public fun Ior.replicate(SA: Semigroup, n: Int, MB: Monoid): Ior = if (n <= 0) Ior.Right(MB.empty()) @@ -1142,76 +1211,98 @@ public fun Ior.replicate(SA: Semigroup, n: Int, MB: Monoid): @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> listOf(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> listOf(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public fun Ior>.sequence(): List> = fold( - { a -> listOf(Left(a)) }, - { b -> b.map { Right(it) } }, - { a, b -> b.map{ Both(a, it) } }) + { a -> listOf(Left(a)) }, + { b -> b.map { Right(it) } }, + { a, b -> b.map { Both(a, it) } }) -@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 Ior>.sequenceEither(): Either> = sequence() @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Either.Right(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> Either.Right(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public fun Ior>.sequence(): Either> = fold( - { a -> Either.Right(Left(a)) }, - { b -> b.map { Right(it) } }, - { a, b -> b.map { Both(a, it) } }) + { a -> Either.Right(Left(a)) }, + { b -> b.map { Right(it) } }, + { a, b -> b.map { Both(a, it) } }) -@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceOption is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Ior>.sequenceOption(): Option> = sequence() @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Some(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", + ReplaceWith( + "fold({ a -> Some(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map{ Ior.Both(a, it) } })", "arrow.core.Ior", - "arrow.core.Some") + "arrow.core.Some" + ) ) public fun Ior>.sequence(): Option> = fold( - { a -> Some(Left(a)) }, - { b -> b.map { Right(it) } }, - { a, b -> b.map { Both(a, it) } }) + { a -> Some(Left(a)) }, + { b -> b.map { Right(it) } }, + { a, b -> b.map { Both(a, it) } }) -@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceOption is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Ior.sequenceNullable(): Ior? = sequence() @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Ior.Left(a) }, {b -> b?.let { Ior.Right(it) } }, { a, b -> b?.let{ Ior.Both(a, it) } })", - "arrow.core.Ior") + ReplaceWith( + "fold({ a -> Ior.Left(a) }, {b -> b?.let { Ior.Right(it) } }, { a, b -> b?.let{ Ior.Both(a, it) } })", + "arrow.core.Ior" + ) ) public fun Ior.sequence(): Ior? = fold( - { a -> Left(a) }, - { b -> b?.let { Right(it) } }, - { a, b -> b?.let{ Both(a, it) } }) + { a -> Left(a) }, + { b -> b?.let { Right(it) } }, + { a, b -> b?.let { Both(a, it) } }) -@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 Ior>.sequenceValidated(): Validated> = sequence() @Deprecated( NicheAPI + "Prefer using Ior DSL, or explicit fold, or when", - ReplaceWith("fold({ a -> Valid(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map { Ior.Both(a, it) } })", + ReplaceWith( + "fold({ a -> Valid(Ior.Left(a)) }, {b -> b.map { Ior.Right(it) } }, { a, b -> b.map { Ior.Both(a, it) } })", "arrow.core.Ior", - "arrow.core.Valid") + "arrow.core.Valid" + ) ) public fun Ior>.sequence(): Validated> = fold( - { a -> Valid(Left(a)) }, - { b -> b.map { Right(it) } }, - { a, b -> b.map { Both(a, it) } }) + { a -> Valid(Left(a)) }, + { b -> b.map { Right(it) } }, + { a, b -> b.map { Both(a, it) } }) /** * Given [B] is a sub type of [C], re-type this value from Ior to Ior @@ -1242,16 +1333,14 @@ public fun Ior.leftWiden(): Ior = @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { Pair(this@zip.bind(), fb.bind()) }", "arrow.core.raise.ior") + ReplaceWith("ior(SA::combine) { Pair(this@zip.bind(), fb.bind()) }", "arrow.core.raise.ior", "arrow.typeclasses.combine") ) -public fun Ior.zip(SA: Semigroup, fb: Ior): Ior> { - - return ior(SA) { Pair(this@zip.bind(), fb.bind()) } -} +public fun Ior.zip(SA: Semigroup, fb: Ior): Ior> = + ior(SA::combine) { Pair(this@zip.bind(), fb.bind()) } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind()) }", "arrow.core.raise.ior") + ReplaceWith("ior(SA::combine) { map(this@zip.bind(), c.bind()) }", "arrow.core.raise.ior", "arrow.typeclasses.combine") ) public inline fun Ior.zip( SA: Semigroup, @@ -1259,14 +1348,14 @@ public inline fun Ior.zip( map: (B, C) -> D ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()) }", "arrow.core.raise.ior") + ReplaceWith("ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()) }", "arrow.core.raise.ior", "arrow.typeclasses.combine") ) public inline fun Ior.zip( SA: Semigroup, @@ -1275,14 +1364,14 @@ public inline fun Ior.zip( map: (B, C, D) -> E ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind() }", "arrow.core.raise.ior") + ReplaceWith("ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind() }", "arrow.core.raise.ior", "arrow.typeclasses.combine") ) public inline fun Ior.zip( SA: Semigroup, @@ -1292,14 +1381,14 @@ public inline fun Ior.zip( map: (B, C, D, E) -> F ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind() }", "arrow.core.raise.ior") + ReplaceWith("ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind() }", "arrow.core.raise.ior", "arrow.typeclasses.combine") ) public inline fun Ior.zip( SA: Semigroup, @@ -1310,14 +1399,17 @@ public inline fun Ior.zip( map: (B, C, D, E, F) -> G ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind(), f.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind() }", "arrow.core.raise.ior") + ReplaceWith( + "ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind() }", + "arrow.core.raise.ior", "arrow.typeclasses.combine" + ) ) public inline fun Ior.zip( SA: Semigroup, @@ -1329,14 +1421,17 @@ public inline fun Ior.zip( map: (B, C, D, E, F, G) -> H ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind() }", "arrow.core.raise.ior") + ReplaceWith( + "ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind() }", + "arrow.core.raise.ior", "arrow.typeclasses.combine" + ) ) public inline fun Ior.zip( SA: Semigroup, @@ -1349,14 +1444,17 @@ public inline fun Ior.zip( map: (B, C, D, E, F, G, H) -> I ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind() }", "arrow.core.raise.ior") + ReplaceWith( + "ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind() }", + "arrow.core.raise.ior", "arrow.typeclasses.combine" + ) ) public inline fun Ior.zip( SA: Semigroup, @@ -1370,14 +1468,17 @@ public inline fun Ior.zip( map: (B, C, D, E, F, G, H, I) -> J ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind() }", "arrow.core.raise.ior") + ReplaceWith( + "ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind() }", + "arrow.core.raise.ior", "arrow.typeclasses.combine" + ) ) public inline fun Ior.zip( SA: Semigroup, @@ -1392,14 +1493,17 @@ public inline fun Ior.zip( map: (B, C, D, E, F, G, H, I, J) -> K ): Ior { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return ior(SA) { + return ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind()) } } @Deprecated( NicheAPI + "Prefer using the inline ior DSL", - ReplaceWith("ior(SA) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind(), k.bind() }", "arrow.core.raise.ior") + ReplaceWith( + "ior(SA::combine) { map(this@zip.bind(), c.bind(), d.bind()), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind(), k.bind() }", + "arrow.core.raise.ior", "arrow.typeclasses.combine" + ) ) public inline fun Ior.zip( SA: Semigroup, diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt index 7d053beaeec..dc7b70c29b1 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt @@ -8,12 +8,16 @@ package arrow.core import arrow.core.Either.Left import arrow.core.Either.Right import arrow.core.raise.Raise +import arrow.core.raise.either import arrow.core.raise.RaiseAccumulate import arrow.core.raise.either import arrow.core.raise.fold import arrow.core.raise.mapOrAccumulate import arrow.typeclasses.Monoid +import arrow.typeclasses.MonoidDeprecation import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.Result.Companion.success import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmName @@ -292,7 +296,10 @@ public inline fun Iterable.zip( internal fun Iterable.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) this.size else default -@Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +@Deprecated( + "traverseEither is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) public inline fun Iterable.traverseEither(f: (A) -> Either): Either> = traverse(f) @@ -309,7 +316,10 @@ public inline fun Iterable.traverse(f: (A) -> Either): Either return destination.right() } -@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 Iterable>.sequenceEither(): Either> = traverse(::identity) @@ -328,18 +338,27 @@ public inline fun Iterable.traverse(f: (A) -> Result): Result Iterable.traverseResult(f: (A) -> Result): Result> = traverse(f) -@Deprecated("sequenceResult is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceResult is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Iterable>.sequenceResult(): Result> = sequence() public fun Iterable>.sequence(): Result> = traverse(::identity) -@Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(semigroup, f)", "arrow.core.traverse")) +@Deprecated( + "traverseValidated is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(semigroup, f)", "arrow.core.traverse") +) public inline fun Iterable.traverseValidated( semigroup: Semigroup, f: (A) -> Validated @@ -361,7 +380,10 @@ public inline fun Iterable.traverse( ): Validated> = mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated() -@Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +@Deprecated( + "traverseValidated is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) public inline fun Iterable.traverseValidated(f: (A) -> ValidatedNel): ValidatedNel> = traverse(f) @@ -377,7 +399,10 @@ public inline fun Iterable.traverseValidated(f: (A) -> ValidatedNel public inline fun Iterable.traverse(f: (A) -> ValidatedNel): ValidatedNel> = mapOrAccumulate { f(it).bindNel() }.toValidated() -@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence(semigroup)", "arrow.core.sequence")) +@Deprecated( + "sequenceValidated is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence(semigroup)", "arrow.core.sequence") +) public fun Iterable>.sequenceValidated(semigroup: Semigroup): Validated> = sequence(semigroup) @@ -391,7 +416,10 @@ public fun Iterable>.sequenceValidated(semigroup: Semigro public fun Iterable>.sequence(semigroup: Semigroup): Validated> = mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated() -@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 Iterable>.sequenceValidated(): ValidatedNel> = sequence() @@ -405,7 +433,10 @@ public fun Iterable>.sequenceValidated(): ValidatedNel public fun Iterable>.sequence(): ValidatedNel> = mapOrAccumulate { it.bindNel() }.toValidated() -@Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +@Deprecated( + "traverseOption is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) public inline fun Iterable.traverseOption(f: (A) -> Option): Option> = traverse(f) @@ -422,14 +453,20 @@ public inline fun Iterable.traverse(f: (A) -> Option): Option Iterable>.sequenceOption(): Option> = sequence() public fun Iterable>.sequence(): Option> = traverse(::identity) -@Deprecated("traverseNullable is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +@Deprecated( + "traverseNullable is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) public inline fun Iterable.traverseNullable(f: (A) -> B?): List? = traverse(f) @@ -448,7 +485,10 @@ public inline fun Iterable.traverse(f: (A) -> B?): List? { return acc.toList() } -@Deprecated("sequenceNullable is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceNullable is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Iterable.sequenceNullable(): List? = sequence() @@ -793,18 +833,24 @@ public fun Iterable.align(b: Iterable): List> = this.align(b, ::identity) /** - * aligns two structures and combine them with the given [Semigroup.combine] + * aligns two structures and combine them with [combine] */ public fun Iterable.salign( - SG: Semigroup, + combine: (A, A) -> A, other: Iterable -): Iterable = SG.run { +): Iterable = align(other) { - it.fold(::identity, ::identity) { a, b -> - a.combine(b) - } + it.fold(::identity, ::identity, combine) } -} + +/** + * aligns two structures and combine them with the given [Semigroup.combine] + */ +@Deprecated(SemigroupDeprecation, ReplaceWith("salign(SG::combine, other)", "arrow.typeclasses.combine")) +public fun Iterable.salign( + SG: Semigroup, + other: Iterable +): Iterable = salign(SG::combine, other) /** * unzips the structure holding the resulting elements in an `Pair` @@ -913,9 +959,9 @@ public fun Iterable>.separateIor(): Pair, List> = ) } -@Deprecated("use fold instead", ReplaceWith("fold(MA)", "arrow.core.fold")) +@Deprecated("Use fold instead", ReplaceWith("fold(MA.empty(), MA::combine)", "arrow.typeclasses.combine")) public fun Iterable.combineAll(MA: Monoid): A = - fold(MA) + fold(MA.empty(), MA::combine) /** * Returns the first element as [Some(element)][Some], or [None] if the iterable is empty. @@ -1205,17 +1251,13 @@ public fun Iterable.widen(): Iterable = public fun List.widen(): List = this -public fun Iterable.fold(MA: Monoid): A = MA.run { - this@fold.fold(empty()) { acc, a -> - acc.combine(a) - } -} +@Deprecated(MonoidDeprecation, ReplaceWith("fold(MA.empty(), MA::combine)", "arrow.typeclasses.combine")) +public fun Iterable.fold(MA: Monoid): A = + fold(MA.empty(), MA::combine) -public fun Iterable.foldMap(MB: Monoid, f: (A) -> B): B = MB.run { - this@foldMap.fold(empty()) { acc, a -> - acc.combine(f(a)) - } -} +@Deprecated(MonoidDeprecation, ReplaceWith("fold(MB.empty()) { acc, a -> MB.run { acc.combine(f(a)) } }")) +public fun Iterable.foldMap(MB: Monoid, f: (A) -> B): B = + fold(MB.empty()) { acc, a -> MB.run { acc.combine(f(a)) } } public fun Iterable.crosswalk(f: (A) -> Iterable): List> = fold(emptyList()) { bs, a -> @@ -1256,6 +1298,7 @@ public fun Iterable.replicate(n: Int): List> = if (n <= 0) emptyList() else toList().let { l -> List(n) { l } } +@Deprecated(NicheAPI) public fun Iterable.replicate(n: Int, MA: Monoid): List = if (n <= 0) listOf(MA.empty()) else this@replicate.zip(replicate(n - 1, MA)) { a, xs -> MA.run { a + xs } } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/NonEmptyList.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/NonEmptyList.kt index 110d09a61cb..b0aaac5bc9b 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/NonEmptyList.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/NonEmptyList.kt @@ -6,6 +6,8 @@ import arrow.core.Either.Left import arrow.core.Either.Right import arrow.core.raise.RaiseAccumulate import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmStatic @@ -218,10 +220,12 @@ public class NonEmptyList( public fun align(b: NonEmptyList): NonEmptyList> = NonEmptyList(Ior.Both(head, b.head), tail.align(b.tail)) + public fun salign(other: NonEmptyList<@UnsafeVariance A>, combine: (A, A) -> @UnsafeVariance A): NonEmptyList = + NonEmptyList(combine(head, other.head), tail.salign(combine, other.tail).toList()) + + @Deprecated(SemigroupDeprecation, ReplaceWith("salign(b, SA::combine)", "arrow.typeclasses.combine")) public fun salign(SA: Semigroup<@UnsafeVariance A>, b: NonEmptyList<@UnsafeVariance A>): NonEmptyList = - SA.run { - NonEmptyList(head.combine(b.head), tail.salign(SA, b.tail).toList()) - } + salign(b, SA::combine) public fun padZip(other: NonEmptyList): NonEmptyList> = NonEmptyList(head to other.head, tail.padZip(other.tail)) @@ -443,8 +447,9 @@ public fun NonEmptyList>.sequence(): Either semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { f(it).bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) public inline fun NonEmptyList.traverseValidated( @@ -456,8 +461,9 @@ public inline fun NonEmptyList.traverseValidated( @Deprecated( ValidatedDeprMsg + "Use the mapOrAccumulate API instead", ReplaceWith( - "mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { f(it).bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) @OptIn(ExperimentalTypeInference::class) @@ -466,27 +472,29 @@ public inline fun NonEmptyList.traverse( semigroup: Semigroup, f: (A) -> Validated ): Validated> = - mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated() + mapOrAccumulate(semigroup::combine) { f(it).bind() }.toValidated() @Deprecated( ValidatedDeprMsg + "Use the mapOrAccumulate API instead", ReplaceWith( - "mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) public fun NonEmptyList>.sequenceValidated(semigroup: Semigroup): Validated> = - mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated() + mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated() @Deprecated( ValidatedDeprMsg + "Use the mapOrAccumulate API instead", ReplaceWith( - "mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) public fun NonEmptyList>.sequence(semigroup: Semigroup): Validated> = - mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated() + mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated() public inline fun NonEmptyList.mapOrAccumulate( combine: (E, E) -> 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 21a54953a8f..799d1f21ecb 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 @@ -7,7 +7,10 @@ import arrow.core.raise.Effect import arrow.core.raise.OptionRaise import arrow.core.raise.option import arrow.typeclasses.Monoid +import arrow.typeclasses.MonoidDeprecation import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -1054,11 +1057,10 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("MB.run { this.fold({ empty() }) { a -> empty().combine(f(a)) } }") + ReplaceWith("fold({ MB.empty() }, f)") ) - public inline fun foldMap(MB: Monoid, f: (A) -> B): B = MB.run { - foldLeft(empty()) { b, a -> b.combine(f(a)) } - } + public inline fun foldMap(MB: Monoid, f: (A) -> B): B = + fold({ MB.empty() }, f) @Deprecated( NicheAPI + "Prefer when or fold instead", @@ -1310,9 +1312,9 @@ public fun A.some(): Option = Some(this) public fun none(): Option = None -@Deprecated("use fold instead", ReplaceWith("fold(Monoid.option(MA))", "arrow.core.fold", "arrow.typeclasses.Monoid")) +@Deprecated(SemigroupDeprecation, ReplaceWith("fold(none()) { x, y -> x.combine(y, MA::combine) }", "arrow.typeclasses.combine")) public fun Iterable>.combineAll(MA: Monoid): Option = - fold(Monoid.option(MA)) + fold(none()) { x, y -> x.combine(y, MA::combine) } @Deprecated("use getOrElse instead", ReplaceWith("getOrElse { MA.empty() }")) public fun Option.combineAll(MA: Monoid): A = @@ -1413,12 +1415,10 @@ public inline fun Option.redeemWith(fe: (Unit) -> Option, fb: (A) - @Deprecated( NicheAPI + "Prefer using the Option DSL or map", - ReplaceWith("MA.run { this.map { List(n) { it }.fold(empty()) { acc, v -> acc + v } } }") + ReplaceWith("map { a -> List(n) { a }.fold(MA.empty(), MA::combine) }", "arrow.typeclasses.combine") ) -public fun Option.replicate(n: Int, MA: Monoid): Option = MA.run { - if (n <= 0) Some(empty()) - else map { a -> List(n) { a }.fold(empty()) { acc, v -> acc + v } } -} +public fun Option.replicate(n: Int, MA: Monoid): Option = + map { a -> List(n) { a }.fold(MA.empty(), MA::combine) } @Deprecated( NicheAPI + "Prefer using the Option DSL or explicit flatmap", @@ -1624,16 +1624,19 @@ public fun Option.widen(): Option = public fun Option>.toMap(): Map = this.toList().toMap() -public fun Option.combine(SGA: Semigroup, b: Option): Option = +public fun Option.combine(other: Option, combine: (A, A) -> A): Option = when (this) { - is Some -> when (b) { - is Some -> Some(SGA.run { value.combine(b.value) }) + is Some -> when (other) { + is Some -> Some(combine(value, other.value)) None -> this } - - None -> b + None -> other } +@Deprecated(SemigroupDeprecation, ReplaceWith("combine(b, SGA::combine)", "arrow.typeclasses.combine")) +public fun Option.combine(SGA: Semigroup, b: Option): Option = + combine(b, SGA::combine) + public operator fun > Option.compareTo(other: Option): Int = fold( { other.fold({ 0 }, { -1 }) }, { a1 -> diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Pair.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Pair.kt index 1776b42757c..9fea3c74ed9 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Pair.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Pair.kt @@ -4,6 +4,8 @@ package arrow.core import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -13,8 +15,13 @@ public operator fun , B : Comparable> Pair.compareTo( else first } -public fun Pair.combine(SA: Semigroup, SB: Semigroup, b: Pair): Pair { - val (xa, xb) = this - val (ya, yb) = b - return Pair(SA.run { xa.combine(ya) }, SB.run { xb.combine(yb) }) -} + +@Deprecated( + "$SemigroupDeprecation\n$NicheAPI", + ReplaceWith( + "Pair(SA.combine(first, b.first), SB.combine(second, b.second))", + "arrow.typeclasses.combine" + ) +) +public fun Pair.combine(SA: Semigroup, SB: Semigroup, b: Pair): Pair = + Pair(SA.combine(first, b.first), SB.combine(second, b.second)) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Sequence.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Sequence.kt index 6a1127682ec..b54517fe15f 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Sequence.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Sequence.kt @@ -8,6 +8,8 @@ import arrow.core.raise.RaiseAccumulate import arrow.core.raise.fold import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation +import arrow.typeclasses.combine import kotlin.experimental.ExperimentalTypeInference public fun Sequence.zip( @@ -519,10 +521,14 @@ public fun Sequence.padZip(other: Sequence): Sequence> public fun Sequence.padZip(other: Sequence, fa: (A?, B?) -> C): Sequence = padZip(other).map { fa(it.first, it.second) } +@Deprecated( + "$SemigroupDeprecation\n$NicheAPI", + ReplaceWith("Sequence { List(n) { this@replicate }.iterator() }") +) public fun Sequence.replicate(n: Int): Sequence> = - if (n <= 0) emptySequence() - else this.let { l -> Sequence { List(n) { l }.iterator() } } + Sequence { List(n) { this@replicate }.iterator() } +@Deprecated(NicheAPI) public fun Sequence.replicate(n: Int, MA: Monoid): Sequence = if (n <= 0) sequenceOf(MA.empty()) else this@replicate.zip(replicate(n - 1, MA)) { a, xs -> MA.run { a + xs } } @@ -577,19 +583,24 @@ public fun Sequence.rightPadZip(other: Sequence, fa: (A, B?) -> public fun Sequence.rightPadZip(other: Sequence): Sequence> = this.rightPadZip(other) { a, b -> a to b } +/** + * aligns two structures and combine them with the given [combine] + */ +public fun Sequence.salign( + other: Sequence, + combine: (A, A) -> A +): Sequence = + align(other) { it.fold(::identity, ::identity, combine) } + /** * aligns two structures and combine them with the given [Semigroup.combine] */ +@Deprecated(SemigroupDeprecation, ReplaceWith("salign(other, SG::combine)", "arrow.typeclasses.combine")) public fun Sequence.salign( SG: Semigroup, other: Sequence -): Sequence = SG.run { - align(other) { - it.fold(::identity, ::identity) { a, b -> - a.combine(b) - } - } -} +): Sequence = + salign(other, SG::combine) /** * Separate the inner [Either] values into the [Either.Left] and [Either.Right]. @@ -642,12 +653,13 @@ public fun Sequence>.sequenceOption(): Option> = @Deprecated( ValidatedDeprMsg + "Use the mapOrAccumulate API instead", ReplaceWith( - "mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) public fun Sequence>.sequence(semigroup: Semigroup): Validated> = - mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { it.bind() }.toValidated() + mapOrAccumulate(semigroup::combine) { it.bind() }.toValidated() @Deprecated( "sequenceValidated is being renamed to sequence to simplify the Arrow API", @@ -733,8 +745,9 @@ public fun Sequence.traverseOption(f: (A) -> Option): Option semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated()", - "arrow.core.mapOrAccumulate" + "mapOrAccumulate(semigroup::combine) { f(it).bind() }.toValidated()", + "arrow.core.mapOrAccumulate", + "arrow.typeclasses.combine" ) ) @OptIn(ExperimentalTypeInference::class) @@ -743,7 +756,7 @@ public fun Sequence.traverse( semigroup: Semigroup, f: (A) -> Validated ): Validated> = - mapOrAccumulate({ a, b -> semigroup.run { a.combine(b) } }) { f(it).bind() }.toValidated() + mapOrAccumulate(semigroup::combine) { f(it).bind() }.toValidated() public fun Sequence.mapOrAccumulate( combine: (Error, Error) -> Error, diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Validated.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Validated.kt index dee1e08acdc..610100c7acc 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Validated.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Validated.kt @@ -4,6 +4,8 @@ import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup import arrow.core.Either.Left import arrow.core.Either.Right +import arrow.typeclasses.MonoidDeprecation +import arrow.typeclasses.combine import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @@ -248,11 +250,10 @@ public sealed class Validated { @Deprecated( DeprAndNicheMsg + "Prefer when or fold instead", - ReplaceWith("MN.run { fold({ empty().combine(g(it)) }, { empty().combine(f(it)) }) }") + ReplaceWith("fold(g, f)") ) - public inline fun bifoldMap(MN: Monoid, g: (E) -> B, f: (A) -> B): B = MN.run { - bifoldLeft(MN.empty(), { c, b -> c.combine(g(b)) }) { c, a -> c.combine(f(a)) } - } + public inline fun bifoldMap(MN: Monoid, g: (E) -> B, f: (A) -> B): B = + fold(g, f) @Deprecated( DeprAndNicheMsg + "Prefer explicit fold instead", @@ -502,6 +503,7 @@ public sealed class Validated { f(this.value) this } + is Valid -> this } @@ -557,18 +559,20 @@ public sealed class Validated { @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), fb.toEither(), ::Pair).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), fb.toEither(), ::Pair).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public fun Validated.zip(SE: Semigroup, fb: Validated): Validated> = - zip(SE, fb, ::Pair) + Either.zipOrAccumulate(SE::combine, toEither(), fb.toEither(), ::Pair).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -576,26 +580,14 @@ public inline fun Validated.zip( b: Validated, f: (A, B) -> Z ): Validated = - zip( - SE, - b, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit - ) { a, b, _, _, _, _, _, _, _, _ -> - f(a, b) - } + Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), f).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -604,26 +596,14 @@ public inline fun Validated.zip( c: Validated, f: (A, B, C) -> Z ): Validated = - zip( - SE, - b, - c, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit - ) { a, b, c, _, _, _, _, _, _, _ -> - f(a, b, c) - } + Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), f).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -633,26 +613,14 @@ public inline fun Validated.zip( d: Validated, f: (A, B, C, D) -> Z ): Validated = - zip( - SE, - b, - c, - d, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit - ) { a, b, c, d, _, _, _, _, _, _ -> - f(a, b, c, d) - } + Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), f).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -663,26 +631,15 @@ public inline fun Validated.zip( e: Validated, f: (A, B, C, D, EE) -> Z ): Validated = - zip( - SE, - b, - c, - d, - e, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit - ) { a, b, c, d, e, _, _, _, _, _ -> - f(a, b, c, d, e) - } + Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), f) + .toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -694,26 +651,23 @@ public inline fun Validated.zip( ff: Validated, f: (A, B, C, D, EE, FF) -> Z ): Validated = - zip( - SE, - b, - c, - d, - e, - ff, - Valid.unit, - Valid.unit, - Valid.unit, - Valid.unit - ) { a, b, c, d, e, ff, _, _, _, _ -> - f(a, b, c, d, e, ff) - } + Either.zipOrAccumulate( + SE::combine, + toEither(), + b.toEither(), + c.toEither(), + d.toEither(), + e.toEither(), + ff.toEither(), + f + ).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -726,15 +680,24 @@ public inline fun Validated.zip( g: Validated, f: (A, B, C, D, EE, F, G) -> Z ): Validated = - zip(SE, b, c, d, e, ff, g, Valid.unit, Valid.unit, Valid.unit) { a, b, c, d, e, ff, g, _, _, _ -> - f(a, b, c, d, e, ff, g) - } + Either.zipOrAccumulate( + SE::combine, + toEither(), + b.toEither(), + c.toEither(), + d.toEither(), + e.toEither(), + ff.toEither(), + g.toEither(), + f + ).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -748,15 +711,25 @@ public inline fun Validated.zip( h: Validated, f: (A, B, C, D, EE, F, G, H) -> Z ): Validated = - zip(SE, b, c, d, e, ff, g, h, Valid.unit, Valid.unit) { a, b, c, d, e, ff, g, h, _, _ -> - f(a, b, c, d, e, ff, g, h) - } + Either.zipOrAccumulate( + SE::combine, + toEither(), + b.toEither(), + c.toEither(), + d.toEither(), + e.toEither(), + ff.toEither(), + g.toEither(), + h.toEither(), + f + ).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), i.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), i.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -771,15 +744,26 @@ public inline fun Validated.zip( i: Validated, f: (A, B, C, D, EE, F, G, H, I) -> Z ): Validated = - zip(SE, b, c, d, e, ff, g, h, i, Valid.unit) { a, b, c, d, e, ff, g, h, i, _ -> - f(a, b, c, d, e, ff, g, h, i) - } + Either.zipOrAccumulate( + SE::combine, + toEither(), + b.toEither(), + c.toEither(), + d.toEither(), + e.toEither(), + ff.toEither(), + g.toEither(), + h.toEither(), + i.toEither(), + f + ).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", ReplaceWith( - "Either.zipOrAccumulate({ a, b -> SE.run, E> { a.combine(b) } }, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), i.toEither(), j.toEither(), f).toValidated()", - "arrow.core.Either" + "Either.zipOrAccumulate(SE::combine, toEither(), b.toEither(), c.toEither(), d.toEither(), e.toEither(), ff.toEither(), g.toEither(), h.toEither(), i.toEither(), j.toEither(), f).toValidated()", + "arrow.core.Either", + "arrow.typeclasses.combine" ) ) public inline fun Validated.zip( @@ -795,33 +779,20 @@ public inline fun Validated.zip( j: Validated, f: (A, B, C, D, EE, F, G, H, I, J) -> Z ): Validated = - if (this is Validated.Valid && b is Validated.Valid && c is Validated.Valid && d is Validated.Valid && e is Validated.Valid && ff is Validated.Valid && g is Validated.Valid && h is Validated.Valid && i is Validated.Valid && j is Validated.Valid) { - Validated.Valid(f(this.value, b.value, c.value, d.value, e.value, ff.value, g.value, h.value, i.value, j.value)) - } else SE.run { - var accumulatedError: Any? = EmptyValue - accumulatedError = - if (this@zip is Validated.Invalid) this@zip.value else accumulatedError - accumulatedError = - if (b is Validated.Invalid) emptyCombine(accumulatedError, b.value) else accumulatedError - accumulatedError = - if (c is Validated.Invalid) emptyCombine(accumulatedError, c.value) else accumulatedError - accumulatedError = - if (d is Validated.Invalid) emptyCombine(accumulatedError, d.value) else accumulatedError - accumulatedError = - if (e is Validated.Invalid) emptyCombine(accumulatedError, e.value) else accumulatedError - accumulatedError = - if (ff is Validated.Invalid) emptyCombine(accumulatedError, ff.value) else accumulatedError - accumulatedError = - if (g is Validated.Invalid) emptyCombine(accumulatedError, g.value) else accumulatedError - accumulatedError = - if (h is Validated.Invalid) emptyCombine(accumulatedError, h.value) else accumulatedError - accumulatedError = - if (i is Validated.Invalid) emptyCombine(accumulatedError, i.value) else accumulatedError - accumulatedError = - if (j is Validated.Invalid) emptyCombine(accumulatedError, j.value) else accumulatedError - - Validated.Invalid(accumulatedError as E) - } + Either.zipOrAccumulate( + SE::combine, + toEither(), + b.toEither(), + c.toEither(), + d.toEither(), + e.toEither(), + ff.toEither(), + g.toEither(), + h.toEither(), + i.toEither(), + j.toEither(), + f + ).toValidated() @Deprecated( ValidatedDeprMsg + "zipOrAccumulate for Either now exposes this same functionality", @@ -1009,7 +980,10 @@ public fun Validated.leftWiden(): Validated = @Deprecated( DeprAndNicheMsg + "Prefer using the Either DSL, or map", - ReplaceWith("(0 until (n.coerceAtLeast(0))).mapOrAccumulate({ a, b -> SE.run { a.combine(b) } }) { bind() }.toValidated()") + ReplaceWith( + "(0 until (n.coerceAtLeast(0))).mapOrAccumulate(SE::combine) { bind() }.toValidated()", + "arrow.typeclasses.combine" + ) ) public fun Validated.replicate(SE: Semigroup, n: Int): Validated> = if (n <= 0) emptyList().valid() @@ -1061,14 +1035,16 @@ public fun Validated.bisequenceNullable(): Validated? = bitraverseNullable(::identity, ::identity) @Deprecated( - DeprAndNicheMsg + "Use fold on Either after refactoring", - ReplaceWith("MA.run { fold({ empty() }) { empty().combine(it) } }") + "$MonoidDeprecation\n$DeprAndNicheMsg\nUse fold on Either after refactoring", + ReplaceWith("fold({ MA.empty() }, ::identity)") ) -public fun Validated.fold(MA: Monoid): A = MA.run { - foldLeft(empty()) { acc, a -> acc.combine(a) } -} +public fun Validated.fold(MA: Monoid): A = + fold({ MA.empty() }, ::identity) -@Deprecated("use fold instead", ReplaceWith("fold(MA)", "arrow.core.fold")) +@Deprecated( + "$MonoidDeprecation\n$DeprAndNicheMsg\nUse fold on Either after refactoring", + ReplaceWith("fold({ MA.empty() }, ::identity)", "arrow.core.fold") +) public fun Validated.combineAll(MA: Monoid): A = fold(MA) @@ -1184,20 +1160,13 @@ public inline fun Validated.valueOr(f: (E) -> A): A = @Deprecated( DeprAndNicheMsg + "Use recover on Either after refactoring", ReplaceWith( - "toEither().recover { e -> that().mapLeft { ee -> SE.run { e.combine(ee) } }.bind() }.toValidated()", - "arrow.core.recover" + "toEither().recover { e -> that().mapLeft { ee -> SE.combine(e, ee) }.bind() }.toValidated()", + "arrow.core.recover", + "arrow.typeclasses.combine" ) ) public inline fun Validated.findValid(SE: Semigroup, that: () -> Validated): Validated = - fold( - { e -> - that().fold( - { ee -> Invalid(SE.run { e.combine(ee) }) }, - { Valid(it) } - ) - }, - { Valid(it) } - ) + toEither().recover { e -> that().mapLeft { ee -> SE.combine(e, ee) }.bind() }.toValidated() /** * Apply a function to a Valid value, returning a new Validation that may be valid or invalid @@ -1286,36 +1255,25 @@ public inline fun Validated.merge(): A = @Deprecated( ValidatedDeprMsg + "Use Either.zipOrAccumulate instead", - ReplaceWith("Either.zipOrAccumulate({ a, b -> SE.run { a.combine(b) } }, toEither(), y.toEither(), { a, b -> SA.run { a.combine(b) } }).toValidated()") + ReplaceWith("Either.zipOrAccumulate(SE::combine, toEither(), y.toEither(), SA::combine).toValidated()") ) public fun Validated.combine( SE: Semigroup, SA: Semigroup, y: Validated ): Validated = - when { - this is Valid && y is Valid -> Valid(SA.run { value.combine(y.value) }) - this is Invalid && y is Invalid -> Invalid(SE.run { value.combine(y.value) }) - this is Invalid -> this - else -> y - } + Either.zipOrAccumulate(SE::combine, toEither(), y.toEither(), SA::combine).toValidated() @Deprecated( DeprAndNicheMsg, ReplaceWith( - "toEither().recover { e -> y.toEither().recover { ee -> raise(SE.run { e.combine(ee) })) }.bind() }.toValidated()", - "arrow.core.recover" + "toEither().recover { e -> y.toEither().recover { ee -> raise(SE.combine(e, ee)) }.bind() }.toValidated()", + "arrow.core.recover", + "arrow.typeclasses.combine" ) ) -public fun Validated.combineK(SE: Semigroup, y: Validated): Validated { - return when (this) { - is Valid -> this - is Invalid -> when (y) { - is Invalid -> Invalid(SE.run { this@combineK.value.combine(y.value) }) - is Valid -> y - } - } -} +public fun Validated.combineK(SE: Semigroup, y: Validated): Validated = + toEither().recover { e -> y.toEither().recover { ee -> raise(SE.combine(e, ee)) }.bind() }.toValidated() /** * Converts the value to an Ior diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/map.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/map.kt index ed9d5ba3af2..34eee2c615a 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/map.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/map.kt @@ -4,12 +4,13 @@ package arrow.core import arrow.core.Either.Left import arrow.core.Either.Right -import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation import kotlin.experimental.ExperimentalTypeInference import kotlin.collections.flatMap as _flatMap import arrow.core.raise.RaiseAccumulate import arrow.core.raise.fold +import arrow.typeclasses.combine /** * Combines to structures by taking the intersection of their shapes @@ -234,10 +235,16 @@ public inline fun Map.zip( return destination } +/** + * Transform every [Map.Entry] of the original [Map] using [f], + * only keeping the [Map.Entry] of the transformed map that match the input [Map.Entry]. + */ public fun Map.flatMap(f: (Map.Entry) -> Map): Map = - _flatMap { entry -> - f(entry)[entry.key]?.let { Pair(entry.key, it) }.asIterable() - }.toMap() + buildMap { + this@flatMap.forEach { entry -> + f(entry)[entry.key]?.let { put(entry.key, it) } + } + } @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -536,14 +543,25 @@ public fun Map.unzip(fc: (Map.Entry) -> Pair): Pa public fun Map.getOrNone(key: K): Option = this[key].toOption() -public fun Map.combine(SG: Semigroup, b: Map): Map = with(SG) { - if (size < b.size) foldLeft(b) { my, (k, b) -> my + Pair(k, b.maybeCombine(my[k])) } - else b.foldLeft(this@combine) { my, (k, a) -> my + Pair(k, a.maybeCombine(my[k])) } -} +/** Combines two maps using [combine] to combine values for the same key. */ +public fun Map.combine(other: Map, combine: (A, A) -> A): Map = + if (size < other.size) fold(other) { my, (k, b) -> my + Pair(k, my[k]?.let { combine(b, it) } ?: b) } + else other.fold(this@combine) { my, (k, a) -> my + Pair(k, my[k]?.let { combine(a, it) } ?: a) } -@Deprecated("use fold instead", ReplaceWith("fold(Monoid.map(SG))", "arrow.core.fold", "arrow.typeclasses.Monoid")) +@Deprecated(SemigroupDeprecation, ReplaceWith("combine(b, SG::combine)", "arrow.typeclasses.combine")) +public fun Map.combine(SG: Semigroup, b: Map): Map = + combine(b, SG::combine) + +@Deprecated( + "Use fold & Map.combine instead.\n$NicheAPI", + ReplaceWith( + "fold(emptyMap()) { acc, map -> acc.combine(map, SG::combine) }", + "arrow.core.combine", + "arrow.typeclasses.combine" + ) +) public fun Iterable>.combineAll(SG: Semigroup): Map = - fold(Monoid.map(SG)) + fold(emptyMap()) { acc, map -> acc.combine(map, SG::combine) } public inline fun Map.fold(initial: B, operation: (acc: B, Map.Entry) -> B): B { var accumulator = initial @@ -551,13 +569,11 @@ public inline fun Map.fold(initial: B, operation: (acc: B, Map.E return accumulator } -@Deprecated("Use fold instead align with Kotlin Std naming", ReplaceWith("fold(b, f)")) -public inline fun Map.foldLeft(b: B, f: (B, Map.Entry) -> B): B { - var result = b - this.forEach { result = f(result, it) } - return result -} +@Deprecated("Use fold instead foldLeft", ReplaceWith("fold(b, f)")) +public inline fun Map.foldLeft(b: B, f: (B, Map.Entry) -> B): B = + fold(b, f) +@Deprecated("Internal method will be removed from binary in 2.0.0") internal fun Pair?.asIterable(): Iterable> = when (this) { null -> emptyList() diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/predef.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/predef.kt index 1849552f863..65526bea9fc 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/predef.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/predef.kt @@ -1,6 +1,7 @@ package arrow.core import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation public inline fun identity(a: A): A = a @@ -24,5 +25,6 @@ internal object EmptyValue { * Like [Semigroup.maybeCombine] but for using with [EmptyValue] */ @PublishedApi +@Deprecated(SemigroupDeprecation, ReplaceWith("EmptyValue.combine(first, second) { x, y -> x.combine(y) }", "arrow.core.EmptyValue")) internal fun Semigroup.emptyCombine(first: Any?, second: T): T = - if (first == EmptyValue) second else (first as T).combine(second) + EmptyValue.combine(first, second) { x, y -> x.combine(y) } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt index ce906755709..cbb5a5c3886 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Builders.kt @@ -15,6 +15,7 @@ import arrow.core.getOrElse import arrow.core.identity import arrow.core.orElse import arrow.typeclasses.Semigroup +import arrow.typeclasses.SemigroupDeprecation import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind.EXACTLY_ONCE import kotlin.contracts.contract @@ -41,11 +42,11 @@ public inline fun option(block: OptionRaise.() -> A): Option { return fold({ block(OptionRaise(this)) }, ::identity, ::Some) } -public inline fun ior(semigroup: Semigroup, @BuilderInference block: IorRaise.() -> A): Ior { +public inline fun ior(noinline combineError: (E, E) -> E, @BuilderInference block: IorRaise.() -> A): Ior { contract { callsInPlace(block, EXACTLY_ONCE) } val state: Atomic> = Atomic(None) return fold>( - { block(IorRaise(semigroup, state, this)) }, + { block(IorRaise(combineError, state, this)) }, { e -> throw e }, { e -> Ior.Left(state.get().getOrElse { e }) }, { a -> state.get().fold({ Ior.Right(a) }, { Ior.Both(it, a) }) } @@ -91,10 +92,10 @@ public value class OptionRaise(private val cont: Raise) : Raise { } public class IorRaise @PublishedApi internal constructor( - semigroup: Semigroup, + private val combineError: (E, E) -> E, private val state: Atomic>, private val raise: Raise, -) : Raise, Semigroup by semigroup { +) : Raise { override fun raise(r: E): Nothing = raise.raise(combine(r)) @@ -110,6 +111,6 @@ public class IorRaise @PublishedApi internal constructor( private fun combine(other: E): E = state.updateAndGet { prev -> - prev.map { e -> e.combine(other) }.orElse { Some(other) } + Some(prev.map { combineError(it, other) }.getOrElse { other }) }.getOrElse { other } } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt index d997083e782..80a829b5895 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/raise/Raise.kt @@ -74,7 +74,7 @@ public annotation class RaiseDSL * effect { failure() } * * val ior: Ior = - * ior(Semigroup.string()) { failure() } + * ior(String::plus) { failure() } * * either shouldBe Either.Left("failed") * effect.toEither() shouldBe Either.Left("failed") diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Monoid.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Monoid.kt index 3767c3db553..10c85c13b4c 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Monoid.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Monoid.kt @@ -8,13 +8,17 @@ import arrow.core.Option import arrow.core.Validated import arrow.core.combine import arrow.core.compose -import arrow.core.flatten import arrow.core.fold import arrow.core.identity import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic import kotlin.collections.plus as _plus +import kotlin.sequences.plus as _plus +public const val MonoidDeprecation: String = + "Monoid is being deprecated, use combine (A, A) -> A lambdas or method references with initial values instead." + +@Deprecated(MonoidDeprecation) public interface Monoid : Semigroup { /** * A zero value for this A @@ -191,7 +195,7 @@ public interface Monoid : Semigroup { private object SequenceMonoid : Monoid> { override fun empty(): Sequence = emptySequence() - override fun Sequence.combine(b: Sequence): Sequence = sequenceOf(this, b).flatten() + override fun Sequence.combine(b: Sequence): Sequence = this._plus(b) } private class EitherMonoid( diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semigroup.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semigroup.kt index 2de78ae1f4d..d019b204be3 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semigroup.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semigroup.kt @@ -1,6 +1,7 @@ package arrow.typeclasses import arrow.core.Const +import arrow.core.ConstDeprecation import arrow.core.Either import arrow.core.Endo import arrow.core.Ior @@ -12,12 +13,19 @@ import arrow.core.compose import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic +public const val SemigroupDeprecation: String = + "Semigroup is being deprecated, use combine (A, A) -> A lambdas or method references instead." + +@Deprecated(SemigroupDeprecation) public fun interface Semigroup { /** * Combine two [A] values. */ public fun A.combine(b: A): A + public fun append(a: A, b: A): A = + a.combine(b) + public operator fun A.plus(b: A): A = this.combine(b) @@ -25,71 +33,137 @@ public fun interface Semigroup { b?.let { combine(it) } ?: this public companion object { + @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Lis::plus directly instead.", + ReplaceWith("List::plus") + ) public fun list(): Semigroup> = Monoid.list() @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Sequence::plus directly instead.", + ReplaceWith("Sequence::plus") + ) public fun sequence(): Semigroup> = Monoid.sequence() @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use String::plus directly instead.", + ReplaceWith("String::plus") + ) public fun string(): Semigroup = Monoid.string() @JvmStatic @JvmName("Boolean") + @Deprecated( + "$SemigroupDeprecation. Use Boolean::and directly instead.", + ReplaceWith("Boolean::and") + ) public fun boolean(): Semigroup = Monoid.boolean() @JvmStatic @JvmName("Byte") + @Deprecated( + "$SemigroupDeprecation. Use Int::plus and toByte directly instead.", + ReplaceWith("{ a, b -> (a + b).toByte() }") + ) public fun byte(): Semigroup = Monoid.byte() @JvmStatic @JvmName("Integer") + @Deprecated( + "$SemigroupDeprecation. Use Int::plus directly instead.", + ReplaceWith("Int::plus") + ) public fun int(): Semigroup = Monoid.int() @JvmStatic @JvmName("Long") + @Deprecated( + "$SemigroupDeprecation. Use Long::plus directly instead.", + ReplaceWith("Long::plus") + ) public fun long(): Semigroup = Monoid.long() @JvmStatic @JvmName("Short") + @Deprecated( + "$SemigroupDeprecation. Use Int::plus and toShort directly instead.", + ReplaceWith("{ a, b -> (a + b).toShort() }") + ) public fun short(): Semigroup = Monoid.short() @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Either::combine directly instead.", + ReplaceWith("{ a: Either, b: Either -> a.combine(b, SA::combine, SB::combine) }") + ) public fun either(SA: Semigroup, SB: Semigroup): Semigroup> = EitherSemigroup(SA, SB) @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Ior::combine directly instead.", + ReplaceWith("{ a: Ior, b: Ior -> a.combine(b, SA::combine, SB::combine) }") + ) public fun ior(SA: Semigroup, SB: Semigroup): Semigroup> = IorSemigroup(SA, SB) @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use arrow.core.compose directly instead.", + ReplaceWith("{ f, g -> f.compose(g.f) }") + ) public fun endo(): Semigroup> = - object : Semigroup> { - override fun Endo.combine(g: Endo): Endo = Endo(f.compose(g.f)) - } + Semigroup { g -> Endo(f.compose(g.f)) } @JvmStatic @JvmName("constant") + @Deprecated(ConstDeprecation) public fun const(SA: Semigroup): Semigroup> = - object : Semigroup> { - override fun Const.combine(b: Const): Const = - this.combine(SA, b) - } + Semigroup { b -> this.combine(SA, b) } @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Map::combine directly instead.", + ReplaceWith( + "{ a: Map, b: Map -> a.combine(b, SG::combine) }", + "arrow.core.combine" + ) + ) public fun map(SG: Semigroup): Semigroup> = MapSemigroup(SG) @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Option::combine directly instead.", + ReplaceWith( + "{ a: Option, b: Option -> a.combine(b, SGA::combine) }", + "arrow.core.combine" + ) + ) public fun option(SGA: Semigroup): Semigroup> = OptionSemigroup(SGA) @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use Validated::combine directly instead.", + ReplaceWith( + "{ a: Validated, b: Validated -> a.combine(b, SE, SA) }", + "arrow.core.combine" + ) + ) public fun validated(SE: Semigroup, SA: Semigroup): Semigroup> = ValidatedSemigroup(SE, SA) @Suppress("UNCHECKED_CAST") @JvmStatic + @Deprecated( + "$SemigroupDeprecation. Use NonEmptyPlus::plus directly instead.", + ReplaceWith("NonEmptyList::plus", "arrow.core.plus") + ) public fun nonEmptyList(): Semigroup> = NonEmptyListSemigroup as Semigroup> @@ -158,3 +232,7 @@ public fun interface Semigroup { } } } + +@Deprecated(SemigroupDeprecation) +public fun Semigroup.combine(a: A, b: A): A = + a.combine(b) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semiring.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semiring.kt index fd896ebf874..7ff3da0dddf 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semiring.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/typeclasses/Semiring.kt @@ -9,6 +9,9 @@ public const val FloatInstanceDeprecation: String = public const val DoubleInstanceDeprecation: String = "Double instances for Semigroup/Monoid & Semiring are deprecated. Due to how equality of floating-point numbers work, they're not lawful under equality." +public const val SemiringDeprecation: String = + "Semiring is being deprecated." + /** * The [Semiring] type class for a given type `A` combines both a commutative additive [Monoid] and a multiplicative [Monoid]. * It requires the multiplicative [Monoid] to distribute over the additive one. The operations of the multiplicative [Monoid] have been renamed to @@ -83,6 +86,7 @@ public const val DoubleInstanceDeprecation: String = * ``` * */ +@Deprecated(SemiringDeprecation) public interface Semiring { /** diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/BooleanTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/BooleanTest.kt index 1060c81e111..04fb215fbbf 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/BooleanTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/BooleanTest.kt @@ -2,13 +2,12 @@ package arrow.core import arrow.core.test.laws.MonoidLaws import arrow.core.test.testLaws -import arrow.typeclasses.Monoid import io.kotest.core.spec.style.StringSpec import io.kotest.property.Arb import io.kotest.property.arbitrary.boolean class BooleanTest : StringSpec({ testLaws( - MonoidLaws.laws(Monoid.boolean(), Arb.boolean()) + MonoidLaws(true, { x, y -> x && y }, Arb.boolean()) ) }) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EitherTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EitherTest.kt index 7accba25689..0d88fcfaa83 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EitherTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EitherTest.kt @@ -36,23 +36,7 @@ class EitherTest : StringSpec({ val ARB = Arb.either(Arb.string(), Arb.int()) testLaws( - MonoidLaws.laws(Monoid.either(Monoid.string(), Monoid.int()), ARB), - /*FxLaws.suspended, Either, Int>( - Arb.int().map(::Right), - ARB.map { it }, - Either::equals, - either::invoke - ) { - it.bind() - }, - FxLaws.eager, Either, Int>( - Arb.int().map(::Right), - ARB.map { it }, - Either::equals, - either::eager - ) { - it.bind() - }*/ + MonoidLaws(0.right(), { x, y -> x.combine(y, String::plus, Int::plus) }, ARB) ) "isLeft should return true if Left and false if Right" { diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EndoTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EndoTest.kt index 21232576398..e68fec6f230 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EndoTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/EndoTest.kt @@ -3,7 +3,6 @@ package arrow.core import arrow.core.test.endo import arrow.core.test.laws.MonoidLaws import arrow.core.test.testLaws -import arrow.typeclasses.Monoid import io.kotest.core.spec.style.StringSpec import io.kotest.property.Arb import io.kotest.property.arbitrary.int @@ -11,7 +10,7 @@ import io.kotest.property.arbitrary.int class EndoTest : StringSpec({ testLaws( - MonoidLaws.laws(Monoid.endo(), Arb.endo(Arb.int())) { a, b -> + MonoidLaws(Endo(::identity), { f, g -> Endo(f.f.compose(g.f)) }, Arb.endo(Arb.int())) { a, b -> a.f(1) == b.f(1) } ) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IorTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IorTest.kt index b7ebbeb1b48..b99bc13d75d 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IorTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IorTest.kt @@ -18,486 +18,482 @@ import io.kotest.property.checkAll class IorTest : StringSpec({ - val ARB = Arb.ior(Arb.string(), Arb.int()) + val ARB = Arb.ior(Arb.string(), Arb.int()) - testLaws( - SemigroupLaws.laws(Semigroup.ior(Semigroup.string(), Semigroup.int()), ARB) - ) + testLaws( + SemigroupLaws({ a, b -> + a.combine(b, String::plus, Int::plus) + }, ARB) + ) - val nullableLongSemigroup = object : Semigroup { - override fun Long?.combine(b: Long?): Long? = - Nullable.zip(this, b) { a, bb -> a + bb } - } + val nullableLongSemigroup = object : Semigroup { + override fun Long?.combine(b: Long?): Long? = + Nullable.zip(this, b) { a, bb -> a + bb } + } - "zip identity" { - checkAll(Arb.ior(Arb.long().orNull(), Arb.int().orNull())) { ior -> - val res = ior.zip(nullableLongSemigroup, Ior.Right(Unit)) { a, _ -> a } - res shouldBe ior - } + "zip identity" { + checkAll(Arb.ior(Arb.long().orNull(), Arb.int().orNull())) { ior -> + val res = ior.zip(nullableLongSemigroup, Ior.Right(Unit)) { a, _ -> a } + res shouldBe ior } + } - "zip is derived from flatMap" { - checkAll( - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()), - Arb.ior(Arb.long().orNull(), Arb.int().orNull()) + "zip is derived from flatMap" { + checkAll( + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()), + Arb.ior(Arb.long().orNull(), Arb.int().orNull()) + ) { a, b, c, d, e, f, g, h, i, j -> + val res = a.zip( + nullableLongSemigroup, + b, c, d, e, f, g, h, i, j ) { a, b, c, d, e, f, g, h, i, j -> - val res = a.zip( - nullableLongSemigroup, - b, c, d, e, f, g, h, i, j - ) { a, b, c, d, e, f, g, h, i, j -> - Nullable.zip( - a, - b, - c, - d, - e, - f, - g, - h, - i, - j - ) { a, b, c, d, e, f, g, h, i, j -> a + b + c + d + e + f + g + h + i + j } + Nullable.zip( + a, + b, + c, + d, + e, + f, + g, + h, + i, + j + ) { a, b, c, d, e, f, g, h, i, j -> a + b + c + d + e + f + g + h + i + j } + } + + val expected = listOf(a, b, c, d, e, f, g, h, i, j) + .fold, Ior>(Ior.Right(0)) { acc, ior -> + val mid = acc.flatMap(nullableLongSemigroup) { a -> ior.map { b -> Nullable.zip(a, b) { a, b -> a + b } } } + mid } - val expected = listOf(a, b, c, d, e, f, g, h, i, j) - .fold, Ior>(Ior.Right(0)) { acc, ior -> - val mid = acc.flatMap(nullableLongSemigroup) { a -> ior.map { b -> Nullable.zip(a, b) { a, b -> a + b } } } - mid - } - - res shouldBe expected - } + res shouldBe expected } + } - "zip should combine left values in correct order" { - Ior.Both("fail1", -1).zip( - Semigroup.string(), - Ior.Left("fail2"), - Ior.Right(-1) - ) { _, _, _ -> "success!" } shouldBe Ior.Left("fail1fail2") - } + "zip should combine left values in correct order" { + Ior.Both("fail1", -1).zip( + Semigroup.string(), + Ior.Left("fail2"), + Ior.Right(-1) + ) { _, _, _ -> "success!" } shouldBe Ior.Left("fail1fail2") + } - "bimap() should allow modify both value" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Right(b).bimap({ "5" }, { a * 2 }) shouldBe Ior.Right(a * 2) - Ior.Left(a).bimap({ a * 3 }, { "5" }) shouldBe Ior.Left(a * 3) - Ior.Both(a, b).bimap({ 2 }, { "power of $it" }) shouldBe Ior.Both(2, "power of $b") - } + "bimap() should allow modify both value" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Right(b).bimap({ "5" }, { a * 2 }) shouldBe Ior.Right(a * 2) + Ior.Left(a).bimap({ a * 3 }, { "5" }) shouldBe Ior.Left(a * 3) + Ior.Both(a, b).bimap({ 2 }, { "power of $it" }) shouldBe Ior.Both(2, "power of $b") } + } - "map() should just right side of an Ior" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).map{ l:String -> l.length } shouldBe Ior.Left(a) - Ior.Right(b).map{ it.length } shouldBe Ior.Right(b.length) - Ior.Both(a, b).map{ it.length } shouldBe Ior.Both(a, b.length) - } + "map() should just right side of an Ior" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).map { l: String -> l.length } shouldBe Ior.Left(a) + Ior.Right(b).map { it.length } shouldBe Ior.Right(b.length) + Ior.Both(a, b).map { it.length } shouldBe Ior.Both(a, b.length) } + } - "mapLeft() should modify only left value" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Right(b).mapLeft { a * 2 } shouldBe Ior.Right(b) - Ior.Left(a).mapLeft { b } shouldBe Ior.Left(b) - Ior.Both(a, b).mapLeft { "power of $it" } shouldBe Ior.Both("power of $a", b) - } + "mapLeft() should modify only left value" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Right(b).mapLeft { a * 2 } shouldBe Ior.Right(b) + Ior.Left(a).mapLeft { b } shouldBe Ior.Left(b) + Ior.Both(a, b).mapLeft { "power of $it" } shouldBe Ior.Both("power of $a", b) } + } - "swap() should interchange value" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Both(a, b).swap() shouldBe Ior.Both(b, a) - } + "swap() should interchange value" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Both(a, b).swap() shouldBe Ior.Both(b, a) } + } - "swap() should interchange entity" { - checkAll(Arb.int()) { a: Int -> - Ior.Left(a).swap() shouldBe Ior.Right(a) - Ior.Right(a).swap() shouldBe Ior.Left(a) - } + "swap() should interchange entity" { + checkAll(Arb.int()) { a: Int -> + Ior.Left(a).swap() shouldBe Ior.Right(a) + Ior.Right(a).swap() shouldBe Ior.Left(a) } + } - "unwrap() should return the isomorphic either" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).unwrap() shouldBe Either.Left(Either.Left(a)) - Ior.Right(b).unwrap() shouldBe Either.Left(Either.Right(b)) - Ior.Both(a, b).unwrap() shouldBe Either.Right(Pair(a, b)) - } + "unwrap() should return the isomorphic either" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).unwrap() shouldBe Either.Left(Either.Left(a)) + Ior.Right(b).unwrap() shouldBe Either.Left(Either.Right(b)) + Ior.Both(a, b).unwrap() shouldBe Either.Right(Pair(a, b)) } + } - "padNull() should return the correct Pair of nullables" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).padNull() shouldBe Pair(a, null) - Ior.Right(b).padNull() shouldBe Pair(null, b) - Ior.Both(a, b).padNull() shouldBe Pair(a, b) - } + "padNull() should return the correct Pair of nullables" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).padNull() shouldBe Pair(a, null) + Ior.Right(b).padNull() shouldBe Pair(null, b) + Ior.Both(a, b).padNull() shouldBe Pair(a, b) } + } - "toEither() should convert values into a valid Either" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).toEither() shouldBe Either.Left(a) - Ior.Right(b).toEither() shouldBe Either.Right(b) - Ior.Both(a, b).toEither() shouldBe Either.Right(b) - } + "toEither() should convert values into a valid Either" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).toEither() shouldBe Either.Left(a) + Ior.Right(b).toEither() shouldBe Either.Right(b) + Ior.Both(a, b).toEither() shouldBe Either.Right(b) } + } - "orNull() should convert right values into a nullable" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).orNull() shouldBe null - Ior.Right(b).orNull() shouldBe b - Ior.Both(a, b).orNull() shouldBe b - } + "orNull() should convert right values into a nullable" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).orNull() shouldBe null + Ior.Right(b).orNull() shouldBe b + Ior.Both(a, b).orNull() shouldBe b } + } - "getOrNull() should convert right values into a nullable, or return null if left" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).getOrNull() shouldBe null - Ior.Right(b).getOrNull() shouldBe b - Ior.Both(a, b).getOrNull() shouldBe b - } + "getOrNull() should convert right values into a nullable, or return null if left" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).getOrNull() shouldBe null + Ior.Right(b).getOrNull() shouldBe b + Ior.Both(a, b).getOrNull() shouldBe b } + } "leftOrNull() should convert left values into a nullable" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).leftOrNull() shouldBe a - Ior.Right(b).leftOrNull() shouldBe null - Ior.Both(a, b).leftOrNull() shouldBe a - } + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).leftOrNull() shouldBe a + Ior.Right(b).leftOrNull() shouldBe null + Ior.Both(a, b).leftOrNull() shouldBe a } + } - "toValidated() should convert values into a valid Validated" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.Left(a).toValidated() shouldBe Invalid(a) - Ior.Right(b).toValidated() shouldBe Valid(b) - Ior.Both(a, b).toValidated() shouldBe Valid(b) - } + "toValidated() should convert values into a valid Validated" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.Left(a).toValidated() shouldBe Invalid(a) + Ior.Right(b).toValidated() shouldBe Valid(b) + Ior.Both(a, b).toValidated() shouldBe Valid(b) } + } - "fromNullables() should build a correct Ior" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - Ior.fromNullables(a, null) shouldBe Ior.Left(a) - Ior.fromNullables(a, b) shouldBe Ior.Both(a, b) - Ior.fromNullables(null, b) shouldBe Ior.Right(b) - Ior.fromNullables(null, null) shouldBe null - } + "fromNullables() should build a correct Ior" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.fromNullables(a, null) shouldBe Ior.Left(a) + Ior.fromNullables(a, b) shouldBe Ior.Both(a, b) + Ior.fromNullables(null, b) shouldBe Ior.Right(b) + Ior.fromNullables(null, null) shouldBe null } + } - "leftNel() should build a correct Ior" { - checkAll(Arb.int()) { a: Int -> - Ior.leftNel(a) shouldBe Ior.Left(nonEmptyListOf(a)) - } + "leftNel() should build a correct Ior" { + checkAll(Arb.int()) { a: Int -> + Ior.leftNel(a) shouldBe Ior.Left(nonEmptyListOf(a)) } + } - "bothNel() should build a correct Ior" { - checkAll(Arb.int(), Arb.string()) { a: Int, b:String -> - Ior.bothNel(a, b) shouldBe Ior.Both(nonEmptyListOf(a), b) - } + "bothNel() should build a correct Ior" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + Ior.bothNel(a, b) shouldBe Ior.Both(nonEmptyListOf(a), b) } + } - "lift(f) should apply the input function to an Ior correctly" { - checkAll(Arb.string()) { a: String -> - val f = Ior.lift { s: String -> "Hello $s" } - f(Ior.Right(a)) shouldBe Ior.Right("Hello $a") - } + "lift(f) should apply the input function to an Ior correctly" { + checkAll(Arb.string()) { a: String -> + val f = Ior.lift { s: String -> "Hello $s" } + f(Ior.Right(a)) shouldBe Ior.Right("Hello $a") } + } - "lift(fa, fb) should apply the input functions to an Ior correctly" { - checkAll(Arb.string(), Arb.string()) { a: String, b:String -> - val fa = { s1: String -> "Hello $s1" } - val fb = { s2: String -> s2.length } - val f = Ior.lift(fa, fb) - f(Ior.Right(b)) shouldBe Ior.Right(b.length) - f(Ior.Left(a)) shouldBe Ior.Left("Hello $a") - f(Ior.Both(a, b)) shouldBe Ior.Both("Hello $a", b.length) - } + "lift(fa, fb) should apply the input functions to an Ior correctly" { + checkAll(Arb.string(), Arb.string()) { a: String, b: String -> + val fa = { s1: String -> "Hello $s1" } + val fb = { s2: String -> s2.length } + val f = Ior.lift(fa, fb) + f(Ior.Right(b)) shouldBe Ior.Right(b.length) + f(Ior.Left(a)) shouldBe Ior.Left("Hello $a") + f(Ior.Both(a, b)) shouldBe Ior.Both("Hello $a", b.length) } + } - "foldLeft should fold an Ior correctly" { - checkAll(Arb.int(), Arb.string()) { a: Int, b:String -> - val left = Ior.Left(a) - val right = Ior.Right(b) - val both = Ior.Both(a, b) - val f = {c: Int, b: String -> c + b.length} - left.foldLeft(0, f) shouldBe 0 - right.foldLeft(0, f) shouldBe b.length - both.foldLeft(0, f) shouldBe b.length - } + "foldLeft should fold an Ior correctly" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val left = Ior.Left(a) + val right = Ior.Right(b) + val both = Ior.Both(a, b) + val f = { c: Int, b: String -> c + b.length } + left.foldLeft(0, f) shouldBe 0 + right.foldLeft(0, f) shouldBe b.length + both.foldLeft(0, f) shouldBe b.length } + } "getOrElse() should return value" { - checkAll(Arb.int(), Arb.int()) { a: Int, b: Int -> - Ior.Right(a).getOrElse { b } shouldBe a - Ior.Left(a).getOrElse { b } shouldBe b - Ior.Both(a, b).getOrElse { a * 2 } shouldBe b - } - } - - "Ior.monad.flatMap should combine left values" { - val ior1 = Ior.Both(3, "Hello, world!") - val iorResult = ior1.flatMap(Semigroup.int()) { Ior.Left(7) } - iorResult shouldBe Ior.Left(10) + checkAll(Arb.int(), Arb.int()) { a: Int, b: Int -> + Ior.Right(a).getOrElse { b } shouldBe a + Ior.Left(a).getOrElse { b } shouldBe b + Ior.Both(a, b).getOrElse { a * 2 } shouldBe b } + } + "Ior.monad.flatMap should combine left values" { + val ior1 = Ior.Both(3, "Hello, world!") + val iorResult = ior1.flatMap(Int::plus) { Ior.Left(7) } + iorResult shouldBe Ior.Left(10) + } "Ior.monad.flatMap should combine Both values" { val ior1 = Ior.Both(3, "Hello, world!") - val iorResult1 = ior1.flatMap(Semigroup.int()) { Ior.Both(7, "Again!") } + val iorResult1 = ior1.flatMap(Int::plus) { Ior.Both(7, "Again!") } iorResult1 shouldBe Ior.Both(10, "Again!") - val iorResult2 = ior1.flatMap(Semigroup.int()) { Ior.Right("Again!") } + val iorResult2 = ior1.flatMap(Int::plus) { Ior.Right("Again!") } iorResult2 shouldBe Ior.Both(3, "Again!") - } - - "combine cases for Semigroup" { - Semigroup.ior(Semigroup.string(), Semigroup.int()).run { - forAll( - row("Hello, ".leftIor(), Ior.Left("Arrow!"), Ior.Left("Hello, Arrow!")), - row(Ior.Left("Hello"), Ior.Right(2020), Ior.Both("Hello", 2020)), - row(Ior.Left("Hello, "), Ior.Both("number", 1), Ior.Both("Hello, number", 1)), - row(Ior.Right(9000), Ior.Left("Over"), Ior.Both("Over", 9000)), - row(Ior.Right(9000), Ior.Right(1), Ior.Right(9001)), - row(Ior.Right(8000), Ior.Both("Over", 1000), Ior.Both("Over", 9000)), - row(Ior.Both("Hello ", 1), Ior.Left("number"), Ior.Both("Hello number", 1)), - row(Ior.Both("Hello number", 1), Ior.Right(1), Ior.Both("Hello number", 2)), - row(Ior.Both("Hello ", 1), Ior.Both("number", 1), Ior.Both("Hello number", 2)) - ) { a, b, expectedResult -> - a + b shouldBe expectedResult - } - } + forAll( + row("Hello, ".leftIor(), Ior.Left("Arrow!"), Ior.Left("Hello, Arrow!")), + row(Ior.Left("Hello"), Ior.Right(2020), Ior.Both("Hello", 2020)), + row(Ior.Left("Hello, "), Ior.Both("number", 1), Ior.Both("Hello, number", 1)), + row(Ior.Right(9000), Ior.Left("Over"), Ior.Both("Over", 9000)), + row(Ior.Right(9000), Ior.Right(1), Ior.Right(9001)), + row(Ior.Right(8000), Ior.Both("Over", 1000), Ior.Both("Over", 9000)), + row(Ior.Both("Hello ", 1), Ior.Left("number"), Ior.Both("Hello number", 1)), + row(Ior.Both("Hello number", 1), Ior.Right(1), Ior.Both("Hello number", 2)), + row(Ior.Both("Hello ", 1), Ior.Both("number", 1), Ior.Both("Hello number", 2)) + ) { a, b, expectedResult -> + a.combine(b, String::plus, Int::plus) shouldBe expectedResult } + } - "traverse should wrap ior in a list" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "traverse should wrap ior in a list" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.traverse { listOf(it) } shouldBe listOf(Ior.Left(a)) - iorR.traverse { listOf(it) } shouldBe listOf(Ior.Right(b)) - iorBoth.traverse { listOf(it) } shouldBe listOf(Ior.Both(a, b)) - } + iorL.traverse { listOf(it) } shouldBe listOf(Ior.Left(a)) + iorR.traverse { listOf(it) } shouldBe listOf(Ior.Right(b)) + iorBoth.traverse { listOf(it) } shouldBe listOf(Ior.Both(a, b)) } + } - "sequence should be consistent with traverse" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.map { listOf(it) }.sequence() shouldBe ior.traverse { listOf(it) } - } + "sequence should be consistent with traverse" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.map { listOf(it) }.sequence() shouldBe ior.traverse { listOf(it) } } + } - "traverseNullable should wrap ior in a nullable" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "traverseNullable should wrap ior in a nullable" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.traverseNullable { it } shouldBe Ior.Left(a) - iorR.traverseNullable { it } shouldBe Ior.Right(b) - iorBoth.traverseNullable { it } shouldBe Ior.Both(a, b) + iorL.traverseNullable { it } shouldBe Ior.Left(a) + iorR.traverseNullable { it } shouldBe Ior.Right(b) + iorBoth.traverseNullable { it } shouldBe Ior.Both(a, b) - iorL.traverseNullable { null } shouldBe Ior.Left(a) - iorR.traverseNullable { null } shouldBe null - iorBoth.traverseNullable { null } shouldBe null - } + iorL.traverseNullable { null } shouldBe Ior.Left(a) + iorR.traverseNullable { null } shouldBe null + iorBoth.traverseNullable { null } shouldBe null } + } - "sequence for Nullable should be consistent with traverseNullable" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.map { it }.sequence() shouldBe ior.traverseNullable { it } - ior.map { null }.sequence() shouldBe ior.traverseNullable { null } - } + "sequence for Nullable should be consistent with traverseNullable" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.map { it }.sequence() shouldBe ior.traverseNullable { it } + ior.map { null }.sequence() shouldBe ior.traverseNullable { null } } + } - "traverseOption should wrap ior in an Option" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "traverseOption should wrap ior in an Option" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.traverse { Some(it) } shouldBe Some(Ior.Left(a)) - iorR.traverse { Some(it) } shouldBe Some(Ior.Right(b)) - iorBoth.traverse { Some(it) } shouldBe Some(Ior.Both(a, b)) - } + iorL.traverse { Some(it) } shouldBe Some(Ior.Left(a)) + iorR.traverse { Some(it) } shouldBe Some(Ior.Right(b)) + iorBoth.traverse { Some(it) } shouldBe Some(Ior.Both(a, b)) } + } - "sequenceOption should be consistent with traverseOption" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.map { Some(it) }.sequence() shouldBe ior.traverse { Some(it) } - } + "sequenceOption should be consistent with traverseOption" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.map { Some(it) }.sequence() shouldBe ior.traverse { Some(it) } } + } - "traverseEither should wrap ior in an Option" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "traverseEither should wrap ior in an Option" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.traverse { it.right() } shouldBe Either.Right(Ior.Left(a)) - iorR.traverse { it.right() } shouldBe Either.Right(Ior.Right(b)) - iorBoth.traverse { it.right() } shouldBe Either.Right(Ior.Both(a, b)) - } + iorL.traverse { it.right() } shouldBe Either.Right(Ior.Left(a)) + iorR.traverse { it.right() } shouldBe Either.Right(Ior.Right(b)) + iorBoth.traverse { it.right() } shouldBe Either.Right(Ior.Both(a, b)) } + } - "sequenceEither should be consistent with traverseEither" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.map { it.right() }.sequence() shouldBe ior.traverse { it.right() } - } + "sequenceEither should be consistent with traverseEither" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.map { it.right() }.sequence() shouldBe ior.traverse { it.right() } } + } - "bitraverse should wrap ior in a list" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "bitraverse should wrap ior in a list" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.bitraverse({ listOf(it, 2, 3) }, { listOf(it) }) shouldBe listOf(Ior.Left(a), Ior.Left(2), Ior.Left(3)) - iorR.bitraverse({ listOf(it, 2, 3) }, { listOf(it) }) shouldBe listOf(Ior.Right(b)) - iorBoth.bitraverse({ listOf(it, 2, 3) }, { listOf(it, 4, 5) }) shouldBe - listOf(Ior.Both(a, b), Ior.Both(2, 4), Ior.Both(3, 5)) - } + iorL.bitraverse({ listOf(it, 2, 3) }, { listOf(it) }) shouldBe listOf(Ior.Left(a), Ior.Left(2), Ior.Left(3)) + iorR.bitraverse({ listOf(it, 2, 3) }, { listOf(it) }) shouldBe listOf(Ior.Right(b)) + iorBoth.bitraverse({ listOf(it, 2, 3) }, { listOf(it, 4, 5) }) shouldBe + listOf(Ior.Both(a, b), Ior.Both(2, 4), Ior.Both(3, 5)) } + } - "bisequence should be consistent with bitraverse" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.bimap({ listOf(it) }, { listOf(it) }).bisequence() shouldBe - ior.bitraverse({ listOf(it) }, { listOf(it) }) - } + "bisequence should be consistent with bitraverse" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.bimap({ listOf(it) }, { listOf(it) }).bisequence() shouldBe + ior.bitraverse({ listOf(it) }, { listOf(it) }) } + } - "bitraverseOption should wrap ior in an Option" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "bitraverseOption should wrap ior in an Option" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.bitraverseOption({ None }, { Some(it) }) shouldBe None - iorR.bitraverseOption({ None }, { Some(it) }) shouldBe Some(Ior.Right(b)) - iorBoth.bitraverseOption({ None }, { Some(it) }) shouldBe None - } + iorL.bitraverseOption({ None }, { Some(it) }) shouldBe None + iorR.bitraverseOption({ None }, { Some(it) }) shouldBe Some(Ior.Right(b)) + iorBoth.bitraverseOption({ None }, { Some(it) }) shouldBe None } + } - "bisequenceOption should be consistent with bitraverseOption" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.bimap({ None }, { Some(it) }).bisequenceOption() shouldBe - ior.bitraverseOption({ None }, { Some(it) }) - } + "bisequenceOption should be consistent with bitraverseOption" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.bimap({ None }, { Some(it) }).bisequenceOption() shouldBe + ior.bitraverseOption({ None }, { Some(it) }) } + } - "bitraverseEither should wrap ior in an Either" { - checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> - val iorL: Ior = a.leftIor() - val iorR: Ior = b.rightIor() - val iorBoth: Ior = (a to b).bothIor() + "bitraverseEither should wrap ior in an Either" { + checkAll(Arb.int(), Arb.string()) { a: Int, b: String -> + val iorL: Ior = a.leftIor() + val iorR: Ior = b.rightIor() + val iorBoth: Ior = (a to b).bothIor() - iorL.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Left(a) - iorR.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Right(Ior.Right(b)) - iorBoth.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Left(a) - } + iorL.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Left(a) + iorR.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Right(Ior.Right(b)) + iorBoth.bitraverseEither({ it.left() }, { it.right() }) shouldBe Either.Left(a) } + } - "bisequenceEither should be consistent with bitraverseEither" { - checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.bimap({ it.left() }, { it.right() }).bisequenceEither() shouldBe - ior.bitraverseEither({ it.left() }, { it.right() }) - } + "bisequenceEither should be consistent with bitraverseEither" { + checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> + ior.bimap({ it.left() }, { it.right() }).bisequenceEither() shouldBe + ior.bitraverseEither({ it.left() }, { it.right() }) } + } - "isLeft() should return true with Left and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - Ior.Left(a).isLeft() shouldBe true - Ior.Right(b).isLeft() shouldBe false - Ior.Both(a, b).isLeft() shouldBe false - } + "isLeft() should return true with Left and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + Ior.Left(a).isLeft() shouldBe true + Ior.Right(b).isLeft() shouldBe false + Ior.Both(a, b).isLeft() shouldBe false } + } - "isRight() should return true with Right and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - Ior.Left(a).isRight() shouldBe false - Ior.Right(b).isRight() shouldBe true - Ior.Both(a, b).isRight() shouldBe false - } + "isRight() should return true with Right and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + Ior.Left(a).isRight() shouldBe false + Ior.Right(b).isRight() shouldBe true + Ior.Both(a, b).isRight() shouldBe false } + } - "isBoth() should return true with Both and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - Ior.Left(a).isBoth() shouldBe false - Ior.Right(b).isBoth() shouldBe false - Ior.Both(a, b).isBoth() shouldBe true - } + "isBoth() should return true with Both and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + Ior.Left(a).isBoth() shouldBe false + Ior.Right(b).isBoth() shouldBe false + Ior.Both(a, b).isBoth() shouldBe true } + } - "isLeft(predicate) should return true with Left, if satisfies the predicate, and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - val predicate = {i: Int -> i % 2 == 0} + "isLeft(predicate) should return true with Left, if satisfies the predicate, and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + val predicate = { i: Int -> i % 2 == 0 } - if(predicate(a)) Ior.Left(a).isLeft(predicate) shouldBe true - else Ior.Left(a).isLeft(predicate) shouldBe false + if (predicate(a)) Ior.Left(a).isLeft(predicate) shouldBe true + else Ior.Left(a).isLeft(predicate) shouldBe false - Ior.Right(b).isLeft(predicate) shouldBe false - Ior.Both(a, b).isLeft(predicate) shouldBe false - } + Ior.Right(b).isLeft(predicate) shouldBe false + Ior.Both(a, b).isLeft(predicate) shouldBe false } + } - "isRight(predicate) should return true with Right, if satisfies the predicate, and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - val predicate = {s: String -> s.length % 2 == 0} + "isRight(predicate) should return true with Right, if satisfies the predicate, and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + val predicate = { s: String -> s.length % 2 == 0 } - if(predicate(b)) Ior.Right(b).isRight(predicate) shouldBe true - else Ior.Right(b).isRight(predicate) shouldBe false + if (predicate(b)) Ior.Right(b).isRight(predicate) shouldBe true + else Ior.Right(b).isRight(predicate) shouldBe false - Ior.Left(a).isRight(predicate) shouldBe false - Ior.Both(a, b).isRight(predicate) shouldBe false - } + Ior.Left(a).isRight(predicate) shouldBe false + Ior.Both(a, b).isRight(predicate) shouldBe false } + } - "isBoth(predicate) should return true with Both, if satisfies the predicate, and false otherwise"{ - checkAll(Arb.int(), Arb.string()){ a, b -> - val leftPredicate = {i: Int-> i % 2 == 0} - val rightPredicate = {s: String -> s.length % 2 == 0} - if(leftPredicate(a) && rightPredicate(b)) Ior.Both(a, b).isBoth(leftPredicate, rightPredicate) shouldBe true - else Ior.Both(a, b).isBoth(leftPredicate, rightPredicate) shouldBe false + "isBoth(predicate) should return true with Both, if satisfies the predicate, and false otherwise" { + checkAll(Arb.int(), Arb.string()) { a, b -> + val leftPredicate = { i: Int -> i % 2 == 0 } + val rightPredicate = { s: String -> s.length % 2 == 0 } + if (leftPredicate(a) && rightPredicate(b)) Ior.Both(a, b).isBoth(leftPredicate, rightPredicate) shouldBe true + else Ior.Both(a, b).isBoth(leftPredicate, rightPredicate) shouldBe false - Ior.Left(a).isBoth(leftPredicate, rightPredicate) shouldBe false - Ior.Right(b).isBoth(leftPredicate, rightPredicate) shouldBe false - } + Ior.Left(a).isBoth(leftPredicate, rightPredicate) shouldBe false + Ior.Right(b).isBoth(leftPredicate, rightPredicate) shouldBe false } + } - "widen should retype Right" { - checkAll(Arb.int(), Arb.string()) { a, b -> - val ior = Ior.Both(a, b) - ior.widen().shouldBeInstanceOf>() - } + "widen should retype Right" { + checkAll(Arb.int(), Arb.string()) { a, b -> + val ior = Ior.Both(a, b) + ior.widen().shouldBeInstanceOf>() } + } - "compareTo should compare 2 Ior" { - val left1 = Ior.Left(1) - val left2 = Ior.Left(2) - val right1 = Ior.Right(1) - val right2 = Ior.Right(2) - val both11 = Ior.Both(1, 1) - val both22 = Ior.Both(2, 2) - left1.compareTo(left2) shouldBe -1 - left1.compareTo(left1) shouldBe 0 - left2.compareTo(left1) shouldBe 1 - left1.compareTo(right1) shouldBe -1 - left1.compareTo(both11) shouldBe -1 - right1.compareTo(right2) shouldBe -1 - right1.compareTo(right1) shouldBe 0 - right2.compareTo(right1) shouldBe 1 - right1.compareTo(left1) shouldBe 1 - right1.compareTo(both11) shouldBe -1 - both11.compareTo(both22) shouldBe -1 - both11.compareTo(both11) shouldBe 0 - both22.compareTo(both11) shouldBe 1 - both11.compareTo(left1) shouldBe 1 - both11.compareTo(right1) shouldBe 1 - } + "compareTo should compare 2 Ior" { + val left1 = Ior.Left(1) + val left2 = Ior.Left(2) + val right1 = Ior.Right(1) + val right2 = Ior.Right(2) + val both11 = Ior.Both(1, 1) + val both22 = Ior.Both(2, 2) + left1.compareTo(left2) shouldBe -1 + left1.compareTo(left1) shouldBe 0 + left2.compareTo(left1) shouldBe 1 + left1.compareTo(right1) shouldBe -1 + left1.compareTo(both11) shouldBe -1 + right1.compareTo(right2) shouldBe -1 + right1.compareTo(right1) shouldBe 0 + right2.compareTo(right1) shouldBe 1 + right1.compareTo(left1) shouldBe 1 + right1.compareTo(both11) shouldBe -1 + both11.compareTo(both22) shouldBe -1 + both11.compareTo(both11) shouldBe 0 + both22.compareTo(both11) shouldBe 1 + both11.compareTo(left1) shouldBe 1 + both11.compareTo(right1) shouldBe 1 + } }) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ListKTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ListKTest.kt index 964a5e298f3..3aacf49c54c 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ListKTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ListKTest.kt @@ -2,7 +2,6 @@ package arrow.core import arrow.core.test.laws.MonoidLaws import arrow.core.test.testLaws -import arrow.typeclasses.Monoid import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import io.kotest.property.Arb @@ -12,7 +11,7 @@ import io.kotest.property.checkAll class ListKTest : StringSpec({ - testLaws(MonoidLaws.laws(Monoid.list(), Arb.list(Arb.int()))) + testLaws(MonoidLaws(emptyList(), List::plus, Arb.list(Arb.int()))) "mapNotNull() should map list and filter out null values" { checkAll(Arb.list(Arb.int())) { listk -> diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/MapKTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/MapKTest.kt index adfac96fe4f..1d10d569c2a 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/MapKTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/MapKTest.kt @@ -5,7 +5,6 @@ import arrow.core.test.laws.MonoidLaws import arrow.core.test.longSmall import arrow.core.test.nonEmptyList import arrow.core.test.testLaws -import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup import io.kotest.core.spec.style.StringSpec import io.kotest.property.Arb @@ -20,8 +19,9 @@ import io.kotest.property.checkAll class MapKTest : StringSpec({ testLaws( - MonoidLaws.laws( - Monoid.map(Semigroup.int()), + MonoidLaws( + emptyMap(), + { a, b -> a.combine(b, Int::plus) }, Arb.map(Arb.longSmall(), Arb.intSmall(), maxSize = 10) ) ) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/NonEmptyListTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/NonEmptyListTest.kt index fee42621686..aab8cbdd9ac 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/NonEmptyListTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/NonEmptyListTest.kt @@ -18,7 +18,7 @@ import kotlin.math.min class NonEmptyListTest : StringSpec({ - testLaws(SemigroupLaws.laws(Semigroup.nonEmptyList(), Arb.nonEmptyList(Arb.int()))) + testLaws(SemigroupLaws(NonEmptyList::plus, Arb.nonEmptyList(Arb.int()))) "iterable.toNonEmptyListOrNull should round trip" { checkAll(Arb.nonEmptyList(Arb.int())) { nonEmptyList -> @@ -109,8 +109,10 @@ class NonEmptyListTest : StringSpec({ "traverse for Validated stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() - val res = (0..20_000).traverse(Semigroup.string()) { - acc.add(it) + val res = (0..20_000) + .toNonEmptyListOrNull()!! + .traverse(Semigroup.string()) { + acc.add(it) Validated.Valid(it) } res shouldBe Validated.Valid(acc) @@ -129,13 +131,6 @@ class NonEmptyListTest : StringSpec({ } } - "sequence for Validated should be consistent with traverseValidated" { - checkAll(Arb.nonEmptyList(Arb.int())) { ints -> - ints.map { if (it % 2 == 0) Valid(it) else Invalid(it) }.sequence(Semigroup.int()) shouldBe - ints.traverse(Semigroup.int()) { if (it % 2 == 0) Valid(it) else Invalid(it) } - } - } - "can align lists with different lengths" { checkAll(Arb.nonEmptyList(Arb.boolean()), Arb.nonEmptyList(Arb.boolean())) { a, b -> a.align(b).size shouldBe max(a.size, b.size) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/OptionTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/OptionTest.kt index 2a7c1dc44f1..6a1d1b56181 100755 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/OptionTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/OptionTest.kt @@ -5,7 +5,6 @@ import arrow.core.continuations.option import arrow.core.test.laws.MonoidLaws import arrow.core.test.option import arrow.core.test.testLaws -import arrow.typeclasses.Monoid import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe @@ -23,23 +22,7 @@ class OptionTest : StringSpec({ val none: Option = None testLaws( - MonoidLaws.laws(Monoid.option(Monoid.int()), Arb.option(Arb.int())), - /*FxLaws.suspended, Option, String>( - Arb.string().map(Option.Companion::invoke), - Arb.option(Arb.string()), - Option::equals, - option::invoke - ) { - it.bind() - }, - FxLaws.eager, Option, String>( - Arb.string().map(Option.Companion::invoke), - Arb.option(Arb.string()), - Option::equals, - option::eager - ) { - it.bind() - }*/ + MonoidLaws(None, { x, y -> x.combine(y, Int::plus) }, Arb.option(Arb.int())) ) "ensure null in option computation" { diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/SequenceKTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/SequenceKTest.kt index 9b3dfaa8d8c..bf8b1d52ea1 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/SequenceKTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/SequenceKTest.kt @@ -1,11 +1,10 @@ package arrow.core -import arrow.typeclasses.Monoid -import arrow.typeclasses.Semigroup import arrow.core.test.laws.MonoidLaws import arrow.core.test.option import arrow.core.test.sequence import arrow.core.test.testLaws +import arrow.typeclasses.Semigroup import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.sequences.shouldBeEmpty import io.kotest.property.Arb @@ -20,7 +19,7 @@ import kotlin.math.min class SequenceKTest : StringSpec({ - testLaws(MonoidLaws.laws(Monoid.sequence(), Arb.sequence(Arb.int())) { s1, s2 -> s1.toList() == s2.toList() }) + testLaws(MonoidLaws(emptySequence(), { a, b -> sequenceOf(a, b).flatten()} , Arb.sequence(Arb.int())) { s1, s2 -> s1.toList() == s2.toList() }) "traverse for Either stack-safe" { // also verifies result order and execution order (l to r) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/extensions/NumberInstancesTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/extensions/NumberInstancesTest.kt index f300ead9275..3eeccaf00e8 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/extensions/NumberInstancesTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/extensions/NumberInstancesTest.kt @@ -3,69 +3,30 @@ package arrow.core.extensions import arrow.core.test.laws.MonoidLaws import arrow.core.test.laws.SemiringLaws import arrow.core.test.testLaws -import arrow.typeclasses.Monoid -import arrow.typeclasses.Semiring import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe import io.kotest.property.Arb import io.kotest.property.arbitrary.byte import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.long import io.kotest.property.arbitrary.short -import io.kotest.property.checkAll class NumberInstancesTest : StringSpec({ fun testAllLaws( - SG: Semiring, - M: Monoid, + zero: F, + combine: (F, F) -> F, + one: F, + combineMultiplicate: (F, F) -> F, GEN: Arb, eq: (F, F) -> Boolean = { a, b -> a == b } ) { - testLaws(SemiringLaws.laws(SG, GEN, eq)) - testLaws(MonoidLaws.laws(M, GEN, eq)) + testLaws(SemiringLaws(zero, combine, one, combineMultiplicate, GEN, eq)) + testLaws(MonoidLaws(zero, combine, GEN, eq)) } - testAllLaws(Semiring.byte(), Monoid.byte(), Arb.byte()) - testAllLaws(Semiring.short(), Monoid.short(), Arb.short()) - testAllLaws(Semiring.int(), Monoid.int(), Arb.int()) - testAllLaws(Semiring.long(), Monoid.long(), Arb.long()) + testAllLaws(0, { x, y -> (x + y).toByte() }, 1, { x, y -> (x * y).toByte() }, Arb.byte()) + testAllLaws(0, { x, y -> (x + y).toShort() }, 1, { x, y -> (x * y).toShort() }, Arb.short()) + testAllLaws(0, { x, y -> x + y }, 1, { x, y -> x * y }, Arb.int()) + testAllLaws(0, { x, y -> x + y }, 1, { x, y -> x * y }, Arb.long()) - /** Semigroup specific instance check */ - - "should semigroup with the instance passed - int" { - checkAll(Arb.int()) { value: Int -> - val seen = Monoid.int().run { value.combine(value) } - val expected = value + value - - expected shouldBe seen - } - } - - "should semigroup with the instance passed - long" { - checkAll(Arb.long()) { value: Long -> - val seen = Monoid.long().run { value.combine(value) } - val expected = value + value - - expected shouldBe seen - } - } - - "should semigroup with the instance passed - short" { - checkAll(Arb.short()) { value: Short -> - val seen = Monoid.short().run { value.combine(value) } - val expected = (value + value).toShort() - - expected shouldBe seen - } - } - - "should semigroup with the instance passed - byte" { - checkAll(Arb.byte()) { value: Byte -> - val seen = Monoid.byte().run { value.combine(value) } - val expected = (value + value).toByte() - - expected shouldBe seen - } - } }) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/IorSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/IorSpec.kt index cd89e884741..67a3c3fb3cf 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/IorSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/raise/IorSpec.kt @@ -21,7 +21,7 @@ import kotlinx.coroutines.awaitAll ) class IorSpec : StringSpec({ "Accumulates" { - ior(Semigroup.string()) { + ior(String::plus) { val one = Ior.Both("Hello", 1).bind() val two = Ior.Both(", World!", 2).bind() one + two @@ -29,7 +29,7 @@ class IorSpec : StringSpec({ } "Accumulates and short-circuits with Left" { - ior(Semigroup.string()) { + ior(String::plus) { val one = Ior.Both("Hello", 1).bind() val two: Int = Ior.Left(", World!").bind() one + two @@ -37,16 +37,16 @@ class IorSpec : StringSpec({ } "Accumulates with Either" { - ior(Semigroup.string()) { + ior(String::plus) { val one = Ior.Both("Hello", 1).bind() - val two: Int = Either.Left(", World!").bind() + val two: Int = Either.Left(", World!").bind() one + two } shouldBe Ior.Left("Hello, World!") } "Concurrent - arrow.ior bind" { checkAll(Arb.list(Arb.string()).filter(List::isNotEmpty)) { strs -> - ior(Semigroup.list()) { + ior(List::plus) { strs.mapIndexed { index, s -> async { Ior.Both(listOf(s), index).bind() } }.awaitAll() } .mapLeft { it.toSet() } shouldBe Ior.Both(strs.toSet(), strs.indices.toList()) @@ -54,7 +54,7 @@ class IorSpec : StringSpec({ } "Accumulates eagerly" { - ior(Semigroup.string()) { + ior(String::plus) { val one = Ior.Both("Hello", 1).bind() val two = Ior.Both(", World!", 2).bind() one + two @@ -62,9 +62,9 @@ class IorSpec : StringSpec({ } "Accumulates with Either eagerly" { - ior(Semigroup.string()) { + ior(String::plus) { val one = Ior.Both("Hello", 1).bind() - val two: Int = Either.Left(", World!").bind() + val two: Int = Either.Left(", World!").bind() one + two } shouldBe Ior.Left("Hello, World!") } @@ -72,7 +72,7 @@ class IorSpec : StringSpec({ "Ior rethrows exception" { val boom = RuntimeException("Boom!") shouldThrow { - ior(Semigroup.string()) { + ior(String::plus) { throw boom } }.message shouldBe "Boom!" diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Laws.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Laws.kt index f4c822988f9..b2383454f66 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Laws.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Laws.kt @@ -7,11 +7,17 @@ import io.kotest.core.spec.style.scopes.StringSpecScope import io.kotest.core.spec.style.scopes.addTest import io.kotest.core.test.TestContext +interface LawSet { + val laws: List +} + data class Law(val name: String, val test: suspend TestContext.() -> Unit) fun A.equalUnderTheLaw(b: A, f: (A, A) -> Boolean = { x, y -> x == y }): Boolean = if (f(this, b)) true else fail("Found $this but expected: $b") +fun StringSpec.testLaws(lawSet: LawSet): Unit = testLaws(lawSet.laws) + fun StringSpec.testLaws(vararg laws: List): Unit = laws .flatMap { list: List -> list.asIterable() } .distinctBy { law: Law -> law.name } diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/MonoidLaws.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/MonoidLaws.kt index 696aa891f71..c3fd565d3a1 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/MonoidLaws.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/MonoidLaws.kt @@ -1,6 +1,7 @@ package arrow.core.test.laws import arrow.core.test.Law +import arrow.core.test.LawSet import arrow.core.test.equalUnderTheLaw import arrow.typeclasses.Monoid import io.kotest.property.Arb @@ -9,32 +10,37 @@ import io.kotest.matchers.shouldBe import io.kotest.property.PropertyContext import io.kotest.property.arbitrary.list -object MonoidLaws { +data class MonoidLaws( + val empty: F, + val combine: (F, F) -> F, + val GEN: Arb, + val eq: (F, F) -> Boolean = { a, b -> a == b } +): LawSet { - fun laws(M: Monoid, GEN: Arb, eq: (F, F) -> Boolean = { a, b -> a == b }): List = - SemigroupLaws.laws(M, GEN, eq) + + override val laws: List = + SemigroupLaws(combine, GEN, eq).laws + listOf( - Law("Monoid Laws: Left identity") { M.monoidLeftIdentity(GEN, eq) }, - Law("Monoid Laws: Right identity") { M.monoidRightIdentity(GEN, eq) }, - Law("Monoid Laws: combineAll should be derived") { M.combineAllIsDerived(GEN, eq) }, - Law("Monoid Laws: combineAll of empty list is empty") { M.combineAllOfEmptyIsEmpty(eq) } + Law("Monoid Laws: Left identity") { monoidLeftIdentity() }, + Law("Monoid Laws: Right identity") { monoidRightIdentity() }, + Law("Monoid Laws: combineAll should be derived") { combineAllIsDerived() }, + Law("Monoid Laws: combineAll of empty list is empty") { combineAllOfEmptyIsEmpty() } ) - private suspend fun Monoid.monoidLeftIdentity(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = + private suspend fun monoidLeftIdentity(): PropertyContext = checkAll(GEN) { a -> - (empty().combine(a)).equalUnderTheLaw(a, eq) + combine(empty, a).equalUnderTheLaw(a, eq) } - private suspend fun Monoid.monoidRightIdentity(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = + private suspend fun monoidRightIdentity(): PropertyContext = checkAll(GEN) { a -> - a.combine(empty()).equalUnderTheLaw(a, eq) + combine(a, empty).equalUnderTheLaw(a, eq) } - private suspend fun Monoid.combineAllIsDerived(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = + private suspend fun combineAllIsDerived(): PropertyContext = checkAll(5, Arb.list(GEN)) { list -> - list.fold().equalUnderTheLaw(if (list.isEmpty()) empty() else list.reduce { acc, f -> acc.combine(f) }, eq) + list.fold(empty, combine).equalUnderTheLaw(if (list.isEmpty()) empty else list.reduce(combine), eq) } - private fun Monoid.combineAllOfEmptyIsEmpty(eq: (F, F) -> Boolean): Unit = - emptyList().fold().equalUnderTheLaw(empty(), eq) shouldBe true + private fun combineAllOfEmptyIsEmpty(): Unit = + emptyList().fold(empty, combine).equalUnderTheLaw(empty, eq) shouldBe true } diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemigroupLaws.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemigroupLaws.kt index 15c8146aa87..701e5b3d8be 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemigroupLaws.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemigroupLaws.kt @@ -1,19 +1,24 @@ package arrow.core.test.laws import arrow.core.test.Law +import arrow.core.test.LawSet import arrow.core.test.equalUnderTheLaw import arrow.typeclasses.Semigroup import io.kotest.property.Arb import io.kotest.property.PropertyContext import io.kotest.property.checkAll -object SemigroupLaws { +data class SemigroupLaws( + val combine: (F, F) -> F, + val G: Arb, + val eq: (F, F) -> Boolean = { a, b -> a == b } +): LawSet { - fun laws(SG: Semigroup, G: Arb, eq: (F, F) -> Boolean = { a, b -> a == b }): List = - listOf(Law("Semigroup: associativity") { SG.semigroupAssociative(G, eq) }) + override val laws: List = + listOf(Law("Semigroup: associativity") { semigroupAssociative() }) - private suspend fun Semigroup.semigroupAssociative(G: Arb, eq: (F, F) -> Boolean): PropertyContext = + private suspend fun semigroupAssociative(): PropertyContext = checkAll(G, G, G) { A, B, C -> - A.combine(B).combine(C).equalUnderTheLaw(A.combine(B.combine(C)), eq) + combine(combine(A, B), C).equalUnderTheLaw(combine(A, combine(B, C)), eq) } } diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemiringLaws.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemiringLaws.kt index 637d2fca489..f6a178df0f8 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemiringLaws.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/laws/SemiringLaws.kt @@ -1,6 +1,7 @@ package arrow.core.test.laws import arrow.core.test.Law +import arrow.core.test.LawSet import arrow.core.test.equalUnderTheLaw import arrow.typeclasses.Semiring import io.kotest.property.Arb @@ -8,149 +9,100 @@ import io.kotest.property.checkAll import io.kotest.matchers.shouldBe import io.kotest.property.PropertyContext -object SemiringLaws { +data class SemiringLaws( + val zero: F, + val combine: (F, F) -> F, + val one: F, + val combineMultiplicate: (F, F) -> F, + val GEN: Arb, + val eq: (F, F) -> Boolean = { a, b -> a == b } +): LawSet { - fun laws(SG: Semiring, GEN: Arb, eq: (F, F) -> Boolean = { a, b -> a == b }): List = + override val laws: List = listOf( - Law("Semiring: Additive commutativity") { SG.semiringAdditiveCommutativity(GEN, eq) }, - Law("Semiring: Additive left identity") { SG.semiringAdditiveLeftIdentity(GEN, eq) }, - Law("Semiring: Additive right identity") { SG.semiringAdditiveRightIdentity(GEN, eq) }, - Law("Semiring: Additive associativity") { SG.semiringAdditiveAssociativity(GEN, eq) }, - Law("Semiring: Multiplicative commutativity") { SG.semiringMultiplicativeCommutativity(GEN, eq) }, - Law("Semiring: Multiplicative left identity") { SG.semiringMultiplicativeLeftIdentity(GEN, eq) }, - Law("Semiring: Multiplicative right identity") { SG.semiringMultiplicativeRightIdentity(GEN, eq) }, - Law("Semiring: Multiplicative associativity") { SG.semiringMultiplicativeAssociativity(GEN, eq) }, - Law("Semiring: Right distributivity") { SG.semiringRightDistributivity(GEN, eq) }, - Law("Semiring: Left distributivity") { SG.semiringLeftDistributivity(GEN, eq) }, - Law("Semiring: Multiplicative left absorption") { SG.semiringMultiplicativeLeftAbsorption(GEN, eq) }, - Law("Semiring: Multiplicative right absorption") { SG.semiringMultiplicativeRightAbsorption(GEN, eq) }, - Law("Semiring: times is derived") { SG.timesIsDerived(GEN, eq) }, - Law("Semiring: plus is derived") { SG.plusIsDerived(GEN, eq) }, - Law("Semiring: maybeCombineAddition is derived") { SG.maybeCombineAdditionIsDerived(GEN, eq) }, - Law("Semiring: maybeCombineAddition left null") { SG.maybeCombineAdditionLeftNull(GEN, eq) }, - Law("Semiring: maybeCombineAddition right null") { SG.maybeCombineAdditionRightNull(GEN, eq) }, - Law("Semiring: maybeCombineAddition both null") { SG.maybeCombineAdditionBothNull(eq) }, - Law("Semiring: maybeCombineMultiplicate is derived") { SG.maybeCombineMultiplicateIsDerived(GEN, eq) }, - Law("Semiring: maybeCombineMultiplicate left null") { SG.maybeCombineMultiplicateLeftNull(GEN, eq) }, - Law("Semiring: maybeCombineMultiplicate right null") { SG.maybeCombineMultiplicateRightNull(GEN, eq) }, - Law("Semiring: maybeCombineMultiplicate both null") { SG.maybeCombineMultiplicateBothNull(eq) } + Law("Semiring: Additive commutativity") { semiringAdditiveCommutativity() }, + Law("Semiring: Additive left identity") { semiringAdditiveLeftIdentity() }, + Law("Semiring: Additive right identity") { semiringAdditiveRightIdentity() }, + Law("Semiring: Additive associativity") { semiringAdditiveAssociativity() }, + Law("Semiring: Multiplicative commutativity") { semiringMultiplicativeCommutativity() }, + Law("Semiring: Multiplicative left identity") { semiringMultiplicativeLeftIdentity() }, + Law("Semiring: Multiplicative right identity") { semiringMultiplicativeRightIdentity() }, + Law("Semiring: Multiplicative associativity") { semiringMultiplicativeAssociativity() }, + Law("Semiring: Right distributivity") { semiringRightDistributivity() }, + Law("Semiring: Left distributivity") { semiringLeftDistributivity() }, + Law("Semiring: Multiplicative left absorption") { semiringMultiplicativeLeftAbsorption() }, + Law("Semiring: Multiplicative right absorption") { semiringMultiplicativeRightAbsorption() }, ) // a + b = b + a - private suspend fun Semiring.semiringAdditiveCommutativity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringAdditiveCommutativity() = checkAll(GEN, GEN) { a, b -> - a.combine(b).equalUnderTheLaw(b.combine(a), eq) + combine(a, b).equalUnderTheLaw(combine(b, a), eq) } // 0 + a = a - private suspend fun Semiring.semiringAdditiveLeftIdentity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringAdditiveLeftIdentity() = checkAll(GEN) { A -> - (zero().combine(A)).equalUnderTheLaw(A, eq) + combine(zero, A).equalUnderTheLaw(A, eq) } // a + 0 = a - private suspend fun Semiring.semiringAdditiveRightIdentity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringAdditiveRightIdentity() = checkAll(GEN) { A -> - A.combine(zero()).equalUnderTheLaw(A, eq) + combine(A, zero).equalUnderTheLaw(A, eq) } // a + (b + c) = (a + b) + c - private suspend fun Semiring.semiringAdditiveAssociativity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringAdditiveAssociativity() = checkAll(GEN, GEN, GEN) { A, B, C -> - A.combine(B.combine(C)).equalUnderTheLaw((A.combine(B)).combine(C), eq) + combine(A, combine(B, C)).equalUnderTheLaw(combine(combine(A, B), C), eq) } // a · b = b · a - private suspend fun Semiring.semiringMultiplicativeCommutativity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeCommutativity() = checkAll(GEN, GEN) { a, b -> - a.combineMultiplicate(b).equalUnderTheLaw(b.combineMultiplicate(a), eq) + combineMultiplicate(a, b).equalUnderTheLaw(combineMultiplicate(b, a), eq) } // 1 · a = a - private suspend fun Semiring.semiringMultiplicativeLeftIdentity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeLeftIdentity() = checkAll(GEN) { A -> - (one().combineMultiplicate(A)).equalUnderTheLaw(A, eq) + combineMultiplicate(one, A).equalUnderTheLaw(A, eq) } // a · 1 = a - private suspend fun Semiring.semiringMultiplicativeRightIdentity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeRightIdentity() = checkAll(GEN) { A -> - A.combineMultiplicate(one()).equalUnderTheLaw(A, eq) + combineMultiplicate(A, one).equalUnderTheLaw(A, eq) } // a · (b · c) = (a · b) · c - private suspend fun Semiring.semiringMultiplicativeAssociativity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeAssociativity() = checkAll(GEN, GEN, GEN) { A, B, C -> - A.combineMultiplicate(B.combineMultiplicate(C)).equalUnderTheLaw((B.combineMultiplicate(A)).combineMultiplicate(C), eq) + combineMultiplicate(A, combineMultiplicate(B, C)).equalUnderTheLaw(combineMultiplicate(combineMultiplicate(A, B), C), eq) } // (a + b) · c = a · c + b · c - private suspend fun Semiring.semiringRightDistributivity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringRightDistributivity() = checkAll(GEN, GEN, GEN) { A, B, C -> - (A.combine(B)).combineMultiplicate(C).equalUnderTheLaw((A.combineMultiplicate(C)).combine(B.combineMultiplicate(C)), eq) + combineMultiplicate(combine(A, B), C).equalUnderTheLaw(combine(combineMultiplicate(A, C), combineMultiplicate(B, C)), eq) } // a · (b + c) = a · b + a · c - private suspend fun Semiring.semiringLeftDistributivity(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringLeftDistributivity() = checkAll(GEN, GEN, GEN) { A, B, C -> - A.combineMultiplicate(B.combine(C)).equalUnderTheLaw((A.combineMultiplicate(B)).combine(A.combineMultiplicate(C)), eq) + combineMultiplicate(A, combine(B, C)).equalUnderTheLaw(combine(combineMultiplicate(A, B), combineMultiplicate(A, C)), eq) } // 0 · a = 0 - private suspend fun Semiring.semiringMultiplicativeLeftAbsorption(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeLeftAbsorption() = checkAll(GEN) { A -> - (zero().combineMultiplicate(A)).equalUnderTheLaw(zero(), eq) + combineMultiplicate(zero, A).equalUnderTheLaw(zero, eq) } // a · 0 = 0 - private suspend fun Semiring.semiringMultiplicativeRightAbsorption(GEN: Arb, eq: (F, F) -> Boolean) = + private suspend fun semiringMultiplicativeRightAbsorption() = checkAll(GEN) { A -> - A.combineMultiplicate(zero()).equalUnderTheLaw(zero(), eq) + combineMultiplicate(A, zero).equalUnderTheLaw(zero, eq) } - - private suspend fun Semiring.timesIsDerived(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN, GEN) { A, B -> - A.times(B).equalUnderTheLaw(A.combineMultiplicate(B), eq) - } - - private suspend fun Semiring.plusIsDerived(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN, GEN) { A, B -> - A.plus(B).equalUnderTheLaw(A.combine(B), eq) - } - - private suspend fun Semiring.maybeCombineAdditionIsDerived(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN, GEN) { A, B -> - A.maybeCombineAddition(B).equalUnderTheLaw(A.combine(B), eq) - } - - private suspend fun Semiring.maybeCombineAdditionLeftNull(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN) { A -> - null.maybeCombineAddition(A).equalUnderTheLaw(zero(), eq) - } - - private suspend fun Semiring.maybeCombineAdditionRightNull(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN) { A -> - A.maybeCombineAddition(null).equalUnderTheLaw(A, eq) - } - - private fun Semiring.maybeCombineAdditionBothNull(eq: (F, F) -> Boolean): Unit = - null.maybeCombineAddition(null).equalUnderTheLaw(zero(), eq) shouldBe true - - private suspend fun Semiring.maybeCombineMultiplicateIsDerived(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN, GEN) { A, B -> - A.maybeCombineMultiplicate(B).equalUnderTheLaw(A.combineMultiplicate(B), eq) - } - - private suspend fun Semiring.maybeCombineMultiplicateLeftNull(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN) { A -> - null.maybeCombineMultiplicate(A).equalUnderTheLaw(one(), eq) - } - - private suspend fun Semiring.maybeCombineMultiplicateRightNull(GEN: Arb, eq: (F, F) -> Boolean): PropertyContext = - checkAll(GEN) { A -> - A.maybeCombineMultiplicate(null).equalUnderTheLaw(A, eq) - } - - private fun Semiring.maybeCombineMultiplicateBothNull(eq: (F, F) -> Boolean): Unit = - null.maybeCombineMultiplicate(null).equalUnderTheLaw(one(), eq) shouldBe true } 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 index fd3c48ac2ad..15de9c5bfdf 100644 --- 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 @@ -22,7 +22,7 @@ suspend fun test() { effect { failure() } val ior: Ior = - ior(Semigroup.string()) { failure() } + ior(String::plus) { failure() } either shouldBe Either.Left("failed") effect.toEither() shouldBe Either.Left("failed") diff --git a/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Every.kt b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Every.kt index 33b96bf40e7..eed319c0a64 100644 --- a/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Every.kt +++ b/arrow-libs/optics/arrow-optics/src/commonMain/kotlin/arrow/optics/Every.kt @@ -10,7 +10,7 @@ import arrow.core.Tuple6 import arrow.core.Tuple7 import arrow.core.Tuple8 import arrow.core.Tuple9 -import arrow.core.foldLeft +import arrow.core.fold import arrow.core.foldMap import arrow.typeclasses.Monoid import kotlin.jvm.JvmStatic @@ -89,7 +89,7 @@ public interface PEvery : PTraversal, Fold, PSette override fun foldMap(M: Monoid, source: Map, map: (focus: V) -> R): R = M.run { - source.foldLeft(empty()) { acc, (_, v) -> + source.fold(empty()) { acc, (_, v) -> acc.combine(map(v)) } }