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

make many of the Semigroups and Monoids commutative #1006

Merged
merged 1 commit into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -1,9 +1,9 @@
package eu.timepit.refined

import _root_.cats.{Contravariant, MonadError, Show}
import _root_.cats.{Contravariant, MonadError, Semigroup, Show}
import _root_.cats.implicits._
import _root_.cats.kernel.{Eq, Monoid, Order, Semigroup}
import eu.timepit.refined.api.{Refined, RefType, Validate}
import _root_.cats.kernel.{CommutativeMonoid, CommutativeSemigroup, Eq, Monoid, Order}
import eu.timepit.refined.api.{RefType, Refined, Validate}
import eu.timepit.refined.numeric.{Negative, NonNegative, NonPositive, Positive}
import eu.timepit.refined.types.numeric._

Expand All @@ -30,49 +30,96 @@ package object cats {
implicit def refTypeShow[F[_, _], T: Show, P](implicit rt: RefType[F]): Show[F[T, P]] =
cats.derivation.refTypeViaContravariant[F, Show, T, P]

// Semigroup instances
implicit val posByteSemigroup: Semigroup[PosByte] = getPosIntegralSemigroup[Byte]
implicit val posShortSemigroup: Semigroup[PosShort] = getPosIntegralSemigroup[Short]
implicit val posIntSemigroup: Semigroup[PosInt] = getPosIntegralSemigroup[Int]
implicit val posLongSemigroup: Semigroup[PosLong] = getPosIntegralSemigroup[Long]
implicit val posFloatSemigroup: Semigroup[PosFloat] = getSemigroup[Float, Positive]
implicit val posDoubleSemigroup: Semigroup[PosDouble] = getSemigroup[Double, Positive]

implicit val negByteSemigroup: Semigroup[NegByte] = getNegIntegralSemigroup[Byte]
implicit val negShortSemigroup: Semigroup[NegShort] = getNegIntegralSemigroup[Short]
implicit val negIntSemigroup: Semigroup[NegInt] = getNegIntegralSemigroup[Int]
implicit val negLongSemigroup: Semigroup[NegLong] = getNegIntegralSemigroup[Long]
implicit val negFloatSemigroup: Semigroup[NegFloat] = getSemigroup[Float, Negative]
implicit val negDoubleSemigroup: Semigroup[NegDouble] = getSemigroup[Double, Negative]
// CommutativeSemigroup instances
implicit val posByteCommutativeSemigroup: CommutativeSemigroup[PosByte] =
getPosIntegralCommutativeSemigroup[Byte]
implicit val posShortCommutativeSemigroup: CommutativeSemigroup[PosShort] =
getPosIntegralCommutativeSemigroup[Short]
implicit val posIntCommutativeSemigroup: CommutativeSemigroup[PosInt] =
getPosIntegralCommutativeSemigroup[Int]
implicit val posLongCommutativeSemigroup: CommutativeSemigroup[PosLong] =
getPosIntegralCommutativeSemigroup[Long]
implicit val posFloatCommutativeSemigroup: CommutativeSemigroup[PosFloat] =
getCommutativeSemigroup[Float, Positive]
implicit val posDoubleCommutativeSemigroup: CommutativeSemigroup[PosDouble] =
getCommutativeSemigroup[Double, Positive]

implicit val negByteCommutativeSemigroup: CommutativeSemigroup[NegByte] =
getNegIntegralCommutativeSemigroup[Byte]
implicit val negShortCommutativeSemigroup: CommutativeSemigroup[NegShort] =
getNegIntegralCommutativeSemigroup[Short]
implicit val negIntCommutativeSemigroup: CommutativeSemigroup[NegInt] =
getNegIntegralCommutativeSemigroup[Int]
implicit val negLongCommutativeSemigroup: CommutativeSemigroup[NegLong] =
getNegIntegralCommutativeSemigroup[Long]
implicit val negFloatCommutativeSemigroup: CommutativeSemigroup[NegFloat] =
getCommutativeSemigroup[Float, Negative]
implicit val negDoubleCommutativeSemigroup: CommutativeSemigroup[NegDouble] =
getCommutativeSemigroup[Double, Negative]

// Monoid instances
implicit val nonNegByteMonoid: Monoid[NonNegByte] = getNonNegIntegralMonoid[Byte]
implicit val nonNegShortMonoid: Monoid[NonNegShort] = getNonNegIntegralMonoid[Short]
implicit val nonNegIntMonoid: Monoid[NonNegInt] = getNonNegIntegralMonoid[Int]
implicit val nonNegLongMonoid: Monoid[NonNegLong] = getNonNegIntegralMonoid[Long]
implicit val nonNegFloatMonoid: Monoid[NonNegFloat] = getMonoid[Float, NonNegative]
implicit val nonNegDoubleMonoid: Monoid[NonNegDouble] = getMonoid[Double, NonNegative]

implicit val nonPosFloatMonoid: Monoid[NonPosFloat] = getMonoid[Float, NonPositive]
implicit val nonPosDoubleMonoid: Monoid[NonPosDouble] = getMonoid[Double, NonPositive]

private def getPosIntegralSemigroup[A: Semigroup: NonNegShift](implicit
implicit val nonNegByteCommutativeMonoid: CommutativeMonoid[NonNegByte] =
getNonNegIntegralCommutativeMonoid[Byte]
implicit val nonNegShortCommutativeMonoid: CommutativeMonoid[NonNegShort] =
getNonNegIntegralCommutativeMonoid[Short]
implicit val nonNegIntCommutativeMonoid: CommutativeMonoid[NonNegInt] =
getNonNegIntegralCommutativeMonoid[Int]
implicit val nonNegLongCommutativeMonoid: CommutativeMonoid[NonNegLong] =
getNonNegIntegralCommutativeMonoid[Long]
implicit val nonNegFloatCommutativeMonoid: CommutativeMonoid[NonNegFloat] =
getCommutativeMonoid[Float, NonNegative]
implicit val nonNegDoubleCommutativeMonoid: CommutativeMonoid[NonNegDouble] =
getCommutativeMonoid[Double, NonNegative]

implicit val nonPosFloatCommutativeMonoid: CommutativeMonoid[NonPosFloat] =
getCommutativeMonoid[Float, NonPositive]
implicit val nonPosDoubleCommutativeMonoid: CommutativeMonoid[NonPosDouble] =
getCommutativeMonoid[Double, NonPositive]

// Semigroup instances retained for binary compatibility
val posByteSemigroup: Semigroup[PosByte] = posByteCommutativeSemigroup
val posShortSemigroup: Semigroup[PosShort] = posShortCommutativeSemigroup
val posIntSemigroup: Semigroup[PosInt] = posIntCommutativeSemigroup
val posLongSemigroup: Semigroup[PosLong] = posLongCommutativeSemigroup
val posFloatSemigroup: Semigroup[PosFloat] = posFloatCommutativeSemigroup
val posDoubleSemigroup: Semigroup[PosDouble] = posDoubleCommutativeSemigroup

val negByteSemigroup: Semigroup[NegByte] = negByteCommutativeSemigroup
val negShortSemigroup: Semigroup[NegShort] = negShortCommutativeSemigroup
val negIntSemigroup: Semigroup[NegInt] = negIntCommutativeSemigroup
val negLongSemigroup: Semigroup[NegLong] = negLongCommutativeSemigroup
val negFloatSemigroup: Semigroup[NegFloat] = negFloatCommutativeSemigroup
val negDoubleSemigroup: Semigroup[NegDouble] = negDoubleCommutativeSemigroup

// Monoid instances retained for binary compatibility
val nonNegByteMonoid: Monoid[NonNegByte] = nonNegByteCommutativeMonoid
val nonNegShortMonoid: Monoid[NonNegShort] = nonNegShortCommutativeMonoid
val nonNegIntMonoid: Monoid[NonNegInt] = nonNegIntCommutativeMonoid
val nonNegLongMonoid: Monoid[NonNegLong] = nonNegLongCommutativeMonoid
val nonNegFloatMonoid: Monoid[NonNegFloat] = nonNegFloatCommutativeMonoid
val nonNegDoubleMonoid: Monoid[NonNegDouble] = nonNegDoubleCommutativeMonoid

val nonPosFloatMonoid: Monoid[NonPosFloat] = nonPosFloatCommutativeMonoid
val nonPosDoubleMonoid: Monoid[NonPosDouble] = nonPosDoubleCommutativeMonoid

private def getPosIntegralCommutativeSemigroup[A: CommutativeSemigroup: NonNegShift](implicit
integral: Integral[A],
v: Validate[A, Positive]
): Semigroup[A Refined Positive] =
Semigroup.instance { (x, y) =>
): CommutativeSemigroup[A Refined Positive] =
CommutativeSemigroup.instance { (x, y) =>
val combined: A = x.value |+| y.value

refineV[Positive](combined).getOrElse {
val result: A = Semigroup[A].combine(NonNegShift[A].shift(combined), integral.one)
val result: A =
CommutativeSemigroup[A].combine(NonNegShift[A].shift(combined), integral.one)
refineV[Positive].unsafeFrom(result)
}
}

private def getNegIntegralSemigroup[A: Integral: Semigroup: NegShift](implicit
v: Validate[A, Negative]
): Semigroup[A Refined Negative] =
Semigroup.instance { (x, y) =>
private def getNegIntegralCommutativeSemigroup[A: Integral: CommutativeSemigroup: NegShift](
implicit v: Validate[A, Negative]
): CommutativeSemigroup[A Refined Negative] =
CommutativeSemigroup.instance { (x, y) =>
val combined: A = x.value |+| y.value

refineV[Negative](combined).getOrElse {
Expand All @@ -81,15 +128,15 @@ package object cats {
}
}

private def getSemigroup[A: Semigroup, P](implicit
private def getCommutativeSemigroup[A: CommutativeSemigroup, P](implicit
v: Validate[A, P]
): Semigroup[A Refined P] =
Semigroup.instance((x, y) => refineV[P].unsafeFrom(x.value |+| y.value))
): CommutativeSemigroup[A Refined P] =
CommutativeSemigroup.instance((x, y) => refineV[P].unsafeFrom(x.value |+| y.value))

private def getNonNegIntegralMonoid[A: Integral: Monoid: NonNegShift](implicit
v: Validate[A, NonNegative]
): Monoid[A Refined NonNegative] =
new Monoid[A Refined NonNegative] {
private def getNonNegIntegralCommutativeMonoid[A: Integral: CommutativeMonoid: NonNegShift](
implicit v: Validate[A, NonNegative]
): CommutativeMonoid[A Refined NonNegative] =
new CommutativeMonoid[A Refined NonNegative] {
override def empty: A Refined NonNegative = refineV[NonNegative].unsafeFrom(Monoid[A].empty)

override def combine(
Expand All @@ -105,10 +152,10 @@ package object cats {
}
}

private def getMonoid[A: Monoid, P](implicit
private def getCommutativeMonoid[A: CommutativeMonoid, P](implicit
v: Validate[A, P]
): Monoid[A Refined P] =
new Monoid[A Refined P] {
): CommutativeMonoid[A Refined P] =
new CommutativeMonoid[A Refined P] {
override def empty: A Refined P = refineV[P].unsafeFrom(Monoid[A].empty)

override def combine(x: A Refined P, y: A Refined P): A Refined P =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package eu.timepit.refined.cats
import cats.kernel.{CommutativeMonoid, CommutativeSemigroup}
import cats.kernel.laws.discipline.{
CommutativeMonoidTests,
CommutativeSemigroupTests,
SerializableTests
}
import eu.timepit.refined.scalacheck.numeric._
import eu.timepit.refined.types.numeric._
import org.scalatest.funsuite.AnyFunSuite
import org.scalatestplus.scalacheck.Checkers
import org.typelevel.discipline.scalatest.FunSuiteDiscipline

class CommutativeSemigroupAndMonoidLawTests
extends AnyFunSuite
with FunSuiteDiscipline
with Checkers {
// Positive commutativeSemigroups
checkAll("CommutativeSemigroup[PosByte]", CommutativeSemigroupTests[PosByte].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[PosByte]",
SerializableTests.serializable(CommutativeSemigroup[PosByte])
)
checkAll(
"CommutativeSemigroup[PosShort]",
CommutativeSemigroupTests[PosShort].commutativeSemigroup
)
checkAll(
"CommutativeSemigroup[PosShort]",
SerializableTests.serializable(CommutativeSemigroup[PosShort])
)
checkAll("CommutativeSemigroup[PosInt]", CommutativeSemigroupTests[PosInt].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[PosInt]",
SerializableTests.serializable(CommutativeSemigroup[PosInt])
)
checkAll("CommutativeSemigroup[PosLong]", CommutativeSemigroupTests[PosLong].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[PosLong]",
SerializableTests.serializable(CommutativeSemigroup[PosLong])
)
// checkAll("CommutativeSemigroup[PosFloat]", CommutativeSemigroupTests[PosFloat].commutativeSemigroup) // approximately associative
checkAll(
"CommutativeSemigroup[PosFloat]",
SerializableTests.serializable(CommutativeSemigroup[PosFloat])
)
// checkAll("CommutativeSemigroup[PosDouble]", CommutativeSemigroupTests[PosDouble].commutativeSemigroup) // approximately associative
checkAll(
"CommutativeSemigroup[PosDouble]",
SerializableTests.serializable(CommutativeSemigroup[PosDouble])
)

// Negative commutativeSemigroups
checkAll("CommutativeSemigroup[NegByte]", CommutativeSemigroupTests[NegByte].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[NegByte]",
SerializableTests.serializable(CommutativeSemigroup[NegByte])
)
checkAll(
"CommutativeSemigroup[NegShort]",
CommutativeSemigroupTests[NegShort].commutativeSemigroup
)
checkAll(
"CommutativeSemigroup[NegShort]",
SerializableTests.serializable(CommutativeSemigroup[NegShort])
)
checkAll("CommutativeSemigroup[NegInt]", CommutativeSemigroupTests[NegInt].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[NegInt]",
SerializableTests.serializable(CommutativeSemigroup[NegInt])
)
checkAll("CommutativeSemigroup[NegLong]", CommutativeSemigroupTests[NegLong].commutativeSemigroup)
checkAll(
"CommutativeSemigroup[NegLong]",
SerializableTests.serializable(CommutativeSemigroup[NegLong])
)
// checkAll("CommutativeSemigroup[NegFloat]", CommutativeSemigroupTests[NegFloat].commutativeSemigroup) // approximately associative
checkAll(
"CommutativeSemigroup[NegFloat]",
SerializableTests.serializable(CommutativeSemigroup[NegFloat])
)
// checkAll("CommutativeSemigroup[NegDouble]", CommutativeSemigroupTests[NegDouble].commutativeSemigroup) // approximately associative
checkAll(
"CommutativeSemigroup[NegDouble]",
SerializableTests.serializable(CommutativeSemigroup[NegDouble])
)

// NonNegative monoids
checkAll("CommutativeMonoid[NonNegByte]", CommutativeMonoidTests[NonNegByte].commutativeMonoid)
checkAll(
"CommutativeMonoid[NonNegByte]",
SerializableTests.serializable(CommutativeMonoid[NonNegByte])
)
checkAll("CommutativeMonoid[NonNegShort]", CommutativeMonoidTests[NonNegShort].commutativeMonoid)
checkAll(
"CommutativeMonoid[NonNegShort]",
SerializableTests.serializable(CommutativeMonoid[NonNegShort])
)
checkAll("CommutativeMonoid[NonNegInt]", CommutativeMonoidTests[NonNegInt].commutativeMonoid)
checkAll(
"CommutativeMonoid[NonNegInt]",
SerializableTests.serializable(CommutativeMonoid[NonNegInt])
)
checkAll("CommutativeMonoid[NonNegLong]", CommutativeMonoidTests[NonNegLong].commutativeMonoid)
checkAll(
"CommutativeMonoid[NonNegLong]",
SerializableTests.serializable(CommutativeMonoid[NonNegLong])
)
// checkAll("Monoid[NonNegFloat]", CommutativeMonoidTests[NonNegFloat].commutativeMonoid) // approximately associative
checkAll(
"CommutativeMonoid[NonNegFloat]",
SerializableTests.serializable(CommutativeMonoid[NonNegFloat])
)
// checkAll("Monoid[NonNegDouble]", CommutativeMonoidTests[NonNegDouble].commutativeMonoid) // approximately associative
checkAll(
"CommutativeMonoid[NonNegDouble]",
SerializableTests.serializable(CommutativeMonoid[NonNegDouble])
)

// NonPositive monoids
// checkAll("Monoid[NonPosFloat]", CommutativeMonoidTests[NonPosFloat].commutativeMonoid) // approximately associative
checkAll(
"CommutativeMonoid[NonPosFloat]",
SerializableTests.serializable(CommutativeMonoid[NonPosFloat])
)
// checkAll("Monoid[NonPosDouble]", CommutativeMonoidTests[NonPosDouble].commutativeMonoid) // approximately associative
checkAll(
"CommutativeMonoid[NonPosDouble]",
SerializableTests.serializable(CommutativeMonoid[NonPosDouble])
)

}

This file was deleted.