From c28e7da09ef07921efbc2419796c0edb45bb25ee Mon Sep 17 00:00:00 2001 From: Imran Malic Settuba <46971368+i-walker@users.noreply.github.com> Date: Mon, 23 May 2022 13:01:32 +0200 Subject: [PATCH] rename traverseX and sequenceX functions in core (#2715) * rename sequencex traversex for NonemptyList + cleanup * rename sequencex traversex for Ior + cleanup * rename sequencex traversex for Map + cleanup * rename sequencex traversex for Option + cleanup * rename sequencex traversex for Validated + cleanup + rename for sequenceNullable in Ior * rename sequencex traversex for Either + cleanup * sequencex traversex clean up for Either + apiDump * clean up tests and remove not needed typed lambda parameter * fix refactor replace with --- arrow-libs/core/arrow-core/api/arrow-core.api | 33 +++++++++++ .../commonMain/kotlin/arrow/core/Either.kt | 41 ++++++++++--- .../src/commonMain/kotlin/arrow/core/Ior.kt | 47 +++++++++++++-- .../kotlin/arrow/core/NonEmptyList.kt | 57 ++++++++++++++++--- .../commonMain/kotlin/arrow/core/Option.kt | 31 ++++++++-- .../commonMain/kotlin/arrow/core/Validated.kt | 35 ++++++++++-- .../src/commonMain/kotlin/arrow/core/map.kt | 51 +++++++++++++---- .../kotlin/arrow/core/EitherTest.kt | 32 +++++------ .../commonTest/kotlin/arrow/core/IorTest.kt | 23 ++++---- .../kotlin/arrow/core/IterableTest.kt | 8 +-- .../commonTest/kotlin/arrow/core/MapKTest.kt | 12 ++-- .../kotlin/arrow/core/NonEmptyListTest.kt | 45 +++++++-------- .../kotlin/arrow/core/OptionTest.kt | 28 ++++----- .../kotlin/arrow/core/SequenceKTest.kt | 8 +-- .../kotlin/arrow/core/ValidatedTest.kt | 33 ++++++----- .../fx/coroutines/ParTraverseEitherTest.kt | 5 +- 16 files changed, 347 insertions(+), 142 deletions(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 813e9088c2a..b456d2197c7 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -184,6 +184,8 @@ public abstract class arrow/core/Either { public fun toString ()Ljava/lang/String; public final fun toValidated ()Larrow/core/Validated; public final fun toValidatedNel ()Larrow/core/Validated; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; public final fun traverse (Lkotlin/jvm/functions/Function1;)Ljava/util/List; public final fun traverseNullable (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public final fun traverseOption (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; @@ -265,6 +267,9 @@ public final class arrow/core/EitherKt { public static final fun right (Ljava/lang/Object;)Larrow/core/Either; public static final fun rightIfNotNull (Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)Larrow/core/Either; public static final fun rightIfNull (Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)Larrow/core/Either; + public static final fun sequence (Larrow/core/Either;)Larrow/core/Either; + public static final fun sequence (Larrow/core/Either;)Larrow/core/Option; + public static final fun sequence (Larrow/core/Either;)Larrow/core/Validated; public static final fun sequence (Larrow/core/Either;)Ljava/util/List; public static final fun sequenceNullable (Larrow/core/Either;)Larrow/core/Either; public static final fun sequenceOption (Larrow/core/Either;)Larrow/core/Option; @@ -445,6 +450,9 @@ public abstract class arrow/core/Ior { public final fun toEither ()Larrow/core/Either; public fun toString ()Ljava/lang/String; public final fun toValidated ()Larrow/core/Validated; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; public final fun traverse (Lkotlin/jvm/functions/Function1;)Ljava/util/List; public final fun traverseEither (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public final fun traverseNullable (Lkotlin/jvm/functions/Function1;)Larrow/core/Ior; @@ -531,6 +539,10 @@ public final class arrow/core/IorKt { public static final fun replicate (Larrow/core/Ior;Larrow/typeclasses/Semigroup;I)Larrow/core/Ior; public static final fun replicate (Larrow/core/Ior;Larrow/typeclasses/Semigroup;ILarrow/typeclasses/Monoid;)Larrow/core/Ior; public static final fun rightIor (Ljava/lang/Object;)Larrow/core/Ior; + public static final fun sequence (Larrow/core/Ior;)Larrow/core/Either; + public static final fun sequence (Larrow/core/Ior;)Larrow/core/Ior; + public static final fun sequence (Larrow/core/Ior;)Larrow/core/Option; + public static final fun sequence (Larrow/core/Ior;)Larrow/core/Validated; public static final fun sequence (Larrow/core/Ior;)Ljava/util/List; public static final fun sequenceEither (Larrow/core/Ior;)Larrow/core/Either; public static final fun sequenceNullable (Larrow/core/Ior;)Larrow/core/Ior; @@ -645,9 +657,15 @@ public final class arrow/core/MapKt { public static final fun padZip (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; public static final fun padZip (Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; public static final fun salign (Ljava/util/Map;Larrow/typeclasses/Semigroup;Ljava/util/Map;)Ljava/util/Map; + public static final fun sequence (Ljava/util/Map;)Larrow/core/Either; + public static final fun sequence (Ljava/util/Map;)Larrow/core/Option; + public static final fun sequence (Ljava/util/Map;Larrow/typeclasses/Semigroup;)Larrow/core/Validated; public static final fun sequenceEither (Ljava/util/Map;)Larrow/core/Either; public static final fun sequenceOption (Ljava/util/Map;)Larrow/core/Option; public static final fun sequenceValidated (Ljava/util/Map;Larrow/typeclasses/Semigroup;)Larrow/core/Validated; + public static final fun traverse (Ljava/util/Map;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; + public static final fun traverse (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public static final fun traverse (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun traverseEither (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public static final fun traverseOption (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun traverseValidated (Ljava/util/Map;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; @@ -727,9 +745,15 @@ public final class arrow/core/NonEmptyListKt { public static final fun flatten (Larrow/core/NonEmptyList;)Larrow/core/NonEmptyList; public static final fun nel (Ljava/lang/Object;)Larrow/core/NonEmptyList; public static final fun nonEmptyListOf (Ljava/lang/Object;[Ljava/lang/Object;)Larrow/core/NonEmptyList; + public static final fun sequence (Larrow/core/NonEmptyList;)Larrow/core/Either; + public static final fun sequence (Larrow/core/NonEmptyList;)Larrow/core/Option; + public static final fun sequence (Larrow/core/NonEmptyList;Larrow/typeclasses/Semigroup;)Larrow/core/Validated; public static final fun sequenceEither (Larrow/core/NonEmptyList;)Larrow/core/Either; public static final fun sequenceOption (Larrow/core/NonEmptyList;)Larrow/core/Option; public static final fun sequenceValidated (Larrow/core/NonEmptyList;Larrow/typeclasses/Semigroup;)Larrow/core/Validated; + public static final fun traverse (Larrow/core/NonEmptyList;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; + public static final fun traverse (Larrow/core/NonEmptyList;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public static final fun traverse (Larrow/core/NonEmptyList;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun traverseEither (Larrow/core/NonEmptyList;Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public static final fun traverseOption (Larrow/core/NonEmptyList;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun traverseValidated (Larrow/core/NonEmptyList;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; @@ -804,6 +828,8 @@ public abstract class arrow/core/Option { public final fun toEither (Lkotlin/jvm/functions/Function0;)Larrow/core/Either; public final fun toList ()Ljava/util/List; public fun toString ()Ljava/lang/String; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; public final fun traverse (Lkotlin/jvm/functions/Function1;)Ljava/util/List; public final fun traverseEither (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public final fun traverseValidated (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; @@ -851,6 +877,8 @@ public final class arrow/core/OptionKt { public static final fun salign (Larrow/core/Option;Larrow/typeclasses/Semigroup;Larrow/core/Option;)Larrow/core/Option; public static final fun separateEither (Larrow/core/Option;)Lkotlin/Pair; public static final fun separateValidated (Larrow/core/Option;)Lkotlin/Pair; + public static final fun sequence (Larrow/core/Option;)Larrow/core/Either; + public static final fun sequence (Larrow/core/Option;)Larrow/core/Validated; public static final fun sequence (Larrow/core/Option;)Ljava/util/List; public static final fun sequenceEither (Larrow/core/Option;)Larrow/core/Either; public static final fun sequenceValidated (Larrow/core/Option;)Larrow/core/Validated; @@ -2298,6 +2326,8 @@ public abstract class arrow/core/Validated { public final fun toOption ()Larrow/core/Option; public fun toString ()Ljava/lang/String; public final fun toValidatedNel ()Larrow/core/Validated; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; + public final fun traverse (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun traverse (Lkotlin/jvm/functions/Function1;)Ljava/util/List; public final fun traverseEither (Lkotlin/jvm/functions/Function1;)Larrow/core/Either; public final fun traverseNullable (Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; @@ -2373,6 +2403,9 @@ public final class arrow/core/ValidatedKt { public static final fun redeem (Larrow/core/Validated;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated; public static final fun replicate (Larrow/core/Validated;Larrow/typeclasses/Semigroup;I)Larrow/core/Validated; public static final fun replicate (Larrow/core/Validated;Larrow/typeclasses/Semigroup;ILarrow/typeclasses/Monoid;)Larrow/core/Validated; + public static final fun sequence (Larrow/core/Validated;)Larrow/core/Either; + public static final fun sequence (Larrow/core/Validated;)Larrow/core/Option; + public static final fun sequence (Larrow/core/Validated;)Larrow/core/Validated; public static final fun sequence (Larrow/core/Validated;)Ljava/util/List; public static final fun sequenceEither (Larrow/core/Validated;)Larrow/core/Either; public static final fun sequenceNullable (Larrow/core/Validated;)Larrow/core/Validated; 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 2f59908d4c6..df37fa8565f 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 @@ -5,6 +5,7 @@ import arrow.core.Either.Left import arrow.core.Either.Right import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import kotlin.experimental.ExperimentalTypeInference import kotlin.js.JsName import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @@ -1000,21 +1001,35 @@ public sealed class Either { is Right -> List(n) { this.value }.right() } + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (B) -> Iterable): List> = - fold({ emptyList() }, { fa(it).map { Right(it) } }) + fold({ emptyList() }, { fa(it).map(::Right) }) + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (B) -> Option): Option> = + fold({ None }, { right -> fa(right).map(::Right) }) + + @Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) public inline fun traverseOption(fa: (B) -> Option): Option> = - fold({ None }, { right -> fa(right).map { Right(it) } }) + traverse(fa) public inline fun traverseNullable(fa: (B) -> C?): Either? = - fold({ null }, { right -> fa(right)?.let { Right(it) } }) + fold({ null }, { right -> fa(right)?.let(::Right) }) - public inline fun traverseValidated(fa: (B) -> Validated): Validated> = + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (B) -> Validated): Validated> = when (this) { - is Right -> fa(this.value).map { Right(it) } + is Right -> fa(this.value).map(::Right) is Left -> this.valid() } + @Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseValidated(fa: (B) -> Validated): Validated> = + traverse(fa) + public inline fun bitraverse(fe: (A) -> Iterable, fa: (B) -> Iterable): List> = fold({ fe(it).map { Left(it) } }, { fa(it).map { Right(it) } }) @@ -1710,14 +1725,26 @@ public inline fun Either.redeemWith(fa: (A) -> Either, public fun Either>.sequence(): List> = traverse(::identity) +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Either>.sequenceOption(): Option> = - traverseOption(::identity) + sequence() +public fun Either>.sequence(): Option> = + traverse(::identity) + +@Deprecated("sequenceNullable is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Either.sequenceNullable(): Either? = + sequence() + +public fun Either.sequence(): Either? = traverseNullable(::identity) +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Either>.sequenceValidated(): Validated> = - traverseValidated(::identity) + sequence() + +public fun Either>.sequence(): Validated> = + traverse(::identity) public fun Either, Iterable>.bisequence(): List> = bitraverse(::identity, ::identity) 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 93be4b2909a..a2f6b55a503 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 @@ -5,6 +5,7 @@ import arrow.core.Ior.Left import arrow.core.Ior.Right import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmStatic public typealias IorNel = Ior, B> @@ -543,6 +544,8 @@ public sealed class Ior { public fun isNotEmpty(): Boolean = !isLeft + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (B) -> Iterable): List> = fold( { a -> listOf(Left(a)) }, @@ -550,20 +553,32 @@ public sealed class Ior { { a, b -> fa(b).map { Both(a, it) } } ) + @Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) public inline fun traverseEither(fa: (B) -> Either): Either> = + traverse(fa) + + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (B) -> Either): Either> = fold( { a -> Either.Right(Left(a)) }, { b -> fa(b).map { Right(it) } }, { a, b -> fa(b).map { Both(a, it) } } ) - public inline fun traverseOption(fa: (B) -> Option): Option> = + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (B) -> Option): Option> = fold( { a -> Some(Left(a)) }, { b -> fa(b).map { Right(it) } }, { a, b -> fa(b).map { Both(a, it) } } ) + @Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseOption(fa: (B) -> Option): Option> = + traverse(fa) + public inline fun traverseNullable(fa: (B) -> C?): Ior? = fold( { a -> Left(a) }, @@ -571,13 +586,19 @@ public sealed class Ior { { a, b -> fa(b)?.let { Both(a, it) } } ) - public inline fun traverseValidated(fa: (B) -> Validated): Validated> = + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (B) -> Validated): Validated> = fold( { a -> Valid(Left(a)) }, { b -> fa(b).map { Right(it) } }, { a, b -> fa(b).map { Both(a, it) } } ) + @Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseValidated(fa: (B) -> Validated): Validated> = + traverse(fa) + public fun void(): Ior = map { Unit } } @@ -676,17 +697,33 @@ public fun Ior.replicate(SA: Semigroup, n: Int, MB: Monoid): public fun Ior>.sequence(): List> = traverse(::identity) +@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Ior>.sequenceEither(): Either> = - traverseEither(::identity) + sequence() +public fun Ior>.sequence(): Either> = + traverse(::identity) + +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Ior>.sequenceOption(): Option> = - traverseOption(::identity) + sequence() + +public fun Ior>.sequence(): Option> = + traverse(::identity) +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Ior.sequenceNullable(): Ior? = + sequence() + +public fun Ior.sequence(): Ior? = traverseNullable(::identity) +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Ior>.sequenceValidated(): Validated> = - traverseValidated(::identity) + sequence() + +public fun Ior>.sequence(): Validated> = + traverse(::identity) /** * Given [B] is a sub type of [C], re-type this value from Ior to Ior 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 26adcb8c9bc..efc7922c75d 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 @@ -3,6 +3,7 @@ package arrow.core import arrow.core.Either.Left import arrow.core.Either.Right import arrow.typeclasses.Semigroup +import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmStatic public typealias Nel = NonEmptyList @@ -408,24 +409,49 @@ public fun NonEmptyList.unzip(f: (C) -> Pair): Pair NonEmptyList.traverseEither(f: (A) -> Either): Either> { +@Deprecated( + "traverseEither is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) +public inline fun NonEmptyList.traverseEither(f: (A) -> Either): Either> = + traverse(f) + +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +public inline fun NonEmptyList.traverse(f: (A) -> Either): Either> { val acc = mutableListOf() forEach { a -> when (val res = f(a)) { is Right -> acc.add(res.value) - is Left -> return@traverseEither res + is Left -> return@traverse res } } // Safe due to traverse laws return NonEmptyList.fromListUnsafe(acc).right() } +@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun NonEmptyList>.sequenceEither(): Either> = - traverseEither(::identity) + sequence() + +public fun NonEmptyList>.sequence(): Either> = + traverse(::identity) +@Deprecated( + "traverseValidated is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(semigroup, f)", "arrow.core.traverse") +) public inline fun NonEmptyList.traverseValidated( semigroup: Semigroup, f: (A) -> Validated +): Validated> = + traverse(semigroup, f) + +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +public inline fun NonEmptyList.traverse( + semigroup: Semigroup, + f: (A) -> Validated ): Validated> = fold(mutableListOf().valid() as Validated>) { acc, a -> when (val res = f(a)) { @@ -440,20 +466,37 @@ public inline fun NonEmptyList.traverseValidated( } }.map { NonEmptyList.fromListUnsafe(it) } +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun NonEmptyList>.sequenceValidated(semigroup: Semigroup): Validated> = - traverseValidated(semigroup, ::identity) + sequence(semigroup) + +public fun NonEmptyList>.sequence(semigroup: Semigroup): Validated> = + traverse(semigroup, ::identity) -public inline fun NonEmptyList.traverseOption(f: (A) -> Option): Option> { +@Deprecated( + "traverseOption is being renamed to traverse to simplify the Arrow API", + ReplaceWith("traverse(f)", "arrow.core.traverse") +) +public inline fun NonEmptyList.traverseOption(f: (A) -> Option): Option> = + traverse(f) + +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +public inline fun NonEmptyList.traverse(f: (A) -> Option): Option> { val acc = mutableListOf() forEach { a -> when (val res = f(a)) { is Some -> acc.add(res.value) - is None -> return@traverseOption res + is None -> return@traverse res } } // Safe due to traverse laws return NonEmptyList.fromListUnsafe(acc).some() } +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun NonEmptyList>.sequenceOption(): Option> = - traverseOption { it } + sequence() + +public fun NonEmptyList>.sequence(): Option> = + traverse(::identity) 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 9892b527740..0c86bd2ccbe 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 @@ -3,6 +3,7 @@ package arrow.core import arrow.core.Either.Right import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @@ -812,21 +813,35 @@ public sealed class Option { public fun replicate(n: Int): Option> = if (n <= 0) Some(emptyList()) else map { a -> List(n) { a } } + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (A) -> Iterable): List> = fold({ emptyList() }, { a -> fa(a).map { Some(it) } }) - public inline fun traverseEither(fa: (A) -> Either): Either> = + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (A) -> Either): Either> = when (this) { is Some -> fa(value).map { Some(it) } is None -> Right(this) } - public inline fun traverseValidated(fa: (A) -> Validated): Validated> = + @Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseEither(fa: (A) -> Either): Either> = + traverse(fa) + + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (A) -> Validated): Validated> = when (this) { is Some -> fa(value).map { Some(it) } is None -> Valid(this) } + @Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseValidated(fa: (A) -> Validated): Validated> = + traverse(fa) + public inline fun toEither(ifEmpty: () -> L): Either = fold({ ifEmpty().left() }, { it.right() }) @@ -991,11 +1006,19 @@ public fun Option>.separateValidated(): Pair, O public fun Option>.sequence(): List> = traverse(::identity) +@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Option>.sequenceEither(): Either> = - traverseEither(::identity) + sequence() + +public fun Option>.sequence(): Either> = + traverse(::identity) +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Option>.sequenceValidated(): Validated> = - traverseValidated(::identity) + sequence() + +public fun Option>.sequence(): Validated> = + traverse(::identity) public fun Option>.unalign(): Pair, Option> = unalign(::identity) 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 e5eb9824e4c..27922f7c4a8 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,7 @@ import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup import arrow.core.Either.Left import arrow.core.Either.Right +import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @@ -118,21 +119,35 @@ public sealed class Validated { public fun void(): Validated = map { Unit } + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (A) -> Iterable): List> = fold({ emptyList() }, { a -> fa(a).map { Valid(it) } }) - public inline fun traverseEither(fa: (A) -> Either): Either> = + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (A) -> Either): Either> = when (this) { is Valid -> fa(this.value).map { Valid(it) } is Invalid -> this.right() } - public inline fun traverseOption(fa: (A) -> Option): Option> = + @Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseEither(fa: (A) -> Either): Either> = + traverse(fa) + + @OptIn(ExperimentalTypeInference::class) + @OverloadResolutionByLambdaReturnType + public inline fun traverse(fa: (A) -> Option): Option> = when (this) { is Valid -> fa(this.value).map { Valid(it) } is Invalid -> None } + @Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(fa)")) + public inline fun traverseOption(fa: (A) -> Option): Option> = + traverse(fa) + public inline fun traverseNullable(fa: (A) -> B?): Validated? = when (this) { is Valid -> fa(this.value)?.let { Valid(it) } @@ -680,13 +695,25 @@ public fun Validated.combineAll(MA: Monoid): A = public fun Validated>.sequence(): List> = traverse(::identity) +@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Validated>.sequenceEither(): Either> = - traverseEither(::identity) + sequence() +public fun Validated>.sequence(): Either> = + traverse(::identity) + +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Validated>.sequenceOption(): Option> = - traverseOption(::identity) + sequence() +public fun Validated>.sequence(): Option> = + traverse(::identity) + +@Deprecated("sequenceNullable is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Validated.sequenceNullable(): Validated? = + sequence() + +public fun Validated.sequence(): Validated? = traverseNullable(::identity) public operator fun , A : Comparable> Validated.compareTo(other: Validated): Int = 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 f786c2b4f92..1265ec598c6 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,6 +4,7 @@ import arrow.core.Either.Left import arrow.core.Either.Right import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import kotlin.experimental.ExperimentalTypeInference import kotlin.collections.flatMap as _flatMap /** @@ -234,25 +235,42 @@ public fun Map.flatMap(f: (Map.Entry) -> Map): Map Map.traverseEither(f: (A) -> Either): Either> { +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +public inline fun Map.traverse(f: (A) -> Either): Either> { val acc = mutableMapOf() forEach { (k, v) -> when (val res = f(v)) { is Right -> acc[k] = res.value - is Left -> return@traverseEither res + is Left -> return@traverse res } } return acc.right() } +@Deprecated("traverseEither is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +public inline fun Map.traverseEither(f: (A) -> Either): Either> = + traverse(f) + +public fun Map>.sequence(): Either> = + traverse(::identity) + +@Deprecated("sequenceEither is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Map>.sequenceEither(): Either> = - traverseEither(::identity) + sequence() +@Deprecated("traverseValidated is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(semigroup, f)", "arrow.core.traverse")) public inline fun Map.traverseValidated( semigroup: Semigroup, f: (A) -> Validated -): Validated> { - return foldLeft(mutableMapOf().valid() as Validated>) { acc, (k, v) -> +): Validated> = + traverse(semigroup, f) + +public inline fun Map.traverse( + semigroup: Semigroup, + f: (A) -> Validated +): Validated> = + foldLeft(mutableMapOf().valid() as Validated>) { acc, (k, v) -> when (val res = f(v)) { is Valid -> when (acc) { is Valid -> acc.also { it.value[k] = res.value } @@ -264,24 +282,37 @@ public inline fun Map.traverseValidated( } } } -} +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence(semigroup)", "arrow.core.sequence")) public fun Map>.sequenceValidated(semigroup: Semigroup): Validated> = - traverseValidated(semigroup, ::identity) + sequence(semigroup) + +public fun Map>.sequence(semigroup: Semigroup): Validated> = + traverse(semigroup, ::identity) -public inline fun Map.traverseOption(f: (A) -> Option): Option> { +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +public inline fun Map.traverse(f: (A) -> Option): Option> { val acc = mutableMapOf() forEach { (k, v) -> when (val res = f(v)) { is Some -> acc[k] = res.value - is None -> return@traverseOption res + is None -> return@traverse res } } return acc.some() } +@Deprecated("traverseOption is being renamed to traverse to simplify the Arrow API", ReplaceWith("traverse(f)", "arrow.core.traverse")) +public inline fun Map.traverseOption(f: (A) -> Option): Option> = + traverse(f) + +@Deprecated("sequenceOption is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Map>.sequenceOption(): Option> = - traverseOption { it } + sequence() + +public fun Map>.sequence(): Option> = + traverse(::identity) public fun Map.void(): Map = mapValues { Unit } 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 fa6c9a467c7..3a0ebadb967 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 @@ -2,9 +2,6 @@ package arrow.core import arrow.core.Either.Left import arrow.core.Either.Right -import arrow.core.computations.EitherEffect -import arrow.core.computations.RestrictedEitherEffect -import arrow.core.computations.either import arrow.core.test.UnitSpec import arrow.core.test.generators.any import arrow.core.test.generators.either @@ -13,7 +10,6 @@ import arrow.core.test.generators.suspendFunThatReturnsAnyLeft import arrow.core.test.generators.suspendFunThatReturnsAnyRight import arrow.core.test.generators.suspendFunThatReturnsEitherAnyOrAnyOrThrows import arrow.core.test.generators.suspendFunThatThrows -import arrow.core.test.laws.FxLaws import arrow.core.test.laws.MonoidLaws import arrow.typeclasses.Monoid import io.kotest.assertions.throwables.shouldThrow @@ -24,10 +20,8 @@ import io.kotest.property.arbitrary.choice import io.kotest.property.arbitrary.constant import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.long -import io.kotest.property.arbitrary.map import io.kotest.property.arbitrary.negativeInts import io.kotest.property.arbitrary.string -import io.kotest.property.checkAll class EitherTest : UnitSpec() { @@ -481,38 +475,38 @@ class EitherTest : UnitSpec() { left.traverseNullable { it } shouldBe null } - "sequenceNullable should be consistent with traverseNullable" { + "sequence for Nullable should be consistent with traverseNullable" { checkAll(Arb.either(Arb.string(), Arb.int())) { either -> - either.map { it }.sequenceNullable() shouldBe either.traverseNullable { it } - either.map { null }.sequenceNullable() shouldBe null + either.map { it }.sequence() shouldBe either.traverseNullable { it } + either.map { null }.sequence() shouldBe null } } - "traverseOption should return option if either is right" { + "traverse for Option should return option if either is right" { val right: Either = Right(1) val left: Either = Left("foo") - right.traverseOption { Some(it) } shouldBe Some(Right(1)) - left.traverseOption { Some(it) } shouldBe None + right.traverse { Some(it) } shouldBe Some(Right(1)) + left.traverse { Some(it) } shouldBe None } - "sequenceOption should be consistent with traverseOption" { + "sequence for Option should be consistent with traverseOption" { checkAll(Arb.either(Arb.string(), Arb.int())) { either -> - either.map { Some(it) }.sequenceOption() shouldBe either.traverseOption { Some(it) } + either.map { Some(it) }.sequence() shouldBe either.traverse { Some(it) } } } - "traverseValidated should return validated of either" { + "traverse for Validated should return validated of either" { val right: Either = Right(1) val left: Either = Left("foo") - right.traverseValidated { it.valid() } shouldBe Valid(Right(1)) - left.traverseValidated { it.valid() } shouldBe Valid(Left("foo")) + right.traverse { it.valid() } shouldBe Valid(Right(1)) + left.traverse { it.valid() } shouldBe Valid(Left("foo")) } - "sequenceValidated should be consistent with traverseValidated" { + "sequence for Validated should be consistent with traverseValidated" { checkAll(Arb.either(Arb.string(), Arb.int())) { either -> - either.map { it.valid() }.sequenceValidated() shouldBe either.traverseValidated { it.valid() } + either.map { it.valid() }.sequence() shouldBe either.traverse { it.valid() } } } 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 f563f2f04e7..4b83bc15750 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 @@ -7,7 +7,6 @@ import arrow.typeclasses.Semigroup import io.kotest.data.forAll import io.kotest.data.row import io.kotest.property.Arb -import io.kotest.property.checkAll import io.kotest.matchers.shouldBe import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.long @@ -237,10 +236,10 @@ class IorTest : UnitSpec() { } } - "sequenceNullable should be consistent with traverseNullable" { + "sequence for Nullable should be consistent with traverseNullable" { checkAll(Arb.ior(Arb.int(), Arb.string())) { ior -> - ior.map { it }.sequenceNullable() shouldBe ior.traverseNullable { it } - ior.map { null }.sequenceNullable() shouldBe ior.traverseNullable { null } + ior.map { it }.sequence() shouldBe ior.traverseNullable { it } + ior.map { null }.sequence() shouldBe ior.traverseNullable { null } } } @@ -250,15 +249,15 @@ class IorTest : UnitSpec() { val iorR: Ior = b.rightIor() val iorBoth: Ior = (a to b).bothIor() - iorL.traverseOption { Some(it) } shouldBe Some(Ior.Left(a)) - iorR.traverseOption { Some(it) } shouldBe Some(Ior.Right(b)) - iorBoth.traverseOption { 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) }.sequenceOption() shouldBe ior.traverseOption { Some(it) } + ior.map { Some(it) }.sequence() shouldBe ior.traverse { Some(it) } } } @@ -268,15 +267,15 @@ class IorTest : UnitSpec() { val iorR: Ior = b.rightIor() val iorBoth: Ior = (a to b).bothIor() - iorL.traverseEither { it.right() } shouldBe Either.Right(Ior.Left(a)) - iorR.traverseEither { it.right() } shouldBe Either.Right(Ior.Right(b)) - iorBoth.traverseEither { 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() }.sequenceEither() shouldBe ior.traverseEither { it.right() } + ior.map { it.right() }.sequence() shouldBe ior.traverse { it.right() } } } diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index 224fc743727..78c4e7dc4e2 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -103,7 +103,7 @@ class IterableTest : UnitSpec() { "traverse Option short-circuits" { checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverse { it: Int -> + val evens = ints.traverse { (it % 2 == 0).maybe { acc.add(it) it @@ -123,7 +123,7 @@ class IterableTest : UnitSpec() { "sequence Option should be consistent with traverse Option" { checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Some(it) }.sequence() shouldBe ints.traverse { it: Int -> Some(it) } + ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } } } @@ -141,7 +141,7 @@ class IterableTest : UnitSpec() { "traverse Nullable short-circuits" { checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverse { it: Int -> + val evens = ints.traverse { if (it % 2 == 0) { acc.add(it) it @@ -176,7 +176,7 @@ class IterableTest : UnitSpec() { "sequence Nullable should be consistent with travers Nullable" { checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it as Int? }.sequence() shouldBe ints.traverse { it: Int -> it as Int? } + ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } } } 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 cafe79f4218..9523814a6a3 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 @@ -25,7 +25,7 @@ class MapKTest : UnitSpec() { "traverseEither is stacksafe" { val acc = mutableListOf() - val res = (0..20_000).map { it to it }.toMap().traverseEither { v -> + val res = (0..20_000).map { it to it }.toMap().traverse { v -> acc.add(v) Either.Right(v) } @@ -36,7 +36,7 @@ class MapKTest : UnitSpec() { "traverseEither short-circuit" { checkAll(Arb.map(Arb.int(), Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverseEither { + val evens = ints.traverse { if (it % 2 == 0) { acc.add(it) Either.Right(it) @@ -53,7 +53,7 @@ class MapKTest : UnitSpec() { "traverseOption is stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() - val res = (0..20_000).map { it to it }.toMap().traverseOption { a -> + val res = (0..20_000).map { it to it }.toMap().traverse { a -> acc.add(a) Some(a) } @@ -64,7 +64,7 @@ class MapKTest : UnitSpec() { "traverseOption short-circuits" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverseOption { + val evens = ints.traverse { (it % 2 == 0).maybe { acc.add(it) it @@ -84,7 +84,7 @@ class MapKTest : UnitSpec() { "traverseValidated is stacksafe" { val acc = mutableListOf() - val res = (0..20_000).map { it to it }.toMap().traverseValidated(Semigroup.string()) { v -> + val res = (0..20_000).map { it to it }.toMap().traverse(Semigroup.string()) { v -> acc.add(v) Validated.Valid(v) } @@ -95,7 +95,7 @@ class MapKTest : UnitSpec() { "traverseValidated acummulates" { checkAll(Arb.map(Arb.int(), Arb.int())) { ints -> val res: ValidatedNel> = - ints.traverseValidated(Semigroup.nonEmptyList()) { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() } + ints.traverse(Semigroup.nonEmptyList()) { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() } val expected: ValidatedNel> = NonEmptyList.fromList(ints.values.filterNot { it % 2 == 0 }) 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 7bb02f888c5..9722f31bd5c 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 @@ -4,7 +4,6 @@ import arrow.core.test.UnitSpec import arrow.core.test.laws.SemigroupLaws import arrow.typeclasses.Semigroup import io.kotest.property.Arb -import io.kotest.property.checkAll import io.kotest.matchers.shouldBe import io.kotest.property.arbitrary.boolean import io.kotest.property.arbitrary.int @@ -16,10 +15,10 @@ class NonEmptyListTest : UnitSpec() { testLaws(SemigroupLaws.laws(Semigroup.nonEmptyList(), Arb.nonEmptyList(Arb.int()))) - "traverseEither stack-safe" { + "traverse for Either stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() - val res = NonEmptyList.fromListUnsafe((0..20_000).toList()).traverseEither { a -> + val res = NonEmptyList.fromListUnsafe((0..20_000).toList()).traverse { a -> acc.add(a) Either.Right(a) } @@ -27,10 +26,10 @@ class NonEmptyListTest : UnitSpec() { res shouldBe Either.Right(NonEmptyList.fromListUnsafe((0..20_000).toList())) } - "traverseEither short-circuit" { + "traverse for Either short-circuit" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverseEither { + val evens = ints.traverse { if (it % 2 == 0) { acc.add(it) Either.Right(it) @@ -44,17 +43,17 @@ class NonEmptyListTest : UnitSpec() { } } - "sequenceEither should be consistent with traverseEither" { + "sequence for Either should be consistent with traverseEither" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> - ints.map { Either.conditionally(it % 2 == 0, { it }, { it }) }.sequenceEither() shouldBe - ints.traverseEither { Either.conditionally(it % 2 == 0, { it }, { it }) } + ints.map { Either.conditionally(it % 2 == 0, { it }, { it }) }.sequence() shouldBe + ints.traverse { Either.conditionally(it % 2 == 0, { it }, { it }) } } } - "traverseOption is stack-safe" { + "traverse for Option is stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() - val res = NonEmptyList.fromListUnsafe((0..20_000).toList()).traverseOption { a -> + val res = NonEmptyList.fromListUnsafe((0..20_000).toList()).traverse { a -> acc.add(a) Some(a) } @@ -62,10 +61,10 @@ class NonEmptyListTest : UnitSpec() { res shouldBe Some(NonEmptyList.fromListUnsafe((0..20_000).toList())) } - "traverseOption short-circuits" { + "traverse for Option short-circuits" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> val acc = mutableListOf() - val evens = ints.traverseOption { + val evens = ints.traverse { (it % 2 == 0).maybe { acc.add(it) it @@ -76,21 +75,21 @@ class NonEmptyListTest : UnitSpec() { } } - "sequenceOption yields some when all entries in the list are some" { + "sequence for Option yields some when all entries in the list are some" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> - val evens = ints.map { (it % 2 == 0).maybe { it } }.sequenceOption() + val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() evens.fold({ Unit }) { it shouldBe ints } } } - "sequenceOption should be consistent with traverseOption" { + "sequence for Option should be consistent with traverseOption" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> - ints.map { (it % 2 == 0).maybe { it } }.sequenceOption() shouldBe - ints.traverseOption { (it % 2 == 0).maybe { it } } + ints.map { (it % 2 == 0).maybe { it } }.sequence() shouldBe + ints.traverse { (it % 2 == 0).maybe { it } } } } - "traverseValidated stack-safe" { + "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()) { @@ -101,10 +100,10 @@ class NonEmptyListTest : UnitSpec() { res shouldBe Validated.Valid((0..20_000).toList()) } - "traverseValidated acummulates" { + "traverse for Validated acummulates" { checkAll(Arb.nonEmptyList(Arb.int())) { ints -> val res: ValidatedNel> = - ints.traverseValidated(Semigroup.nonEmptyList()) { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() } + ints.traverse(Semigroup.nonEmptyList()) { i: Int -> if (i % 2 == 0) i.validNel() else i.invalidNel() } val expected: ValidatedNel> = NonEmptyList.fromList(ints.filterNot { it % 2 == 0 }) .fold({ NonEmptyList.fromListUnsafe(ints.filter { it % 2 == 0 }).validNel() }, { it.invalid() }) @@ -113,10 +112,10 @@ class NonEmptyListTest : UnitSpec() { } } - "sequenceValidated should be consistent with traverseValidated" { + "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) }.sequenceValidated(Semigroup.int()) shouldBe - ints.traverseValidated(Semigroup.int()) { if (it % 2 == 0) Valid(it) else Invalid(it) } + 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) } } } 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 d4d489c639a..18b3333a4b1 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 @@ -1,12 +1,9 @@ package arrow.core -import arrow.core.computations.OptionEffect -import arrow.core.computations.RestrictedOptionEffect -import arrow.core.computations.ensureNotNull -import arrow.core.computations.option +import arrow.core.continuations.ensureNotNull +import arrow.core.continuations.option import arrow.core.test.UnitSpec import arrow.core.test.generators.option -import arrow.core.test.laws.FxLaws import arrow.core.test.laws.MonoidLaws import arrow.typeclasses.Monoid import io.kotest.matchers.shouldBe @@ -15,10 +12,7 @@ import io.kotest.property.Arb import io.kotest.property.arbitrary.boolean import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.long -import io.kotest.property.arbitrary.map import io.kotest.property.arbitrary.orNull -import io.kotest.property.arbitrary.string -import io.kotest.property.checkAll class OptionTest : UnitSpec() { @@ -141,7 +135,7 @@ class OptionTest : UnitSpec() { "mapNotNull" { some.mapNotNull { it.toIntOrNull() } shouldBe None - some.mapNotNull { it.toUpperCase() } shouldBe Some("KOTLIN") + some.mapNotNull { it.uppercase() } shouldBe Some("KOTLIN") } "fold" { @@ -150,8 +144,8 @@ class OptionTest : UnitSpec() { } "flatMap" { - some.flatMap { Some(it.toUpperCase()) } shouldBe Some("KOTLIN") - none.flatMap { Some(it.toUpperCase()) } shouldBe None + some.flatMap { Some(it.uppercase()) } shouldBe Some("KOTLIN") + none.flatMap { Some(it.uppercase()) } shouldBe None } "align" { @@ -388,26 +382,26 @@ class OptionTest : UnitSpec() { "traverseEither should yield either of option" { val some: Option = Some("value") val none: Option = None - some.traverseEither { it.right() } shouldBe some.right() - none.traverseEither { it.right() } shouldBe none.right() + some.traverse { it.right() } shouldBe some.right() + none.traverse { it.right() } shouldBe none.right() } "sequenceEither should be consistent with traverseEither" { checkAll(Arb.option(Arb.int())) { option -> - option.map { it.right() }.sequenceEither() shouldBe option.traverseEither { it.right() } + option.map { it.right() }.sequence() shouldBe option.traverse{ it.right() } } } "traverseValidated should yield validated of option" { val some: Option = Some("value") val none: Option = None - some.traverseValidated { it.valid() } shouldBe some.valid() - none.traverseValidated { it.valid() } shouldBe none.valid() + some.traverse { it.valid() } shouldBe some.valid() + none.traverse { it.valid() } shouldBe none.valid() } "sequenceValidated should be consistent with traverseValidated" { checkAll(Arb.option(Arb.int())) { option -> - option.map { it.valid() }.sequenceValidated() shouldBe option.traverseValidated { it.valid() } + option.map { it.valid() }.sequence() shouldBe option.traverse { it.valid() } } } 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 29a156b3b73..e732c4f43e5 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 @@ -21,7 +21,7 @@ class SequenceKTest : UnitSpec() { testLaws(MonoidLaws.laws(Monoid.sequence(), Arb.sequence(Arb.int())) { s1, s2 -> s1.toList() == s2.toList() }) - "traverseEither stack-safe" { + "traverse for Either stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() val res = generateSequence(0) { it + 1 }.traverse { a -> @@ -36,7 +36,7 @@ class SequenceKTest : UnitSpec() { res shouldBe Either.Left(Unit) } - "traverseOption stack-safe" { + "traverse for Option stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() val res = generateSequence(0) { it + 1 }.traverse { a -> @@ -49,7 +49,7 @@ class SequenceKTest : UnitSpec() { res shouldBe None } - "traverseValidated stack-safe" { + "traverse for Validated stack-safe" { // also verifies result order and execution order (l to r) val acc = mutableListOf() val res = (0..20_000).asSequence().traverse(Semigroup.string()) { @@ -60,7 +60,7 @@ class SequenceKTest : UnitSpec() { res shouldBe Validated.Valid((0..20_000).toList()) } - "traverseValidated acummulates" { + "traverse for Validated acummulates" { checkAll(Arb.sequence(Arb.int())) { ints -> val res: ValidatedNel> = ints.map { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() } .sequence(Semigroup.nonEmptyList()) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ValidatedTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ValidatedTest.kt index adaeaada31a..db8c178d79a 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ValidatedTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/ValidatedTest.kt @@ -9,7 +9,6 @@ import arrow.core.test.generators.validated import io.kotest.assertions.fail import io.kotest.matchers.nulls.shouldBeNull import io.kotest.property.Arb -import io.kotest.property.checkAll import io.kotest.matchers.shouldBe import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.long @@ -361,21 +360,21 @@ class ValidatedTest : UnitSpec() { } } - "traverseOption should yield option when validated is valid" { + "traverse for Option should yield option when validated is valid" { val valid = Valid("Who") val invalid = Invalid("Nope") - valid.traverseOption { Some(it) } shouldBe Some(Valid("Who")) - invalid.traverseOption { Some(it) } shouldBe None + valid.traverse { Some(it) } shouldBe Some(Valid("Who")) + invalid.traverse { Some(it) } shouldBe None } - "sequenceOption should yield consistent result with traverseOption" { + "sequence for Option should yield consistent result with traverseOption" { checkAll(Arb.string(), Arb.string()) { a: String, b: String -> val valid = Valid(a) val invalid = Invalid(b) - valid.traverseOption { Some(it) } shouldBe valid.map { Some(it) }.sequenceOption() - invalid.traverseOption { Some(it) } shouldBe invalid.map { Some(it) }.sequenceOption() + valid.traverse { Some(it) } shouldBe valid.map { Some(it) }.sequence() + invalid.traverse { Some(it) } shouldBe invalid.map { Some(it) }.sequence() } } @@ -388,32 +387,32 @@ class ValidatedTest : UnitSpec() { invalid.traverseNullable { it }.shouldBeNull() } - "sequenceNullable should yield consistent result with traverseNullable" { + "sequence for Nullable should yield consistent result with traverseNullable" { checkAll(Arb.string(), Arb.string()) { a: String, b: String -> val valid = Valid(a) val invalid = Invalid(b) - valid.traverseNullable { it } shouldBe valid.map { it }.sequenceNullable() - valid.traverseNullable { null } shouldBe valid.map { null }.sequenceNullable() - invalid.traverseNullable { it } shouldBe invalid.map { it }.sequenceNullable() + valid.traverseNullable { it } shouldBe valid.map { it }.sequence() + valid.traverseNullable { null } shouldBe valid.map { null }.sequence() + invalid.traverseNullable { it } shouldBe invalid.map { it }.sequence() } } - "traverseEither should wrap validated in either" { + "traverse for Either should wrap validated in either" { val valid = Valid("Who") val invalid = Invalid("Nope") - valid.traverseEither { it.right() } shouldBe Valid("Who").right() - invalid.traverseEither { it.right() } shouldBe Invalid("Nope").right() + valid.traverse { it.right() } shouldBe Valid("Who").right() + invalid.traverse { it.right() } shouldBe Invalid("Nope").right() } - "sequenceEither should yield consistent result with traverseEither" { + "sequence for Either should yield consistent result with traverseEither" { checkAll(Arb.string(), Arb.string()) { a: String, b: String -> val valid = Valid(a) val invalid = Invalid(b) - valid.traverseEither { Right(it) } shouldBe valid.map { Right(it) }.sequenceEither() - invalid.traverseEither { Right(it) } shouldBe invalid.map { Right(it) }.sequenceEither() + valid.traverse { Right(it) } shouldBe valid.map { Right(it) }.sequence() + invalid.traverse { Right(it) } shouldBe invalid.map { Right(it) }.sequence() } } diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ParTraverseEitherTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ParTraverseEitherTest.kt index e67e0f587be..7cdd933e762 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ParTraverseEitherTest.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ParTraverseEitherTest.kt @@ -3,12 +3,11 @@ package arrow.fx.coroutines import arrow.core.Either import arrow.core.left import arrow.core.right -import arrow.core.sequenceEither +import arrow.core.sequence import io.kotest.matchers.should import io.kotest.matchers.shouldBe import io.kotest.property.Arb import io.kotest.property.arbitrary.int -import io.kotest.property.arbitrary.list import io.kotest.property.arbitrary.string import kotlinx.coroutines.CompletableDeferred @@ -61,7 +60,7 @@ class ParTraverseEitherTest : ArrowFxSpec( val res = l.parTraverseEither { it } if (containsError) l.contains>(res) shouldBe true - else res shouldBe l.sequenceEither() + else res shouldBe l.sequence() } }