diff --git a/build.sbt b/build.sbt index fd23f9de69..c4b4cc60f0 100644 --- a/build.sbt +++ b/build.sbt @@ -207,7 +207,7 @@ lazy val kernel = crossProject.crossType(CrossType.Pure) .settings(scoverageSettings: _*) .settings(sourceGenerators in Compile <+= (sourceManaged in Compile).map(KernelBoiler.gen)) .jsSettings(commonJsSettings:_*) - .jvmSettings((commonJvmSettings ++ (mimaPreviousArtifacts := Set("org.typelevel" %% "cats-kernel" % "0.6.0"))):_*) + .jvmSettings((commonJvmSettings ++ (mimaPreviousArtifacts := Set("org.typelevel" %% "cats-kernel" % "0.7.0"))):_*) lazy val kernelJVM = kernel.jvm lazy val kernelJS = kernel.js diff --git a/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala b/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala index 22c47cab7e..27f7f59958 100644 --- a/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala +++ b/kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala @@ -6,7 +6,7 @@ import org.typelevel.discipline.Laws import org.scalacheck.{Arbitrary, Prop} import org.scalacheck.Prop._ -import cats.kernel.instances.boolean._ +import cats.kernel.instances.all._ object OrderLaws { def apply[A: Eq: Arbitrary]: OrderLaws[A] = new OrderLaws[A] { @@ -59,6 +59,26 @@ trait OrderLaws[A] extends Laws { }, "gt" -> forAll { (x: A, y: A) => A.lt(x, y) ?== A.gt(y, x) + }, + "partialCompare" -> forAll { (x: A, y: A) => + val c = A.partialCompare(x, y) + ((c < 0) ?== A.lt(x, y)) && ((c == 0) ?== A.eqv(x, y)) && ((c > 0) ?== A.gt(x, y)) + }, + "pmin" -> forAll { (x: A, y: A) => + val c = A.partialCompare(x, y) + val m = A.pmin(x, y) + if (c < 0) m ?== Some(x) + else if (c == 0) (m ?== Some(x)) && (m ?== Some(y)) + else if (c > 0) m ?== Some(y) + else m ?== None + }, + "pmax" -> forAll { (x: A, y: A) => + val c = A.partialCompare(x, y) + val m = A.pmax(x, y) + if (c < 0) m ?== Some(y) + else if (c == 0) (m ?== Some(x)) && (m ?== Some(y)) + else if (c > 0) m ?== Some(x) + else m ?== None } ) @@ -67,6 +87,24 @@ trait OrderLaws[A] extends Laws { parent = Some(partialOrder), "totality" -> forAll { (x: A, y: A) => A.lteqv(x, y) ?|| A.lteqv(y, x) + }, + "compare" -> forAll { (x: A, y: A) => + val c = A.compare(x, y) + ((c < 0) ?== A.lt(x, y)) && ((c == 0) ?== A.eqv(x, y)) && ((c > 0) ?== A.gt(x, y)) + }, + "min" -> forAll { (x: A, y: A) => + val c = A.compare(x, y) + val m = A.min(x, y) + if (c < 0) m ?== x + else if (c == 0) (m ?== x) && (m ?== y) + else m ?== y + }, + "max" -> forAll { (x: A, y: A) => + val c = A.compare(x, y) + val m = A.max(x, y) + if (c < 0) m ?== y + else if (c == 0) (m ?== x) && (m ?== y) + else m ?== x } ) diff --git a/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala index 22aa33f785..4dc3f12b7e 100644 --- a/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala @@ -77,6 +77,14 @@ class LawTests extends FunSuite with Discipline { //laws[GroupLaws, Double].check(_.commutativeGroup) // approximately associative laws[GroupLaws, BigInt].check(_.commutativeGroup) + { + // default Arbitrary[BigDecimal] is a bit too intense :/ + implicit val arbBigDecimal: Arbitrary[BigDecimal] = + Arbitrary(arbitrary[Double].map(n => BigDecimal(n.toString))) + laws[OrderLaws, BigDecimal].check(_.order) + laws[GroupLaws, BigDecimal].check(_.commutativeGroup) + } + laws[GroupLaws, (Int, Int)].check(_.band) laws[GroupLaws, Unit].check(_.boundedSemilattice) diff --git a/kernel/src/main/scala/cats/kernel/instances/all.scala b/kernel/src/main/scala/cats/kernel/instances/all.scala index 3fc5b82b5a..b519278ef1 100644 --- a/kernel/src/main/scala/cats/kernel/instances/all.scala +++ b/kernel/src/main/scala/cats/kernel/instances/all.scala @@ -4,7 +4,8 @@ package instances package object all extends AllInstances trait AllInstances - extends BigIntInstances + extends BigDecimalInstances + with BigIntInstances with BooleanInstances with ByteInstances with CharInstances diff --git a/kernel/src/main/scala/cats/kernel/instances/bigDecimal.scala b/kernel/src/main/scala/cats/kernel/instances/bigDecimal.scala new file mode 100644 index 0000000000..28203cb91e --- /dev/null +++ b/kernel/src/main/scala/cats/kernel/instances/bigDecimal.scala @@ -0,0 +1,33 @@ +package cats.kernel +package instances + +package object bigDecimal extends BigDecimalInstances // scalastyle:ignore package.object.name + +trait BigDecimalInstances { + implicit val catsKernelStdOrderForBigDecimal: Order[BigDecimal] = + new BigDecimalOrder + implicit val catsKernelStdGroupForBigDecimal: CommutativeGroup[BigDecimal] = + new BigDecimalGroup +} + +class BigDecimalGroup extends CommutativeGroup[BigDecimal] { + val empty: BigDecimal = BigDecimal(0) + def combine(x: BigDecimal, y: BigDecimal): BigDecimal = x + y + def inverse(x: BigDecimal): BigDecimal = -x + override def remove(x: BigDecimal, y: BigDecimal): BigDecimal = x - y +} + +class BigDecimalOrder extends Order[BigDecimal] { + + def compare(x: BigDecimal, y: BigDecimal): Int = x compare y + + override def eqv(x: BigDecimal, y: BigDecimal): Boolean = x == y + override def neqv(x: BigDecimal, y: BigDecimal): Boolean = x != y + override def gt(x: BigDecimal, y: BigDecimal): Boolean = x > y + override def gteqv(x: BigDecimal, y: BigDecimal): Boolean = x >= y + override def lt(x: BigDecimal, y: BigDecimal): Boolean = x < y + override def lteqv(x: BigDecimal, y: BigDecimal): Boolean = x <= y + + override def min(x: BigDecimal, y: BigDecimal): BigDecimal = x min y + override def max(x: BigDecimal, y: BigDecimal): BigDecimal = x max y +}