Skip to content

Commit 24dc3c3

Browse files
committed
Add StrongLaws and StrongTests
1 parent 495aec7 commit 24dc3c3

File tree

7 files changed

+66
-4
lines changed

7 files changed

+66
-4
lines changed

build.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ lazy val core = project.dependsOn(macros)
9797
sourceGenerators in Compile <+= (sourceManaged in Compile).map(Boilerplate.gen)
9898
)
9999

100-
lazy val laws = project.dependsOn(macros, core, data)
100+
lazy val laws = project.dependsOn(macros, core, data, std)
101101
.settings(moduleName := "cats-laws")
102102
.settings(catsSettings: _*)
103103
.settings(

core/src/main/scala/cats/functor/Strong.scala

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package cats
22
package functor
33

4+
/**
5+
* Must obey the laws defined in [[laws.StrongLaws]].
6+
*/
47
trait Strong[F[_, _]] extends Profunctor[F] {
58
def first[A, B, C](fa: F[A, B]): F[(A, C), (B, C)]
69
def second[A, B, C](fa: F[A, B]): F[(C, A), (C, B)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cats.laws
2+
3+
import cats.functor.Strong
4+
import cats.syntax.profunctor._
5+
import cats.syntax.strong._
6+
import cats.std.function._
7+
8+
/**
9+
* Laws that must be obeyed by any [[cats.functor.Strong]].
10+
*/
11+
trait StrongLaws[F[_, _]] extends ProfunctorLaws[F] {
12+
implicit override def F: Strong[F]
13+
14+
def strongFirstDistributivity[A0, A1, B1, B2, C](fab: F[A1, B1], f: A0 => A1, g: B1 => B2): IsEq[F[(A0, C), (B2, C)]] =
15+
fab.dimap(f)(g).first[C] <-> fab.first[C].dimap(f.first[C])(g.first[C])
16+
17+
def strongSecondDistributivity[A0, A1, B1, B2, C](fab: F[A1, B1], f: A0 => A1, g: B1 => B2): IsEq[F[(C, A0), (C, B2)]] =
18+
fab.dimap(f)(g).second[C] <-> fab.second[C].dimap(f.second[C])(g.second[C])
19+
}
20+
21+
object StrongLaws {
22+
def apply[F[_, _]](implicit ev: Strong[F]): StrongLaws[F] =
23+
new StrongLaws[F] { def F = ev }
24+
}

laws/src/main/scala/cats/laws/discipline/SplitTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ trait SplitTests[F[_, _]] extends ComposeTests[F] {
1616
ArbFDE: Arbitrary[F[D, E]],
1717
ArbFEG: Arbitrary[F[E, G]],
1818
EqFAD: Eq[F[A, D]],
19-
EqFADCG: Eq[F[(A, D),(C, G)]]
19+
EqFADCG: Eq[F[(A, D), (C, G)]]
2020
): RuleSet =
2121
new RuleSet {
2222
def name = "split"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package cats.laws
2+
package discipline
3+
4+
import cats.Eq
5+
import cats.functor.Strong
6+
import org.scalacheck.Arbitrary
7+
import org.scalacheck.Prop._
8+
9+
trait StrongTests[F[_, _]] extends ProfunctorTests[F] {
10+
def laws: StrongLaws[F]
11+
12+
def strong[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit
13+
ArbFAB: Arbitrary[F[A, B]],
14+
ArbFBC: Arbitrary[F[B, C]],
15+
ArbFCD: Arbitrary[F[C, D]],
16+
EqFAB: Eq[F[A, B]],
17+
EqFAG: Eq[F[A, G]],
18+
EqFAEDE: Eq[F[(A, E), (D, E)]],
19+
EqFEAED: Eq[F[(E, A), (E, D)]]
20+
): RuleSet =
21+
new RuleSet {
22+
def name = "strong"
23+
def bases = Nil
24+
def parents = Seq(profunctor[A, B, C, D, E, G])
25+
def props = Seq(
26+
"strong first distributivity" -> forAll(laws.strongFirstDistributivity[A, B, C, D, E] _),
27+
"strong second distributivity" -> forAll(laws.strongSecondDistributivity[A, B, C, D, E] _)
28+
)
29+
}
30+
}
31+
32+
object StrongTests {
33+
def apply[F[_, _]: Strong]: StrongTests[F] =
34+
new StrongTests[F] { def laws = StrongLaws[F] }
35+
}

tests/src/test/scala/cats/tests/FunctionTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ class FunctionTests extends CatsSuite {
88
checkAll("Function0[Int]", MonadTests[Function0].monad[Int, Int, Int])
99
checkAll("Function1[Int, Int]", CategoryTests[Function1].category[Int, Int, Int, Int])
1010
checkAll("Function1[Int, Int]", SplitTests[Function1].split[Int, Int, Int, Int, Int, Int])
11-
checkAll("Function1[Int, Int]", ProfunctorTests[Function1].profunctor[Int, Int, Int, Int, Int, Int])
11+
checkAll("Function1[Int, Int]", StrongTests[Function1].strong[Int, Int, Int, Int, Int, Int])
1212
}

tests/src/test/scala/cats/tests/KleisliTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ class KleisliTests extends CatsSuite {
1313
Eq.by[Kleisli[F, A, B], A => F[B]](_.run)
1414

1515
checkAll("Kleisli[Option, Int, Int]", ApplicativeTests[Kleisli[Option, Int, ?]].applicative[Int, Int, Int])
16-
checkAll("Kleisli[Option, Int, Int]", ProfunctorTests[Kleisli[Option, ?, ?]].profunctor[Int, Int, Int, Int, Int, Int])
16+
checkAll("Kleisli[Option, Int, Int]", StrongTests[Kleisli[Option, ?, ?]].strong[Int, Int, Int, Int, Int, Int])
1717
}

0 commit comments

Comments
 (0)