Skip to content

Commit

Permalink
change unalign signature (#2972)
Browse files Browse the repository at this point in the history
see discussion in
#2960 (comment)
#2960 (comment)

---------

Co-authored-by: Alejandro Serrano <trupill@gmail.com>
  • Loading branch information
abendt and serras authored Mar 24, 2023
1 parent a460c3b commit 1cdb549
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -793,11 +793,14 @@ public inline fun <A, B, C> Iterable<C>.unzip(fc: (C) -> Pair<A, B>): Pair<List<
* ```
* <!--- KNIT example-iterable-13.kt -->
*/
@Deprecated(
"The current unalign function is renamed to separateIor, and a new unalign function is going to be added to Arrow 2.0.0.",
ReplaceWith("separateIor()", "arrow.core.separateIor")
)
public fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A>, List<B>> = separateIor()
public fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A?>, List<B?>> =
fold(emptyList<A>() to emptyList()) { (l, r), x ->
x.fold(
{ Pair(l + it, r + null) },
{ Pair(l + null, r + it) },
{ a, b -> Pair(l + a, r + b) }
)
}

/**
* after applying the given function, splits the resulting union shaped structure into its components parts
Expand All @@ -817,11 +820,7 @@ public fun <A, B> Iterable<Ior<A, B>>.unalign(): Pair<List<A>, List<B>> = separa
* ```
* <!--- KNIT example-iterable-14.kt -->
*/
@Deprecated(
"The current unalign function is renamed to separateIor, and a new unalign function is going to be added to Arrow 2.0.0.",
ReplaceWith("map(fa).separateIor()", "arrow.core.separateIor")
)
public inline fun <A, B, C> Iterable<C>.unalign(fa: (C) -> Ior<A, B>): Pair<List<A>, List<B>> =
public inline fun <A, B, C> Iterable<C>.unalign(fa: (C) -> Ior<A, B>): Pair<List<A?>, List<B?>> =
map(fa).unalign()

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package arrow.core

import arrow.core.test.either
import arrow.core.test.functionAToB
import arrow.core.test.ior
import arrow.core.test.functionAToB
import arrow.core.test.option
import arrow.typeclasses.Semigroup
import io.kotest.core.spec.style.StringSpec
Expand Down Expand Up @@ -325,15 +325,29 @@ class IterableTest : StringSpec({
}

"unalign is the inverse of align" {
fun <A, B> Pair<List<A?>, List<B?>>.fix(): Pair<List<A>, List<B>> =
first.mapNotNull { it } to second.mapNotNull { it }

checkAll(Arb.list(Arb.int()), Arb.list(Arb.string())) { a, b ->
a.align(b).unalign() shouldBe (a to b)
a.align(b).unalign().fix() shouldBe (a to b)
}
}

"align is the inverse of unalign" {
fun <A, B> Ior<A?, B?>.fix(): Ior<A, B> =
fold({ Ior.Left(it!!) }, { Ior.Right(it!!) }, { a, b ->
when {
a == null -> Ior.Right(b!!)
b == null -> Ior.Left(a)
else -> Ior.Both(a, b)
}
})

checkAll(Arb.list(Arb.ior(Arb.int(), Arb.string()))) { xs ->
val (a, b) = xs.unalign()
a.align(b) shouldBe xs
a.align(b) {
it.fix()
} shouldBe xs
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ fun <A, B> Arb.Companion.ior(arbA: Arb<A>, arbB: Arb<B>): Arb<Ior<A, B>> =
arbA.alignWith(arbB) { it }

private fun <A, B, R> Arb<A>.alignWith(arbB: Arb<B>, transform: (Ior<A, B>) -> R): Arb<R> =
Arb.bind(this, arbB) { a, b -> transform(Ior.Both(a, b)) }
Arb.choice(
this.map { Ior.Left(it) },
Arb.bind(this, arbB) { a, b -> Ior.Both(a, b) },
arbB.map { Ior.Right(it) }
).map(transform)


fun Arb.Companion.suspendFunThatReturnsEitherAnyOrAnyOrThrows(): Arb<suspend () -> Either<Any, Any>> =
choice(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package arrow.core.test

import io.kotest.assertions.assertSoftly
import io.kotest.core.spec.style.StringSpec
import io.kotest.inspectors.forAtLeastOne
import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.list
import io.kotest.property.arbitrary.next
import io.kotest.property.arbitrary.string

class GeneratorsTest : StringSpec({
"Arb.ior should generate Left, Right & Both" {
assertSoftly(Arb.list(Arb.ior(Arb.string(), Arb.int()), range = 20 .. 100).next()) {
forAtLeastOne {
it.isRight().shouldBeTrue()
}
forAtLeastOne {
it.isBoth().shouldBeTrue()
}
forAtLeastOne {
it.isLeft().shouldBeTrue()
}
}
}
})

0 comments on commit 1cdb549

Please sign in to comment.