Skip to content

Commit

Permalink
Add Comparison.fromInt, make toInt a val, add PartialOrder comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
adelbertc committed Jun 9, 2016
1 parent b8bf39d commit 753b5a3
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 21 deletions.
29 changes: 29 additions & 0 deletions kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ class LawTests extends FunSuite with Discipline {
laws[GroupLaws, Unit].check(_.boundedSemilattice)

// Comparison related

// Something that can give NaN for test
def subsetPartialOrder[A]: PartialOrder[Set[A]] = new PartialOrder[Set[A]] {
def partialCompare(x: Set[A], y: Set[A]): Double =
if (x == y) 0.0
else if (x subsetOf y) -1.0
else if (y subsetOf x) 1.0
else Double.NaN
}

laws[OrderLaws, Set[Int]]("subset").check(_.partialOrder(subsetPartialOrder[Int]))

implicit val arbitraryComparison: Arbitrary[Comparison] =
Arbitrary(Gen.oneOf(Comparison.GreaterThan, Comparison.EqualTo, Comparison.LessThan))

Expand All @@ -94,12 +106,29 @@ class LawTests extends FunSuite with Discipline {
eqv.eqv(order.comparison(-1, 0), Comparison.LessThan)
}

test("partialComparison") {
val po = subsetPartialOrder[Int]
val eqv = Eq[Option[Comparison]]
eqv.eqv(po.partialComparison(Set(1), Set()), Some(Comparison.GreaterThan)) &&
eqv.eqv(po.partialComparison(Set(), Set()), Some(Comparison.EqualTo)) &&
eqv.eqv(po.partialComparison(Set(), Set(1)), Some(Comparison.LessThan)) &&
eqv.eqv(po.partialComparison(Set(1, 2), Set(2, 3)), None)
}

test("signum . toInt . comparison = signum . compare") {
check { (i: Int, j: Int) =>
Eq[Int].eqv(Order[Int].comparison(i, j).toInt.signum, Order[Int].compare(i, j).signum)
}
}

test("signum . toDouble . partialComparison = signum . partialCompare") {
check { (x: Set[Int], y: Set[Int]) =>
val found = subsetPartialOrder[Int].partialComparison(x, y).map(_.toDouble.signum)
val expected = Some(subsetPartialOrder[Int].partialCompare(x, y)).filter(d => !d.isNaN).map(_.signum)
Eq[Option[Int]].eqv(found, expected)
}
}

// esoteric machinery follows...

implicit lazy val band: Band[(Int, Int)] =
Expand Down
33 changes: 22 additions & 11 deletions kernel/src/main/scala/cats/kernel/Comparison.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
package cats.kernel

/** ADT encoding the possible results of a comparison */
sealed abstract class Comparison extends Product with Serializable {
/** The signum of this comparison */
def toInt: Int = this match {
case Comparison.GreaterThan => 1
case Comparison.EqualTo => 0
case Comparison.LessThan => -1
}
}
sealed abstract class Comparison(val toInt: Int, val toDouble: Double) extends Product with Serializable

object Comparison {
final case object GreaterThan extends Comparison
final case object EqualTo extends Comparison
final case object LessThan extends Comparison
final case object GreaterThan extends Comparison(1, 1.0)
final case object EqualTo extends Comparison(0, 0.0)
final case object LessThan extends Comparison(-1, -1.0)

// Used for fromDouble
private val SomeGt = Some(Comparison.GreaterThan)
private val SomeEq = Some(Comparison.EqualTo)
private val SomeLt = Some(Comparison.LessThan)

def fromInt(int: Int): Comparison = {
if (int > 0) Comparison.GreaterThan
else if (int == 0) Comparison.EqualTo
else Comparison.LessThan
}

def fromDouble(double: Double): Option[Comparison] = {
if (double.isNaN) None
else if (double > 0.0) SomeGt
else if (double == 0.0) SomeEq
else SomeLt
}

implicit val catsKernelEqForComparison: Eq[Comparison] = Eq.fromUniversalEquals
}
9 changes: 1 addition & 8 deletions kernel/src/main/scala/cats/kernel/Order.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import scala.{specialized => sp}
* By the totality law, x <= y and y <= x cannot be both false.
*/
trait Order[@sp A] extends Any with PartialOrder[A] { self =>

/**
* Result of comparing `x` with `y`. Returns an Int whose sign is:
* - negative iff `x < y`
Expand All @@ -33,12 +32,7 @@ trait Order[@sp A] extends Any with PartialOrder[A] { self =>
* Like `compare`, but returns a [[cats.kernel.Comparison]] instead of an Int.
* Has the benefit of being able to pattern match on, but not as performant.
*/
def comparison(x: A, y: A): Comparison = {
val r = compare(x, y)
if (r > 0) Comparison.GreaterThan
else if (r == 0) Comparison.EqualTo
else Comparison.LessThan
}
def comparison(x: A, y: A): Comparison = Comparison.fromInt(compare(x, y))

def partialCompare(x: A, y: A): Double = compare(x, y).toDouble

Expand Down Expand Up @@ -146,7 +140,6 @@ abstract class OrderFunctions[O[T] <: Order[T]] extends PartialOrderFunctions[O]
}

object Order extends OrderFunctions[Order] {

/**
* Access an implicit `Order[A]`.
*/
Expand Down
9 changes: 7 additions & 2 deletions kernel/src/main/scala/cats/kernel/PartialOrder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import scala.{specialized => sp}
* false true = 1.0 (corresponds to x > y)
*/
trait PartialOrder[@sp A] extends Any with Eq[A] { self =>

/**
* Result of comparing `x` with `y`. Returns NaN if operands are not
* comparable. If operands are comparable, returns a Double whose
Expand All @@ -34,6 +33,13 @@ trait PartialOrder[@sp A] extends Any with Eq[A] { self =>
*/
def partialCompare(x: A, y: A): Double

/**
* Like `partialCompare`, but returns a [[cats.kernel.Comparison]] instead of an Double.
* Has the benefit of being able to pattern match on, but not as performant.
*/
def partialComparison(x: A, y: A): Option[Comparison] =
Comparison.fromDouble(partialCompare(x, y))

/**
* Result of comparing `x` with `y`. Returns None if operands are
* not comparable. If operands are comparable, returns Some[Int]
Expand Down Expand Up @@ -137,7 +143,6 @@ abstract class PartialOrderFunctions[P[T] <: PartialOrder[T]] extends EqFunction
}

object PartialOrder extends PartialOrderFunctions[PartialOrder] {

/**
* Access an implicit `PartialOrder[A]`.
*/
Expand Down

0 comments on commit 753b5a3

Please sign in to comment.