From 5ebcd2b91f4ea3c350b80817d7b3f244d8c9504d Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 18 Jan 2023 14:49:03 +0100 Subject: [PATCH 1/4] Add flattenOrAccumulate --- .../commonMain/kotlin/arrow/core/Iterable.kt | 105 ++- .../kotlin/arrow/core/IterableTest.kt | 828 +++++++++--------- 2 files changed, 518 insertions(+), 415 deletions(-) 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 813eb0e110a..dc6464125eb 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 @@ -283,7 +283,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) @@ -300,7 +303,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) @@ -319,18 +325,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 @@ -350,6 +365,7 @@ public inline fun Iterable.traverse( is Valid -> acc.also { it.value.add(res.value) } is Invalid -> acc } + is Validated.Invalid -> when (acc) { is Valid -> res is Invalid -> Invalid(acc.value.combine(res.value)) @@ -358,7 +374,10 @@ public inline fun Iterable.traverse( } } -@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) @@ -367,21 +386,30 @@ public inline fun Iterable.traverseValidated(f: (A) -> ValidatedNel public inline fun Iterable.traverse(f: (A) -> ValidatedNel): ValidatedNel> = traverse(Semigroup.nonEmptyList(), f) -@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) public fun Iterable>.sequence(semigroup: Semigroup): Validated> = traverse(semigroup, ::identity) -@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) +@Deprecated( + "sequenceValidated is being renamed to sequence to simplify the Arrow API", + ReplaceWith("sequence()", "arrow.core.sequence") +) public fun Iterable>.sequenceValidated(): ValidatedNel> = sequence() public fun Iterable>.sequence(): ValidatedNel> = traverse(Semigroup.nonEmptyList(), ::identity) -@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) @@ -398,14 +426,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) @@ -424,10 +458,52 @@ 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() +/** + * Flatten a list of [Either] into a single [Either] with a list of values, or accumulates all errors using [combine]. + */ +public inline fun Iterable>.flattenOrAccumulate(combine: (Error, Error) -> Error): Either> = + fold, Either>>(Right(ArrayList(collectionSizeOrDefault(10)))) { acc, res -> + when (res) { + is Right -> when (acc) { + is Right -> acc.also { acc.value.add(res.value) } + is Left -> acc + } + + is Left -> when (acc) { + is Right -> res + is Left -> Left(combine(acc.value, res.value)) + } + } + } + +/** + * Flatten a list of [Either] into a single [Either] with a list of values, or accumulates all errors with into an [NonEmptyList]. + */ +public fun Iterable>.flattenOrAccumulate(): Either, List> { + val buffer = mutableListOf() + val res = fold, Either, ArrayList>>(Right(ArrayList(collectionSizeOrDefault(10)))) { acc, res -> + when (res) { + is Right -> when (acc) { + is Right -> acc.also { acc.value.add(res.value) } + is Left -> acc + } + + is Left -> when (acc) { + is Right -> Left(buffer.also { it.add(res.value) }) + is Left -> Left(buffer.also { it.add(res.value) }) + } + } + } + return res.mapLeft { NonEmptyList(it[0], it.drop(1)) } +} + public fun Iterable.sequence(): List? = traverse(::identity) @@ -784,6 +860,7 @@ public fun Iterable.firstOrNone(): Option = } else { None } + else -> { iterator().nextOrNone() } @@ -817,6 +894,7 @@ public fun Iterable.singleOrNone(): Option = 1 -> firstOrNone() else -> None } + else -> { iterator().run { nextOrNone().filter { !hasNext() } } } @@ -848,6 +926,7 @@ public fun Iterable.lastOrNone(): Option = } else { None } + else -> iterator().run { if (hasNext()) { var last: T @@ -882,6 +961,7 @@ public fun Iterable.elementAtOrNone(index: Int): Option = in indices -> Some(elementAt(index)) else -> None } + else -> iterator().skip(index).nextOrNone() } @@ -891,6 +971,7 @@ private tailrec fun Iterator.skip(count: Int): Iterator = next() skip(count - 1) } + else -> this } 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 e09da510e95..ac25ba9a834 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 @@ -21,483 +21,505 @@ import kotlin.math.min class IterableTest : StringSpec({ - "traverse Either stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Either.Right(a) - } - res shouldBe Either.Right(acc) - res shouldBe Either.Right((0..20_000).toList()) - } - - "traverse Either short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Either.Right(it) - } else Either.Left(it) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - when (evens) { - is Either.Right -> evens.value shouldBe ints - is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } - } - } + "traverse Either stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a -> + acc.add(a) + Either.Right(a) } + res shouldBe Either.Right(acc) + res shouldBe Either.Right((0..20_000).toList()) + } - "sequenceEither should be consistent with traverse Either" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } - } - } + "flattenOrAccumulate(combine)" { + checkAll(Arb.list(Arb.either(Arb.string(), Arb.int()))) { list -> + val expected = + if (list.any { it.isLeft() }) list.filterIsInstance>() + .fold("") { acc, either -> "$acc${either.value}" }.left() + else list.filterIsInstance>().map { it.value }.right() - "traverse Result stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Result.success(a) - } - res shouldBe Result.success(acc) - res shouldBe Result.success((0..20_000).toList()) - } - - "traverse Result short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Result.success(it) - } else Result.failure(RuntimeException()) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold( - { it shouldBe ints }, - { } - ) - } + list.flattenOrAccumulate { a, b -> "$a$b" } shouldBe expected } + } - "sequence Result should be consistent with traverse Result" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } - } - } + "flattenOrAccumulate" { + checkAll(Arb.list(Arb.either(Arb.string(), Arb.int()))) { list -> + val expected = + if (list.any { it.isLeft() }) list.filterIsInstance>() + .map { it.value }.toNonEmptyListOrNull().shouldNotBeNull().left() + else list.filterIsInstance>().map { it.value }.right() - "traverse Option is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - Some(a) - } - res shouldBe Some(acc) - res shouldBe Some((0..20_000).toList()) - } - - "traverse Option short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - (it % 2 == 0).maybe { - acc.add(it) - it - } - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold({ Unit }) { it shouldBe ints } - } + list.flattenOrAccumulate() shouldBe expected } + } - "sequence Option yields some when all entries in the list are some" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() - evens.fold({ Unit }) { it shouldBe ints } - } - } - - "sequence Option should be consistent with traverse Option" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } - } - } - - "traverse Nullable is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - a + "traverse Either short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Either.Right(it) + } else Either.Left(it) } - res.shouldNotBeNull() shouldBe acc - res.shouldNotBeNull() shouldBe (0..20_000).toList() - } - - "traverse Nullable short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - it - } else { - null - } - } - - val expected = ints.takeWhile { it % 2 == 0 } - acc shouldBe expected - - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly expected - } + acc shouldBe ints.takeWhile { it % 2 == 0 } + when (evens) { + is Either.Right -> evens.value shouldBe ints + is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } } } + } - "sequence Nullable yields some when all entries in the list are not null" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { if (it % 2 == 0) it else null }.sequence() - - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } - } - } + "sequenceEither should be consistent with traverse Either" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } } + } - "sequence Nullable should be consistent with travers Nullable" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } - } + "traverse Result stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a -> + acc.add(a) + Result.success(a) } + res shouldBe Result.success(acc) + res shouldBe Result.success((0..20_000).toList()) + } - "traverse Validated stack-safe" { - // also verifies result order and execution order (l to r) + "traverse Result short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val res = (0..20_000).traverse(Semigroup.string()) { - acc.add(it) - Validated.Valid(it) - } - res shouldBe Validated.Valid(acc) - res shouldBe Validated.Valid((0..20_000).toList()) - } - - "traverse Validated acumulates" { - checkAll(Arb.list(Arb.int())) { ints -> - val res: ValidatedNel> = - ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } - .sequence() - - val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } - .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) - - res shouldBe expected + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Result.success(it) + } else Result.failure(RuntimeException()) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold( + { it shouldBe ints }, + { } + ) + } + } + + "sequence Result should be consistent with traverse Result" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } + } + } + + "traverse Option is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + Some(a) + } + res shouldBe Some(acc) + res shouldBe Some((0..20_000).toList()) + } + + "traverse Option short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + (it % 2 == 0).maybe { + acc.add(it) + it + } } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold({ Unit }) { it shouldBe ints } } + } - "sequence Validated should be consistent with traverse Validated" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe - ints.traverse(Semigroup.string()) { it.valid() } - } + "sequence Option yields some when all entries in the list are some" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() + evens.fold({ Unit }) { it shouldBe ints } } + } - "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { - checkAll( - Arb.list(Arb.int()), - Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) - ) { ints, f -> - - val res: Either>? = - ints.traverse(f)?.sequence() - - val expected: Either>? = - ints.map(f).sequence()?.sequence() - - res shouldBe expected - } + "sequence Option should be consistent with traverse Option" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } } + } - "zip3" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> - val result = a.zip(b, c, ::Triple) - val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } - result shouldBe expected - } + "traverse Nullable is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + a } + res.shouldNotBeNull() shouldBe acc + res.shouldNotBeNull() shouldBe (0..20_000).toList() + } - "zip4" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> - val result = a.zip(b, c, d, ::Tuple4) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - - result shouldBe expected + "traverse Nullable short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + it + } else { + null + } } - } - "zip5" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e -> - val result = a.zip(b, c, d, e, ::Tuple5) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - - result shouldBe expected - } - } + val expected = ints.takeWhile { it % 2 == 0 } + acc shouldBe expected - "zip6" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f -> - val result = a.zip(b, c, d, e, f, ::Tuple6) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - - result shouldBe expected + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly expected } } + } - "zip7" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g -> - val result = a.zip(b, c, d, e, f, g, ::Tuple7) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - - result shouldBe expected - } - } + "sequence Nullable yields some when all entries in the list are not null" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { if (it % 2 == 0) it else null }.sequence() - "zip8" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h -> - val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - - result shouldBe expected + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } } } + } - "zip9" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i -> - val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - - result shouldBe expected - } + "sequence Nullable should be consistent with travers Nullable" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } } + } - "zip10" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i, j -> - val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } - - result shouldBe expected - } + "traverse 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) + Validated.Valid(it) } + res shouldBe Validated.Valid(acc) + res shouldBe Validated.Valid((0..20_000).toList()) + } - "can align lists with different lengths" { - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).size shouldBe max(a.size, b.size) - } + "traverse Validated acumulates" { + checkAll(Arb.list(Arb.int())) { ints -> + val res: ValidatedNel> = + ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } + .sequence() + + val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } + .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) + + res shouldBe expected + } + } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).take(min(a.size, b.size)).forEach { - it.isBoth shouldBe true - } - } - - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).drop(min(a.size, b.size)).forEach { - if (a.size < b.size) { - it.isRight shouldBe true - } else { - it.isLeft shouldBe true - } + "sequence Validated should be consistent with traverse Validated" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe + ints.traverse(Semigroup.string()) { it.valid() } + } + } + + "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { + checkAll( + Arb.list(Arb.int()), + Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) + ) { ints, f -> + + val res: Either>? = + ints.traverse(f)?.sequence() + + val expected: Either>? = + ints.map(f).sequence()?.sequence() + + res shouldBe expected + } + } + + "zip3" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> + val result = a.zip(b, c, ::Triple) + val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } + result shouldBe expected + } + } + + "zip4" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> + val result = a.zip(b, c, d, ::Tuple4) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + + result shouldBe expected + } + } + + "zip5" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e -> + val result = a.zip(b, c, d, e, ::Tuple5) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + + result shouldBe expected + } + } + + "zip6" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f -> + val result = a.zip(b, c, d, e, f, ::Tuple6) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + + result shouldBe expected + } + } + + "zip7" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g -> + val result = a.zip(b, c, d, e, f, g, ::Tuple7) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + + result shouldBe expected + } + } + + "zip8" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h -> + val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + + result shouldBe expected + } + } + + "zip9" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i -> + val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + + result shouldBe expected + } + } + + "zip10" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i, j -> + val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } + + result shouldBe expected + } + } + + "can align lists with different lengths" { + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).size shouldBe max(a.size, b.size) + } + + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).take(min(a.size, b.size)).forEach { + it.isBoth shouldBe true + } + } + + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).drop(min(a.size, b.size)).forEach { + if (a.size < b.size) { + it.isRight shouldBe true + } else { + it.isLeft shouldBe true } } } + } - "leftPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) { a, b -> a to b } + val result = a.leftPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } } + } - "leftPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) + val result = a.leftPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } } + } - "rightPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) + val result = a.rightPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a } + } - "rightPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) { a, b -> a to b } + val result = a.rightPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a } + } - "padZip" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } - } + "padZip" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } } + } - "padZipWithNull" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "padZipWithNull" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } - } + a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } } + } - "filterOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } - } + "filterOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } } + } - "flattenOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } - } + "flattenOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } } + } - "separateEither" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.left() - else it.right() - } - list.separateEither() shouldBe ints.partition { it % 2 == 0 } + "separateEither" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.left() + else it.right() } + list.separateEither() shouldBe ints.partition { it % 2 == 0 } } + } - "separateValidated" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.invalid() - else it.valid() - } - list.separateValidated() shouldBe ints.partition { it % 2 == 0 } + "separateValidated" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.invalid() + else it.valid() } + list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } + } }) From 668469ecfa96c69ed2aba4584fbd959b54033254 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 18 Jan 2023 14:50:37 +0100 Subject: [PATCH 2/4] Remove unrelated formatting in Iterable.kt --- .../commonMain/kotlin/arrow/core/Iterable.kt | 66 ++++--------------- 1 file changed, 12 insertions(+), 54 deletions(-) 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 dc6464125eb..d5164c25a46 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 @@ -283,10 +283,7 @@ 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) @@ -303,10 +300,7 @@ 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) @@ -325,27 +319,18 @@ 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 @@ -365,7 +350,6 @@ public inline fun Iterable.traverse( is Valid -> acc.also { it.value.add(res.value) } is Invalid -> acc } - is Validated.Invalid -> when (acc) { is Valid -> res is Invalid -> Invalid(acc.value.combine(res.value)) @@ -374,10 +358,7 @@ public inline fun Iterable.traverse( } } -@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) @@ -386,30 +367,21 @@ public inline fun Iterable.traverseValidated(f: (A) -> ValidatedNel public inline fun Iterable.traverse(f: (A) -> ValidatedNel): ValidatedNel> = traverse(Semigroup.nonEmptyList(), f) -@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) public fun Iterable>.sequence(semigroup: Semigroup): Validated> = traverse(semigroup, ::identity) -@Deprecated( - "sequenceValidated is being renamed to sequence to simplify the Arrow API", - ReplaceWith("sequence()", "arrow.core.sequence") -) +@Deprecated("sequenceValidated is being renamed to sequence to simplify the Arrow API", ReplaceWith("sequence()", "arrow.core.sequence")) public fun Iterable>.sequenceValidated(): ValidatedNel> = sequence() public fun Iterable>.sequence(): ValidatedNel> = traverse(Semigroup.nonEmptyList(), ::identity) -@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) @@ -426,20 +398,14 @@ 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) @@ -458,10 +424,7 @@ 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() @@ -860,7 +823,6 @@ public fun Iterable.firstOrNone(): Option = } else { None } - else -> { iterator().nextOrNone() } @@ -894,7 +856,6 @@ public fun Iterable.singleOrNone(): Option = 1 -> firstOrNone() else -> None } - else -> { iterator().run { nextOrNone().filter { !hasNext() } } } @@ -926,7 +887,6 @@ public fun Iterable.lastOrNone(): Option = } else { None } - else -> iterator().run { if (hasNext()) { var last: T @@ -961,7 +921,6 @@ public fun Iterable.elementAtOrNone(index: Int): Option = in indices -> Some(elementAt(index)) else -> None } - else -> iterator().skip(index).nextOrNone() } @@ -971,7 +930,6 @@ private tailrec fun Iterator.skip(count: Int): Iterator = next() skip(count - 1) } - else -> this } From 8b97fb79b0bba8e50cc1fc97fdb0014105a524e0 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 18 Jan 2023 14:54:52 +0100 Subject: [PATCH 3/4] Remove formatting IterableTest.kt --- .../kotlin/arrow/core/IterableTest.kt | 756 +++++++++--------- 1 file changed, 378 insertions(+), 378 deletions(-) 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 ac25ba9a834..84e3782a02f 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 @@ -21,17 +21,6 @@ import kotlin.math.min class IterableTest : StringSpec({ - "traverse Either stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Either.Right(a) - } - res shouldBe Either.Right(acc) - res shouldBe Either.Right((0..20_000).toList()) - } - "flattenOrAccumulate(combine)" { checkAll(Arb.list(Arb.either(Arb.string(), Arb.int()))) { list -> val expected = @@ -54,472 +43,483 @@ class IterableTest : StringSpec({ } } - "traverse Either short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Either stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Either.Right(it) - } else Either.Left(it) + val res = (0..20_000).traverse { a -> + acc.add(a) + Either.Right(a) } - acc shouldBe ints.takeWhile { it % 2 == 0 } - when (evens) { - is Either.Right -> evens.value shouldBe ints - is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } + res shouldBe Either.Right(acc) + res shouldBe Either.Right((0..20_000).toList()) + } + + "traverse Either short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Either.Right(it) + } else Either.Left(it) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + when (evens) { + is Either.Right -> evens.value shouldBe ints + is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } + } } } - } - - "sequenceEither should be consistent with traverse Either" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } - } - } - "traverse Result stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Result.success(a) + "sequenceEither should be consistent with traverse Either" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } + } } - res shouldBe Result.success(acc) - res shouldBe Result.success((0..20_000).toList()) - } - "traverse Result short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Result stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Result.success(it) - } else Result.failure(RuntimeException()) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold( - { it shouldBe ints }, - { } - ) - } - } - - "sequence Result should be consistent with traverse Result" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } + val res = (0..20_000).traverse { a -> + acc.add(a) + Result.success(a) + } + res shouldBe Result.success(acc) + res shouldBe Result.success((0..20_000).toList()) + } + + "traverse Result short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Result.success(it) + } else Result.failure(RuntimeException()) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold( + { it shouldBe ints }, + { } + ) + } } - } - "traverse Option is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - Some(a) + "sequence Result should be consistent with traverse Result" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } + } } - res shouldBe Some(acc) - res shouldBe Some((0..20_000).toList()) - } - "traverse Option short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Option is stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - (it % 2 == 0).maybe { - acc.add(it) - it + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + Some(a) + } + res shouldBe Some(acc) + res shouldBe Some((0..20_000).toList()) + } + + "traverse Option short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + (it % 2 == 0).maybe { + acc.add(it) + it + } } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold({ Unit }) { it shouldBe ints } } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold({ Unit }) { it shouldBe ints } - } - } - - "sequence Option yields some when all entries in the list are some" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() - evens.fold({ Unit }) { it shouldBe ints } } - } - "sequence Option should be consistent with traverse Option" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } + "sequence Option yields some when all entries in the list are some" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() + evens.fold({ Unit }) { it shouldBe ints } + } } - } - "traverse Nullable is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - a + "sequence Option should be consistent with traverse Option" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } + } } - res.shouldNotBeNull() shouldBe acc - res.shouldNotBeNull() shouldBe (0..20_000).toList() - } - "traverse Nullable short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - it - } else { - null - } + "traverse Nullable is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + a } + res.shouldNotBeNull() shouldBe acc + res.shouldNotBeNull() shouldBe (0..20_000).toList() + } + + "traverse Nullable short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + it + } else { + null + } + } - val expected = ints.takeWhile { it % 2 == 0 } - acc shouldBe expected + val expected = ints.takeWhile { it % 2 == 0 } + acc shouldBe expected - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly expected + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly expected + } } } - } - "sequence Nullable yields some when all entries in the list are not null" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { if (it % 2 == 0) it else null }.sequence() + "sequence Nullable yields some when all entries in the list are not null" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { if (it % 2 == 0) it else null }.sequence() - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } + } } } - } - "sequence Nullable should be consistent with travers Nullable" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + "sequence Nullable should be consistent with travers Nullable" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + } } - } - "traverse 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) - Validated.Valid(it) + "traverse 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) + Validated.Valid(it) + } + res shouldBe Validated.Valid(acc) + res shouldBe Validated.Valid((0..20_000).toList()) } - res shouldBe Validated.Valid(acc) - res shouldBe Validated.Valid((0..20_000).toList()) - } - "traverse Validated acumulates" { - checkAll(Arb.list(Arb.int())) { ints -> - val res: ValidatedNel> = - ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } - .sequence() + "traverse Validated acumulates" { + checkAll(Arb.list(Arb.int())) { ints -> + val res: ValidatedNel> = + ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } + .sequence() - val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } - .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) + val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } + .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) - res shouldBe expected + res shouldBe expected + } } - } - "sequence Validated should be consistent with traverse Validated" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe - ints.traverse(Semigroup.string()) { it.valid() } + "sequence Validated should be consistent with traverse Validated" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe + ints.traverse(Semigroup.string()) { it.valid() } + } } - } - "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { - checkAll( - Arb.list(Arb.int()), - Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) - ) { ints, f -> + "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { + checkAll( + Arb.list(Arb.int()), + Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) + ) { ints, f -> - val res: Either>? = - ints.traverse(f)?.sequence() + val res: Either>? = + ints.traverse(f)?.sequence() - val expected: Either>? = - ints.map(f).sequence()?.sequence() + val expected: Either>? = + ints.map(f).sequence()?.sequence() - res shouldBe expected + res shouldBe expected + } } - } - "zip3" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> - val result = a.zip(b, c, ::Triple) - val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } - result shouldBe expected + "zip3" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> + val result = a.zip(b, c, ::Triple) + val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } + result shouldBe expected + } } - } - "zip4" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> - val result = a.zip(b, c, d, ::Tuple4) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + "zip4" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> + val result = a.zip(b, c, d, ::Tuple4) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - result shouldBe expected + result shouldBe expected + } } - } - "zip5" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e -> - val result = a.zip(b, c, d, e, ::Tuple5) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - - result shouldBe expected + "zip5" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e -> + val result = a.zip(b, c, d, e, ::Tuple5) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + + result shouldBe expected + } } - } - "zip6" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f -> - val result = a.zip(b, c, d, e, f, ::Tuple6) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - - result shouldBe expected + "zip6" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f -> + val result = a.zip(b, c, d, e, f, ::Tuple6) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + + result shouldBe expected + } } - } - "zip7" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g -> - val result = a.zip(b, c, d, e, f, g, ::Tuple7) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - - result shouldBe expected + "zip7" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g -> + val result = a.zip(b, c, d, e, f, g, ::Tuple7) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + + result shouldBe expected + } } - } - "zip8" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h -> - val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - - result shouldBe expected + "zip8" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h -> + val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + + result shouldBe expected + } } - } - "zip9" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i -> - val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - - result shouldBe expected + "zip9" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i -> + val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + + result shouldBe expected + } } - } - "zip10" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i, j -> - val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } - - result shouldBe expected + "zip10" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i, j -> + val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } + + result shouldBe expected + } } - } - "can align lists with different lengths" { - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).size shouldBe max(a.size, b.size) - } + "can align lists with different lengths" { + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).size shouldBe max(a.size, b.size) + } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).take(min(a.size, b.size)).forEach { - it.isBoth shouldBe true + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).take(min(a.size, b.size)).forEach { + it.isBoth shouldBe true + } } - } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).drop(min(a.size, b.size)).forEach { - if (a.size < b.size) { - it.isRight shouldBe true - } else { - it.isLeft shouldBe true + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).drop(min(a.size, b.size)).forEach { + if (a.size < b.size) { + it.isRight shouldBe true + } else { + it.isLeft shouldBe true + } } } } - } - "leftPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) { a, b -> a to b } + val result = a.leftPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + } } - } - "leftPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) + val result = a.leftPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + } } - } - "rightPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) + val result = a.rightPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a + } } - } - "rightPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) { a, b -> a to b } + val result = a.rightPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a + } } - } - "padZip" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } + "padZip" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } + } } - } - "padZipWithNull" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "padZipWithNull" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } + a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } + } } - } - "filterOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } + "filterOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } + } } - } - "flattenOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } + "flattenOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } + } } - } - "separateEither" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.left() - else it.right() + "separateEither" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.left() + else it.right() + } + list.separateEither() shouldBe ints.partition { it % 2 == 0 } } - list.separateEither() shouldBe ints.partition { it % 2 == 0 } } - } - "separateValidated" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.invalid() - else it.valid() + "separateValidated" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.invalid() + else it.valid() + } + list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } - list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } - } }) From 9eeec0752c38b9ef10df6063c951699ad6c19cd9 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 18 Jan 2023 15:02:28 +0100 Subject: [PATCH 4/4] apiDump --- arrow-libs/core/arrow-core/api/arrow-core.api | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 5e69f590c55..1f9bc538ff3 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -587,6 +587,8 @@ public final class arrow/core/IterableKt { public static final fun firstOrNone (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun flatten (Ljava/lang/Iterable;)Ljava/util/List; public static final fun flattenOption (Ljava/lang/Iterable;)Ljava/util/List; + public static final fun flattenOrAccumulate (Ljava/lang/Iterable;)Larrow/core/Either; + public static final fun flattenOrAccumulate (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Larrow/core/Either; public static final fun fold (Ljava/lang/Iterable;Larrow/typeclasses/Monoid;)Ljava/lang/Object; public static final fun foldMap (Ljava/lang/Iterable;Larrow/typeclasses/Monoid;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun getListUnit ()Ljava/util/List;