Skip to content

Commit

Permalink
Tighten test code for Contravariant derivatives
Browse files Browse the repository at this point in the history
  • Loading branch information
stephen-lazaro committed Nov 29, 2017
1 parent 110ac5e commit f7c4104
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 26 deletions.
10 changes: 1 addition & 9 deletions laws/src/main/scala/cats/laws/ContravariantMonoidalLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ import cats.syntax.contravariantSemigroupal._
/**
* Laws that must hold for any `cats.ContravariantMonoidal`.
*/
trait ContravariantMonoidalLaws[F[_]] extends ContravariantLaws[F] {
trait ContravariantMonoidalLaws[F[_]] extends ContravariantSemigroupalLaws[F] {
implicit override def F: ContravariantMonoidal[F]

/**
* The traditional diagonal map
*/
def delta[A](a: A): (A, A) = (a, a)

def contravariantMonoidalUnitRight[A](fa: F[A]): IsEq[F[A]] =
(fa, F.unit[A]).contramapN(delta[A]) <-> fa

Expand All @@ -27,9 +22,6 @@ trait ContravariantMonoidalLaws[F[_]] extends ContravariantLaws[F] {

def contravariantMonoidalContramap2CompatibleContramapRight[A, B, C](fa: F[A], f: C => (B, A)): IsEq[F[C]] =
(F.unit[B], fa).contramapN(f) <-> fa.contramap(f andThen (_._2))

def contravariantMonoidalContramap2DiagonalAssociates[A](m: F[A], n: F[A], o: F[A]): IsEq[F[A]] =
((m, n).contramapN(delta[A]), o).contramapN(delta[A]) <-> (m, (n, o).contramapN(delta[A])).contramapN(delta[A])
}

object ContravariantMonoidalLaws {
Expand Down
21 changes: 21 additions & 0 deletions laws/src/main/scala/cats/laws/ContravariantSemigroupalLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cats
package laws

import cats.ContravariantSemigroupal
import cats.syntax.contravariantSemigroupal._

/**
* Laws that are expected for any `cats.ContravariantSemigroupal`.
*/
trait ContravariantSemigroupalLaws[F[_]] extends ContravariantLaws[F] with SemigroupalLaws[F] {
implicit override def F: ContravariantSemigroupal[F]

def delta[A](a: A): (A, A) = (a, a)

def contravariantSemigroupalContramap2DiagonalAssociates[A](m: F[A], n: F[A], o: F[A]): IsEq[F[A]] =
((m, n).contramapN(delta[A]), o).contramapN(delta[A]) <-> (m, (n, o).contramapN(delta[A])).contramapN(delta[A])
}
object ContravariantSemigroupalLaws {
def apply[F[_]](implicit ev: ContravariantSemigroupal[F]): ContravariantSemigroupalLaws[F] =
new ContravariantSemigroupalLaws[F] { def F: ContravariantSemigroupal[F] = ev }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,41 @@ package laws
package discipline

import cats.ContravariantMonoidal
import cats.laws.discipline.SemigroupalTests.Isomorphisms
import org.scalacheck.{Arbitrary, Cogen}
import org.scalacheck.Prop._

trait ContravariantMonoidalTests[F[_]] extends ContravariantTests[F] {
trait ContravariantMonoidalTests[F[_]] extends ContravariantSemigroupalTests[F] {
def laws: ContravariantMonoidalLaws[F]

def contravariantMonoidal[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
arbFA: Arbitrary[F[A]],
arbFB: Arbitrary[F[B]],
arbFC: Arbitrary[F[C]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]]
EqFC: Eq[F[C]],
EqFABC: Eq[F[(A, B, C)]],
iso: Isomorphisms[F]
): RuleSet = {
new DefaultRuleSet(
name = "contravariantMonoidal",
parent = Some(contravariant[A, B, C]),
"contravariantMonoidal right unit" ->
forAll(laws.contravariantMonoidalUnitRight[A] _),
"contravariantMonoidal left unit" ->
forAll(laws.contravariantMonoidalUnitLeft[A] _),
"contravariantMonoidal contramap2 compatible contramap left" ->
forAll(laws.contravariantMonoidalContramap2CompatibleContramapLeft[A, B, C] _),
"contravariantMonoidal contramap2 compatible contramap right" ->
forAll(laws.contravariantMonoidalContramap2CompatibleContramapRight[A, B, C] _),
"contravariantMonoidal contramap2 delta associates" ->
forAll(laws.contravariantMonoidalContramap2DiagonalAssociates[A] _)
)
new RuleSet {
val name = "contravariantMonoidal"
val parents = Seq(contravariantSemigroupal[A, B, C])
val bases = Seq.empty
val props = Seq(
"contravariantMonoidal right unit" ->
forAll(laws.contravariantMonoidalUnitRight[A] _),
"contravariantMonoidal left unit" ->
forAll(laws.contravariantMonoidalUnitLeft[A] _),
"contravariantMonoidal contramap2 compatible contramap left" ->
forAll(laws.contravariantMonoidalContramap2CompatibleContramapLeft[A, B, C] _),
"contravariantMonoidal contramap2 compatible contramap right" ->
forAll(laws.contravariantMonoidalContramap2CompatibleContramapRight[A, B, C] _)
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cats
package laws
package discipline

import cats.ContravariantSemigroupal
import cats.laws.discipline.SemigroupalTests.Isomorphisms
import org.scalacheck.{Arbitrary, Cogen}
import org.scalacheck.Prop._

trait ContravariantSemigroupalTests[F[_]] extends ContravariantTests[F] with SemigroupalTests[F] {
def laws: ContravariantSemigroupalLaws[F]

def contravariantSemigroupal[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
arbFA: Arbitrary[F[A]],
arbFB: Arbitrary[F[B]],
arbFC: Arbitrary[F[C]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFABC: Eq[F[(A, B, C)]],
iso: Isomorphisms[F]
): RuleSet = {
new RuleSet {
val name = "contravariantSemigroupal"
val parents = Seq(contravariant[A, B, C], semigroupal[A, B, C])
val bases = Seq.empty
val props = Seq(
"contravariantSemigroupal contramap2 delta associates" ->
forAll(laws.contravariantSemigroupalContramap2DiagonalAssociates[A] _)
)
}
}
}

object ContravariantSemigroupalTests {
def apply[F[_]: ContravariantSemigroupal]: ContravariantSemigroupalTests[F] =
new ContravariantSemigroupalTests[F] { def laws: ContravariantSemigroupalLaws[F] = ContravariantSemigroupalLaws[F] }
}
3 changes: 2 additions & 1 deletion tests/src/test/scala/cats/tests/FunctionSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ class FunctionSuite extends CatsSuite {
checkAll("Group[() => Grp]", SerializableTests.serializable(Group[() => Grp]))
checkAll("CommutativeGroup[() => CGrp]", SerializableTests.serializable(CommutativeGroup[() => CGrp]))


// law checks for the various Function1-related instances
checkAll("Function1[String, Semi]", SemigroupTests[Function1[String, Semi]].semigroup)
checkAll("Function1[String, CSemi]", CommutativeSemigroupTests[Function1[String, CSemi]].commutativeSemigroup)
Expand All @@ -101,6 +100,8 @@ class FunctionSuite extends CatsSuite {
checkAll("Function1[String, CMono]", CommutativeMonoidTests[Function1[String, CMono]].commutativeMonoid)
checkAll("Function1[String, Grp]", GroupTests[Function1[String, Grp]].group)
checkAll("Function1[String, CGrp]", CommutativeGroupTests[Function1[String, CGrp]].commutativeGroup)
// Isos for ContravariantMonoidal
implicit val isoCodomain = SemigroupalTests.Isomorphisms.invariant[Function1[?, Long]]
checkAll("Function1[?, Monoid]", ContravariantMonoidalTests[Function1[?, Long]].contravariantMonoidal[Int, Int, Int])

// serialization tests for the various Function1-related instances
Expand Down

0 comments on commit f7c4104

Please sign in to comment.