diff --git a/src/main/scala/fpspeedrun/Eq.scala b/src/main/scala/fpspeedrun/Eq.scala index 7343eaa..02fa50f 100644 --- a/src/main/scala/fpspeedrun/Eq.scala +++ b/src/main/scala/fpspeedrun/Eq.scala @@ -1,5 +1,17 @@ package fpspeedrun trait Eq[T] { - def ===(x: T, y: T): Boolean + def ===(x: T, y: T): Boolean = ! !==(x, y) + def !==(x: T, y: T): Boolean = ! ===(x, y) } + +object Eq { + + import syntax.eq.EqOps + + implicit def listEq[T : Eq]: Eq[List[T]] = new Eq[List[T]] { + override def ===(x: List[T], y: List[T]): Boolean = + x.size == y.size && ( x zip y forall { case (a: T, b: T) => a === b } ) + } + +} \ No newline at end of file diff --git a/src/main/scala/fpspeedrun/Ord.scala b/src/main/scala/fpspeedrun/Ord.scala index 231eec3..dc1e91e 100644 --- a/src/main/scala/fpspeedrun/Ord.scala +++ b/src/main/scala/fpspeedrun/Ord.scala @@ -1,15 +1,26 @@ package fpspeedrun -import fpspeedrun.Ord.Compare -trait Ord[T] extends Eq[T]{ +import fpspeedrun.Ord.{Compare, EQ} + +trait Ord[T] extends Eq[T] { + override def ===(x: T, y: T): Boolean = compare(x, y) == EQ def compare(x: T, y: T): Compare } -object Ord{ +object Ord { + sealed trait Compare - object Compare{ - case object LT //less than - case object EQ //equals to - case object GT //greater than - } + + case object LT extends Compare //less than + case object EQ extends Compare //equals to + case object GT extends Compare //greater than + + import syntax.ord.OrdOps + + implicit def lexicographicalListOrd[T : Ord]: Ord[List[T]] = (x: List[T], y: List[T]) => + x zip y find { case (a, b) => a !== b } match { + case Some((a, b)) => a compare b + case None => if (x.size < y.size) LT else if (x.size > y.size) GT else EQ + } + } diff --git a/src/main/scala/fpspeedrun/OrdInstances.scala b/src/main/scala/fpspeedrun/OrdInstances.scala new file mode 100644 index 0000000..2af5fbd --- /dev/null +++ b/src/main/scala/fpspeedrun/OrdInstances.scala @@ -0,0 +1,21 @@ +package fpspeedrun + +import fpspeedrun.Ord.{EQ, GT, LT} +import syntax.ord.OrdOps + +object OrdInstances { + + implicit def sizeFirstListOrd[T : Ord]: Ord[List[T]] = (x: List[T], y: List[T]) => + if (x.size < y.size) LT + else if (x.size > y.size) GT + else x zip y find { case (a, b) => a !== b } match { + case Some((a, b)) => a compare b + case None => EQ + } + + implicit def sizeOnlyListOrd[T : Ord]: Ord[List[T]] = (x: List[T], y: List[T]) => + if (x.size < y.size) LT + else if (x.size > y.size) GT + else EQ + +} diff --git a/src/main/scala/fpspeedrun/Ratio.scala b/src/main/scala/fpspeedrun/Ratio.scala index bc3fe1b..af4eba0 100644 --- a/src/main/scala/fpspeedrun/Ratio.scala +++ b/src/main/scala/fpspeedrun/Ratio.scala @@ -1,4 +1,17 @@ package fpspeedrun -final case class Ratio() +import fpspeedrun.Ord.{EQ, GT, LT} +final case class Ratio(numerator: Int, denominator: Int) + +object Ratio { + + implicit val ratioOrd: Ord[Ratio] = (x: Ratio, y: Ratio) => { + val crossProductsDiff: Int = x.numerator * y.denominator - x.denominator * y.numerator + + if (crossProductsDiff > 0) GT + else if (crossProductsDiff < 0) LT + else EQ + } + +} diff --git a/src/main/scala/fpspeedrun/syntax.scala b/src/main/scala/fpspeedrun/syntax.scala index d4f9a19..cafc60b 100644 --- a/src/main/scala/fpspeedrun/syntax.scala +++ b/src/main/scala/fpspeedrun/syntax.scala @@ -1,9 +1,26 @@ package fpspeedrun +import fpspeedrun.Ord.Compare + object syntax { - object eq{ + + object eq { + implicit class EqOps[T](val x: T) extends AnyVal{ def ===(y: T)(implicit eq: Eq[T]): Boolean = eq.===(x, y) + def !==(y: T)(implicit eq: Eq[T]): Boolean = eq.!==(x, y) + } + + } + + object ord { + + implicit class OrdOps[T](val x: T) extends AnyVal { + def ===(y: T)(implicit ord: Ord[T]): Boolean = ord.===(x, y) + def !==(y: T)(implicit ord: Ord[T]): Boolean = ord.!==(x, y) + def compare(y: T)(implicit ord: Ord[T]): Compare = ord.compare(x, y) } + } + }