Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecation of Semigroup and Monoid #2935

Merged
merged 37 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
25701ca
Start deprecation of Semigroup and Monoid
serras Feb 17, 2023
c04602d
Deprecation for EmptyValue
serras Feb 17, 2023
915b740
Update API files
serras Feb 17, 2023
848b423
Deprecation for map
serras Feb 17, 2023
42d32c5
Update API files
serras Feb 17, 2023
bb4234c
Deprecation for NonEmptyList, Option, and Pair
serras Feb 17, 2023
1fd6dde
Deprecation for Raise builders
serras Feb 17, 2023
c45c6d4
Merge branch 'main' into deprecate-semigroup-monoid
serras Feb 17, 2023
f47a982
Merge branch 'main' into deprecate-semigroup-monoid
serras Feb 23, 2023
5148d55
Deprecation for Ior and zips
serras Feb 23, 2023
570634d
Update API files
serras Feb 23, 2023
e58c82f
Merge branch 'main' into deprecate-semigroup-monoid
serras Feb 23, 2023
0ecbcb4
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Op…
serras Feb 27, 2023
c50c804
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Op…
serras Feb 27, 2023
1d509a8
Merge branch 'main' into deprecate-semigroup-monoid
serras Mar 2, 2023
b8e0086
Remove emptyCombine + add missing Validated#zip
serras Mar 2, 2023
1020548
Fix more merge woes
serras Mar 2, 2023
7deae73
Fix incorrect 'combine' implementation
serras Mar 3, 2023
316809f
Remove unnecessary combine
serras Mar 3, 2023
9f367da
More Either woes
serras Mar 3, 2023
21fa9e5
Merge remote-tracking branch 'origin/main' into deprecate-semigroup-m…
nomisRev Mar 7, 2023
bccec6e
Update PR, introduce Semigroup::combine, and revert Ior changes in fa…
nomisRev Mar 7, 2023
627a8a5
Merge remote-tracking branch 'origin/main' into deprecate-semigroup-m…
nomisRev Mar 8, 2023
5ff3a7b
Revert unrelated change
nomisRev Mar 8, 2023
58c9296
A few improvements
serras Mar 8, 2023
d0e4c81
Deprecate Semiring
serras Mar 8, 2023
212e706
Rework Laws
serras Mar 8, 2023
bc0f97c
Update API files
serras Mar 8, 2023
1f31084
GitHub Actions
serras Mar 8, 2023
38f362e
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
nomisRev Mar 8, 2023
bbe260a
Merge branch 'main' into deprecate-semigroup-monoid
serras Mar 9, 2023
439c8e3
Try to fix Native compilation
serras Mar 9, 2023
7779714
Deprecate Const, Endo, Semigroup constructors, and revert Either#comb…
nomisRev Mar 10, 2023
28ba065
Merge branch 'deprecate-semigroup-monoid' of github.com:arrow-kt/arro…
nomisRev Mar 10, 2023
b13ebe9
Merge remote-tracking branch 'origin/main' into deprecate-semigroup-m…
nomisRev Mar 10, 2023
cdd5e50
Update API files
nomisRev Mar 10, 2023
ac8e6a2
Retrigger CI
nomisRev Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2298,15 +2298,15 @@ public operator fun <A : Comparable<A>, B : Comparable<B>> Either<A, B>.compareT
* otherwise it returns the `this` or fallbacks to [other] in case `this` is [Left].
*/
public fun <A, B> Either<A, B>.combine(other: Either<A, B>, combineLeft: (A, A) -> A, combineRight: (B, B) -> B): Either<A, B> =
when (this) {
when (val one = this) {
is Left -> when (other) {
is Left -> Left(combineLeft(value, other.value))
is Right -> this
is Left -> Left(combineLeft(one.value, other.value))
is Right -> one
}

is Right -> when (other) {
is Left -> other
is Right -> Right(combineRight(this@combine.value, other.value))
is Right -> Right(combineRight(one.value, other.value))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -840,21 +840,17 @@ public fun <A> Iterable<A>.salign(
other: Iterable<A>
): Iterable<A> =
align(other) {
it.fold(::identity, ::identity) { a, b ->
combine(a, b)
}
it.fold(::identity, ::identity, combine)
}

/**
* aligns two structures and combine them with the given [Semigroup.combine]
*/
@Deprecated(SemigroupDeprecation, ReplaceWith("salign({ a, b -> SG.run { a.combine(b) } }, other)"))
@Deprecated(SemigroupDeprecation, ReplaceWith("salign(SG::combine, other)"))
nomisRev marked this conversation as resolved.
Show resolved Hide resolved
public fun <A> Iterable<A>.salign(
nomisRev marked this conversation as resolved.
Show resolved Hide resolved
SG: Semigroup<A>,
other: Iterable<A>
): Iterable<A> = SG.run {
salign({ a, b -> a.combine(b) }, other)
}
): Iterable<A> = salign(SG::combine, other)

/**
* unzips the structure holding the resulting elements in an `Pair`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,6 @@ public class IorRaise<E> @PublishedApi internal constructor(

private fun combine(other: E): E =
state.updateAndGet { prev ->
prev.map { combineError(it, other) }.orElse { Some(other) }
Some(prev.map { combineError(it, other) }.getOrElse { other })
}.getOrElse { other }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ public const val FloatInstanceDeprecation: String =
public const val DoubleInstanceDeprecation: String =
"Double instances for Semigroup/Monoid & Semiring are deprecated. Due to how equality of floating-point numbers work, they're not lawful under equality."

public const val SemiringDeprecation: String =
"Semiring is being deprecated."

/**
* The [Semiring] type class for a given type `A` combines both a commutative additive [Monoid] and a multiplicative [Monoid].
* It requires the multiplicative [Monoid] to distribute over the additive one. The operations of the multiplicative [Monoid] have been renamed to
Expand Down Expand Up @@ -83,6 +86,7 @@ public const val DoubleInstanceDeprecation: String =
* ```
* <!--- KNIT example-semiring-04.kt -->
*/
@Deprecated(SemiringDeprecation)
public interface Semiring<A> {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package arrow.core

import arrow.core.test.laws.MonoidLaws
import arrow.core.test.testLaws
import arrow.typeclasses.Monoid
import io.kotest.core.spec.style.StringSpec
import io.kotest.property.Arb
import io.kotest.property.arbitrary.boolean

class BooleanTest : StringSpec({
testLaws(
MonoidLaws.laws(Monoid.boolean(), Arb.boolean())
MonoidLaws(true, { x, y -> x && y }, Arb.boolean())
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,7 @@ class EitherTest : StringSpec({
val ARB = Arb.either(Arb.string(), Arb.int())

testLaws(
MonoidLaws.laws(Monoid.either(Monoid.string(), Monoid.int()), ARB),
/*FxLaws.suspended<EitherEffect<String, *>, Either<String, Int>, Int>(
Arb.int().map(::Right),
ARB.map { it },
Either<String, Int>::equals,
either::invoke
) {
it.bind()
},
FxLaws.eager<RestrictedEitherEffect<String, *>, Either<String, Int>, Int>(
Arb.int().map(::Right),
ARB.map { it },
Either<String, Int>::equals,
either::eager
) {
it.bind()
}*/
MonoidLaws(0.right(), { x, y -> x.combine(y, String::plus, Int::plus) }, ARB)
)

"isLeft should return true if Left and false if Right" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package arrow.core
import arrow.core.test.endo
import arrow.core.test.laws.MonoidLaws
import arrow.core.test.testLaws
import arrow.typeclasses.Monoid
import io.kotest.core.spec.style.StringSpec
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int

class EndoTest : StringSpec({

testLaws(
MonoidLaws.laws(Monoid.endo(), Arb.endo(Arb.int())) { a, b ->
MonoidLaws(Endo(::identity), { f, g -> Endo(f.f.compose(g.f)) }, Arb.endo(Arb.int())) { a, b ->
a.f(1) == b.f(1)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package arrow.core
import arrow.core.test.ior
import arrow.core.test.laws.SemigroupLaws
import arrow.core.test.testLaws
import arrow.typeclasses.Semigroup
import io.kotest.core.spec.style.StringSpec
import io.kotest.data.forAll
import io.kotest.data.row
Expand All @@ -20,12 +19,11 @@ class IorTest : StringSpec({
val ARB = Arb.ior(Arb.string(), Arb.int())

testLaws(
SemigroupLaws.laws(Semigroup.ior(Semigroup.string(), Semigroup.int()), ARB)
SemigroupLaws( { x, y -> x.combine(String::plus, Int::plus, y) }, ARB)
)

val nullableLongSemigroup = object : Semigroup<Long?> {
override fun Long?.combine(b: Long?): Long? =
Nullable.zip(this, b) { a, bb -> a + bb }
val nullableLongSemigroup: (Long?, Long?) -> Long? = { x, y ->
Nullable.zip(x, y, Long::plus)
}

"zip identity" {
Expand Down Expand Up @@ -78,7 +76,7 @@ class IorTest : StringSpec({

"zip should combine left values in correct order" {
Ior.Both("fail1", -1).zip(
Semigroup.string(),
String::plus,
Ior.Left("fail2"),
Ior.Right(-1)
) { _, _, _ -> "success!" } shouldBe Ior.Left("fail1fail2")
Expand Down Expand Up @@ -180,12 +178,11 @@ class IorTest : StringSpec({

"Ior.monad.flatMap should combine left values" {
val ior1 = Ior.Both(3, "Hello, world!")
val iorResult = ior1.flatMap(Semigroup.int()) { Ior.Left(7) }
val iorResult = ior1.flatMap(Int::plus) { Ior.Left(7) }
iorResult shouldBe Ior.Left(10)
}

"combine cases for Semigroup" {
Semigroup.ior(Semigroup.string(), Semigroup.int()).run {
forAll(
row("Hello, ".leftIor(), Ior.Left("Arrow!"), Ior.Left("Hello, Arrow!")),
row(Ior.Left("Hello"), Ior.Right(2020), Ior.Both("Hello", 2020)),
Expand All @@ -197,9 +194,8 @@ class IorTest : StringSpec({
row(Ior.Both("Hello number", 1), Ior.Right(1), Ior.Both("Hello number", 2)),
row(Ior.Both("Hello ", 1), Ior.Both("number", 1), Ior.Both("Hello number", 2))
) { a, b, expectedResult ->
a + b shouldBe expectedResult
a.combine(String::plus, Int::plus, b) shouldBe expectedResult
}
}
}

"traverse should wrap ior in a list" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package arrow.core

import arrow.core.test.laws.MonoidLaws
import arrow.core.test.testLaws
import arrow.typeclasses.Monoid
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
Expand All @@ -12,7 +11,7 @@ import io.kotest.property.checkAll

class ListKTest : StringSpec({

testLaws(MonoidLaws.laws(Monoid.list(), Arb.list(Arb.int())))
testLaws(MonoidLaws(emptyList(), List<Int>::plus, Arb.list(Arb.int())))

"mapNotNull() should map list and filter out null values" {
checkAll(Arb.list(Arb.int())) { listk ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import arrow.core.test.laws.MonoidLaws
import arrow.core.test.longSmall
import arrow.core.test.nonEmptyList
import arrow.core.test.testLaws
import arrow.typeclasses.Monoid
import arrow.typeclasses.Semigroup
import io.kotest.core.spec.style.StringSpec
import io.kotest.property.Arb
import io.kotest.matchers.shouldBe
Expand All @@ -20,8 +18,8 @@ import io.kotest.property.checkAll

class MapKTest : StringSpec({
testLaws(
MonoidLaws.laws(
Monoid.map(Semigroup.int()),
MonoidLaws(
emptyMap(), Map<Long, Int>::plus,
Arb.map(Arb.longSmall(), Arb.intSmall(), maxSize = 10)
)
)
Expand Down Expand Up @@ -87,7 +85,7 @@ class MapKTest : StringSpec({

"traverseValidated is stacksafe" {
val acc = mutableListOf<Int>()
val res = (0..20_000).associateWith { it }.traverse(Semigroup.string()) { v ->
val res = (0..20_000).associateWith { it }.traverse(String::plus) { v ->
acc.add(v)
Validated.Valid(v)
}
Expand All @@ -98,7 +96,7 @@ class MapKTest : StringSpec({
"traverseValidated acummulates" {
checkAll(Arb.map(Arb.int(), Arb.int())) { ints ->
val res: ValidatedNel<Int, Map<Int, Int>> =
ints.traverse(Semigroup.nonEmptyList()) { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() }
ints.traverse(NonEmptyList<Int>::plus) { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() }

val expected: ValidatedNel<Int, Map<Int, Int>> =
Option.fromNullable(ints.values.filterNot { it % 2 == 0 }.toNonEmptyListOrNull())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package arrow.core
import arrow.core.test.laws.SemigroupLaws
import arrow.core.test.nonEmptyList
import arrow.core.test.testLaws
import arrow.typeclasses.Semigroup
import io.kotest.assertions.withClue
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.booleans.shouldBeTrue
Expand All @@ -18,7 +17,7 @@ import kotlin.math.min

class NonEmptyListTest : StringSpec({

testLaws(SemigroupLaws.laws(Semigroup.nonEmptyList(), Arb.nonEmptyList(Arb.int())))
testLaws(SemigroupLaws(NonEmptyList<Int>::plus, Arb.nonEmptyList(Arb.int())))

"iterable.toNonEmptyListOrNull should round trip" {
checkAll(Arb.nonEmptyList(Arb.int())) { nonEmptyList ->
Expand Down Expand Up @@ -109,7 +108,7 @@ class NonEmptyListTest : StringSpec({
"traverse for Validated stack-safe" {
// also verifies result order and execution order (l to r)
val acc = mutableListOf<Int>()
val res = (0..20_000).traverse(Semigroup.string()) {
val res = (0..20_000).traverse(String::plus) {
acc.add(it)
Validated.Valid(it)
}
Expand All @@ -120,7 +119,7 @@ class NonEmptyListTest : StringSpec({
"traverse for Validated acummulates" {
checkAll(Arb.nonEmptyList(Arb.int())) { ints ->
val res: ValidatedNel<Int, NonEmptyList<Int>> =
ints.traverse(Semigroup.nonEmptyList()) { i: Int -> if (i % 2 == 0) i.validNel() else i.invalidNel() }
ints.traverse(NonEmptyList<Int>::plus) { i: Int -> if (i % 2 == 0) i.validNel() else i.invalidNel() }

val expected: ValidatedNel<Int, NonEmptyList<Int>> =
ints.filterNot { it % 2 == 0 }.toNonEmptyListOrNull()?.invalid() ?: ints.filter { it % 2 == 0 }.toNonEmptyListOrNull()!!.valid()
Expand All @@ -129,13 +128,6 @@ class NonEmptyListTest : StringSpec({
}
}

"sequence for Validated should be consistent with traverseValidated" {
checkAll(Arb.nonEmptyList(Arb.int())) { ints ->
ints.map { if (it % 2 == 0) Valid(it) else Invalid(it) }.sequence(Semigroup.int()) shouldBe
ints.traverse(Semigroup.int()) { if (it % 2 == 0) Valid(it) else Invalid(it) }
}
}

"can align lists with different lengths" {
checkAll(Arb.nonEmptyList(Arb.boolean()), Arb.nonEmptyList(Arb.boolean())) { a, b ->
a.align(b).size shouldBe max(a.size, b.size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import arrow.core.continuations.option
import arrow.core.test.laws.MonoidLaws
import arrow.core.test.option
import arrow.core.test.testLaws
import arrow.typeclasses.Monoid
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
Expand All @@ -23,23 +22,7 @@ class OptionTest : StringSpec({
val none: Option<String> = None

testLaws(
MonoidLaws.laws(Monoid.option(Monoid.int()), Arb.option(Arb.int())),
/*FxLaws.suspended<OptionEffect<*>, Option<String>, String>(
Arb.string().map(Option.Companion::invoke),
Arb.option(Arb.string()),
Option<String>::equals,
option::invoke
) {
it.bind()
},
FxLaws.eager<RestrictedOptionEffect<*>, Option<String>, String>(
Arb.string().map(Option.Companion::invoke),
Arb.option(Arb.string()),
Option<String>::equals,
option::eager
) {
it.bind()
}*/
MonoidLaws(None, { x, y -> x.combine(y, Int::plus) }, Arb.option(Arb.int()))
)

"ensure null in option computation" {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package arrow.core

import arrow.typeclasses.Monoid
import arrow.typeclasses.Semigroup
import arrow.core.test.laws.MonoidLaws
import arrow.core.test.option
import arrow.core.test.sequence
Expand All @@ -20,7 +18,7 @@ import kotlin.math.min

class SequenceKTest : StringSpec({

testLaws(MonoidLaws.laws(Monoid.sequence(), Arb.sequence(Arb.int())) { s1, s2 -> s1.toList() == s2.toList() })
testLaws(MonoidLaws(emptySequence(), { a, b -> sequenceOf(a, b).flatten()} , Arb.sequence(Arb.int())) { s1, s2 -> s1.toList() == s2.toList() })

"traverse for Either stack-safe" {
// also verifies result order and execution order (l to r)
Expand Down Expand Up @@ -53,7 +51,7 @@ class SequenceKTest : StringSpec({
"traverse for Validated stack-safe" {
// also verifies result order and execution order (l to r)
val acc = mutableListOf<Int>()
val res = (0..20_000).asSequence().traverse(Semigroup.string()) {
val res = (0..20_000).asSequence().traverse(String::plus) {
acc.add(it)
Validated.Valid(it)
}.map { it.toList() }
Expand All @@ -64,7 +62,7 @@ class SequenceKTest : StringSpec({
"traverse for Validated acummulates" {
checkAll(Arb.sequence(Arb.int())) { ints ->
val res: ValidatedNel<Int, List<Int>> = ints.map { i -> if (i % 2 == 0) i.validNel() else i.invalidNel() }
.sequence(Semigroup.nonEmptyList())
.sequence(NonEmptyList<Int>::plus)

val expected: ValidatedNel<Int, Sequence<Int>> =
ints.filterNot { it % 2 == 0 }.toList()
Expand Down
Loading