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

Add Contravariant instance for Eq and test Show instance. #1211

Merged
merged 3 commits into from
Jul 19, 2016
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
17 changes: 16 additions & 1 deletion core/src/main/scala/cats/functor/Contravariant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,22 @@ import simulacrum.typeclass
}
}

object Contravariant {
object Contravariant extends KernelContravariantInstances

/**
* Convariant instances for types that are housed in cats.kernel and therefore
* can't have instances for this type class in their companion objects.
*/
private[functor] sealed trait KernelContravariantInstances {
implicit val catsFunctorContravariantForEq: Contravariant[Eq] =
new Contravariant[Eq] {
/** Derive a `Eq` for `B` given a `Eq[A]` and a function `B => A`.
*
* Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping)
*/
def contramap[A, B](fa: Eq[A])(f: B => A): Eq[B] = fa.on(f)
}

implicit val catsFunctorContravariantForPartialOrder: Contravariant[PartialOrder] =
new Contravariant[PartialOrder] {
/** Derive a `PartialOrder` for `B` given a `PartialOrder[A]` and a function `B => A`.
Expand Down
3 changes: 3 additions & 0 deletions laws/src/main/scala/cats/laws/discipline/Arbitrary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ object arbitrary extends ArbitraryInstances0 {
implicit def catsLawsArbitraryForFn0[A: Arbitrary]: Arbitrary[() => A] =
Arbitrary(getArbitrary[A].map(() => _))

implicit def catsLawsArbitraryForEq[A: Arbitrary]: Arbitrary[Eq[A]] =
Arbitrary(new Eq[A] { def eqv(x: A, y: A) = x.hashCode == y.hashCode })

implicit def catsLawsArbitraryForPartialOrder[A: Arbitrary]: Arbitrary[PartialOrder[A]] =
Arbitrary(Gen.oneOf(
PartialOrder.from[A]((_: A, _: A) => Double.NaN),
Expand Down
20 changes: 18 additions & 2 deletions laws/src/main/scala/cats/laws/discipline/Eq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ object eq {
}
}

/**
* Create an approximation of Eq[Eq[A]] by generating 100 values for A
* and comparing the application of the two eqv functions
*/
implicit def catsLawsEqForEq[A](implicit arbA: Arbitrary[(A, A)]): Eq[Eq[A]] = new Eq[Eq[A]] {
def eqv(f: Eq[A], g: Eq[A]): Boolean = {
val samples = List.fill(100)(arbA.arbitrary.sample).collect {
case Some(a) => a
case None => sys.error("Could not generate arbitrary values to compare two Eq[A]")
}
samples.forall {
case (l, r) => f.eqv(l, r) == g.eqv(l, r)
}
}
}

/**
* Create an approximation of Eq[PartialOrder[A]] by generating 100 values for A
* and comparing the application of the two compare functions
Expand All @@ -51,14 +67,14 @@ object eq {
* Create an approximation of Eq[Order[A]] by generating 100 values for A
* and comparing the application of the two compare functions
*/
implicit def catsLawsEqForOrder[A](implicit arbA: Arbitrary[(A, A)], intEq: Eq[Int]): Eq[Order[A]] = new Eq[Order[A]] {
implicit def catsLawsEqForOrder[A](implicit arbA: Arbitrary[(A, A)]): Eq[Order[A]] = new Eq[Order[A]] {
def eqv(f: Order[A], g: Order[A]): Boolean = {
val samples = List.fill(100)(arbA.arbitrary.sample).collect {
case Some(a) => a
case None => sys.error("Could not generate arbitrary values to compare two Order[A]")
}
samples.forall {
case (l, r) => intEq.eqv(f.compare(l, r), g.compare(l, r))
case (l, r) => f.compare(l, r) == g.compare(l, r)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import cats.laws.discipline.{ContravariantTests, SerializableTests}
import cats.laws.discipline.eq._

class KernelContravariantTests extends CatsSuite {
checkAll("Contravariant[Eq]", ContravariantTests[Eq].contravariant[Int, Int, Int])
checkAll("Contravariant[Eq]", SerializableTests.serializable(Contravariant[Eq]))

checkAll("Contravariant[PartialOrder]", ContravariantTests[PartialOrder].contravariant[Int, Int, Int])
checkAll("Contravariant[PartialOrder]", SerializableTests.serializable(Contravariant[PartialOrder]))

Expand Down
12 changes: 12 additions & 0 deletions tests/src/test/scala/cats/tests/ShowTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cats
package tests

import cats.functor.Contravariant
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.{ContravariantTests, SerializableTests}
import cats.laws.discipline.eq._

class ShowTests extends CatsSuite {
checkAll("Contravariant[Show]", ContravariantTests[Show].contravariant[Int, Int, Int])
checkAll("Contravariant[Show]", SerializableTests.serializable(Contravariant[Show]))
}