From 64c74fad5aee865d3c31c73d506260b184439f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Tue, 4 Oct 2016 19:19:34 +0200 Subject: [PATCH 01/11] add Monad instance for cats.data.Prod --- core/src/main/scala/cats/data/Prod.scala | 22 ++++++++++++++++++- .../src/test/scala/cats/tests/ProdTests.scala | 6 +++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 493ff8073b..548d86d2c6 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -52,7 +52,7 @@ private[data] sealed abstract class ProdInstances3 extends ProdInstances4 { } } -private[data] sealed abstract class ProdInstances4 { +private[data] sealed abstract class ProdInstances4 extends ProdInstances5 { implicit def catsDataFunctorForProd[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Prod[F, G, α]]] = new ProdFunctor[F, G] { def F: Functor[F] = FF def G: Functor[G] = GG @@ -63,6 +63,13 @@ private[data] sealed abstract class ProdInstances4 { } } +private[data] sealed abstract class ProdInstances5 { + implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { + def F: Monad[F] = FM + def G: Monad[G] = GM + } +} + sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { def F: Functor[F] def G: Functor[G] @@ -109,3 +116,16 @@ sealed trait ProdAlternative[F[_], G[_]] extends Alternative[λ[α => Prod[F, G, def F: Alternative[F] def G: Alternative[G] } + +sealed trait ProdMonad[F[_], G[_]] extends Monad[λ[α => Prod[F, G, α]]] with ProdFunctor[F, G] { + def F: Monad[F] + def G: Monad[G] + override def pure[A](a: A): Prod[F, G, A] = + Prod(F.pure(a), G.pure(a)) + + override def flatMap[A, B](p: Prod[F, G, A])(f: A => Prod[F, G, B]): Prod[F, G, B] = + Prod(F.flatMap(p.first)(f(_).first), G.flatMap(p.second)(f(_).second)) + + def tailRecM[A, B](a: A)(f: A => Prod[F, G, Either[A, B]]): Prod[F, G, B] = + Prod(F.tailRecM(a)(f(_).first), G.tailRecM(a)(f(_).second)) +} diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index 1d04e7bea4..db78a65014 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -42,4 +42,10 @@ class ProdTests extends CatsSuite { checkAll("Prod[ListWrapper, ListWrapper, ?]", FunctorTests[Prod[ListWrapper, ListWrapper, ?]].functor[Int, Int, Int]) checkAll("Functor[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Functor[Prod[ListWrapper, ListWrapper, ?]])) } + + { + implicit val monad = ListWrapper.monad + checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadTests[Prod[ListWrapper, ListWrapper, ?]].monad[Int, Int, Int]) + checkAll("Monad[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Monad[Prod[ListWrapper, ListWrapper, ?]])) + } } From 78f4c60a5bc046a2a7904d16aa5a9751ec6d7a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Wed, 5 Oct 2016 17:49:45 +0200 Subject: [PATCH 02/11] add missing implicit --- tests/src/test/scala/cats/tests/ProdTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index db78a65014..80c1c33148 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -45,6 +45,7 @@ class ProdTests extends CatsSuite { { implicit val monad = ListWrapper.monad + implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[ListWrapper, ListWrapper, ?]] checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadTests[Prod[ListWrapper, ListWrapper, ?]].monad[Int, Int, Int]) checkAll("Monad[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Monad[Prod[ListWrapper, ListWrapper, ?]])) } From c2c7e978864642eae9744212a1ac5bf1ab037797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Fri, 7 Oct 2016 15:26:39 +0200 Subject: [PATCH 03/11] create instances for Foldable and Traverse --- core/src/main/scala/cats/data/Prod.scala | 36 ++++++++++++++++++- .../src/test/scala/cats/tests/ProdTests.scala | 14 ++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 548d86d2c6..22b40306cb 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -2,6 +2,7 @@ package cats package data import cats.functor.Contravariant +import cats.syntax.cartesian._ /** * [[Prod]] is a product to two independent functor values. @@ -63,13 +64,27 @@ private[data] sealed abstract class ProdInstances4 extends ProdInstances5 { } } -private[data] sealed abstract class ProdInstances5 { +private[data] sealed abstract class ProdInstances5 extends ProdInstances6 { implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { def F: Monad[F] = FM def G: Monad[G] = GM } } +private[data] sealed abstract class ProdInstances6 extends ProdInstances7 { + implicit def catsDataFoldableForProd[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Prod[F, G, α]]] = new ProdFoldable[F, G] { + def F: Foldable[F] = FF + def G: Foldable[G] = GF + } +} + +private[data] sealed abstract class ProdInstances7 { + implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { + def F: Traverse[F] = FF + def G: Traverse[G] = GF + } +} + sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { def F: Functor[F] def G: Functor[G] @@ -129,3 +144,22 @@ sealed trait ProdMonad[F[_], G[_]] extends Monad[λ[α => Prod[F, G, α]]] with def tailRecM[A, B](a: A)(f: A => Prod[F, G, Either[A, B]]): Prod[F, G, B] = Prod(F.tailRecM(a)(f(_).first), G.tailRecM(a)(f(_).second)) } + +sealed trait ProdFoldable[F[_], G[_]] extends Foldable[λ[α => Prod[F, G, α]]] { + def F: Foldable[F] + def G: Foldable[G] + + override def foldLeft[A, B](fa: Prod[F, G, A], b: B)(f: (B, A) => B): B = + G.foldLeft(fa.second, F.foldLeft(fa.first, b)(f))(f) + + override def foldRight[A, B](fa: Prod[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fa.first, G.foldRight(fa.second, lb)(f))(f) +} + +sealed trait ProdTraverse[F[_], G[_]] extends Traverse[λ[α => Prod[F, G, α]]] with ProdFoldable[F, G] { + def F: Traverse[F] + def G: Traverse[G] + + override def traverse[H[_]: Applicative, A, B](fa: Prod[F, G, A])(f: A => H[B]): H[Prod[F, G, B]] = + (F.traverse(fa.first)(f) |@| G.traverse(fa.second)(f)).map(Prod(_, _)) +} diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index 80c1c33148..446d449b58 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -49,4 +49,18 @@ class ProdTests extends CatsSuite { checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadTests[Prod[ListWrapper, ListWrapper, ?]].monad[Int, Int, Int]) checkAll("Monad[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Monad[Prod[ListWrapper, ListWrapper, ?]])) } + + { + implicit val foldable = ListWrapper.foldable + checkAll("Prod[ListWrapper, ListWrapper, ?]", FoldableTests[Prod[ListWrapper, ListWrapper, ?]].foldable[Int, Int]) + checkAll("Foldable[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Foldable[Prod[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val traverse = ListWrapper.traverse + + checkAll("Prod[ListWrapper, ListWrapper, ?]", TraverseTests[Prod[ListWrapper, ListWrapper, ?]].traverse[Int, Int, Int, Int, Option, Option]) + checkAll("Traverse[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Traverse[Prod[ListWrapper, ListWrapper, ?]])) + } + } From 95aed3ae61e24475a93d58488d55cb8a7653f2f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Sat, 8 Oct 2016 11:52:02 +0200 Subject: [PATCH 04/11] create instance for MonadCombine --- core/src/main/scala/cats/data/Prod.scala | 19 ++++++++++++++++--- .../src/test/scala/cats/tests/ProdTests.scala | 8 +++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 22b40306cb..1781195f5b 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -78,13 +78,20 @@ private[data] sealed abstract class ProdInstances6 extends ProdInstances7 { } } -private[data] sealed abstract class ProdInstances7 { +private[data] sealed abstract class ProdInstances7 extends ProdInstances8 { implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { def F: Traverse[F] = FF def G: Traverse[G] = GF } } +private[data] sealed abstract class ProdInstances8 { + implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { + def F: MonadCombine[F] = FF + def G: MonadCombine[G] = GF + } +} + sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { def F: Functor[F] def G: Functor[G] @@ -100,7 +107,7 @@ sealed trait ProdContravariant[F[_], G[_]] extends Contravariant[λ[α => Prod[F sealed trait ProdApply[F[_], G[_]] extends Apply[λ[α => Prod[F, G, α]]] with ProdFunctor[F, G] { def F: Apply[F] def G: Apply[G] - def ap[A, B](f: Prod[F, G, A => B])(fa: Prod[F, G, A]): Prod[F, G, B] = + override def ap[A, B](f: Prod[F, G, A => B])(fa: Prod[F, G, A]): Prod[F, G, B] = Prod(F.ap(f.first)(fa.first), G.ap(f.second)(fa.second)) override def product[A, B](fa: Prod[F, G, A], fb: Prod[F, G, B]): Prod[F, G, (A, B)] = Prod(F.product(fa.first, fb.first), G.product(fa.second, fb.second)) @@ -132,7 +139,7 @@ sealed trait ProdAlternative[F[_], G[_]] extends Alternative[λ[α => Prod[F, G, def G: Alternative[G] } -sealed trait ProdMonad[F[_], G[_]] extends Monad[λ[α => Prod[F, G, α]]] with ProdFunctor[F, G] { +sealed trait ProdMonad[F[_], G[_]] extends Monad[λ[α => Prod[F, G, α]]] with ProdApplicative[F, G] { def F: Monad[F] def G: Monad[G] override def pure[A](a: A): Prod[F, G, A] = @@ -163,3 +170,9 @@ sealed trait ProdTraverse[F[_], G[_]] extends Traverse[λ[α => Prod[F, G, α]]] override def traverse[H[_]: Applicative, A, B](fa: Prod[F, G, A])(f: A => H[B]): H[Prod[F, G, B]] = (F.traverse(fa.first)(f) |@| G.traverse(fa.second)(f)).map(Prod(_, _)) } + +sealed trait ProdMonadCombine[F[_], G[_]] extends MonadCombine[λ[α => Prod[F, G, α]]] + with ProdMonad[F, G] with ProdAlternative[F, G] { + def F: MonadCombine[F] + def G: MonadCombine[G] +} diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index 446d449b58..a3c572d9b3 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -58,9 +58,15 @@ class ProdTests extends CatsSuite { { implicit val traverse = ListWrapper.traverse - checkAll("Prod[ListWrapper, ListWrapper, ?]", TraverseTests[Prod[ListWrapper, ListWrapper, ?]].traverse[Int, Int, Int, Int, Option, Option]) checkAll("Traverse[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Traverse[Prod[ListWrapper, ListWrapper, ?]])) } + { + implicit val monadCombine = ListWrapper.monadCombine + implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[ListWrapper, ListWrapper, ?]] + checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadCombineTests[Prod[ListWrapper, ListWrapper, ?]].monadCombine[Int, Int, Int]) + checkAll("MonadCombine[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonadCombine[Prod[ListWrapper, ListWrapper, ?]])) + } + } From d648c889b153b973541c8efe3280553d875a5bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Mon, 10 Oct 2016 18:41:00 +0200 Subject: [PATCH 05/11] create instances for Show and Order --- core/src/main/scala/cats/data/Prod.scala | 28 ++++++++++++++++++- .../src/test/scala/cats/tests/ProdTests.scala | 21 ++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 1781195f5b..d97fe6172b 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -85,13 +85,24 @@ private[data] sealed abstract class ProdInstances7 extends ProdInstances8 { } } -private[data] sealed abstract class ProdInstances8 { +private[data] sealed abstract class ProdInstances8 extends ProdInstances9 { implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { def F: MonadCombine[F] = FF def G: MonadCombine[G] = GF } } +private[data] sealed abstract class ProdInstances9 { + implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { + def F: Order[F[A]] = FF + def G: Order[G[A]] = GF + } + implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { + def F: Show[F[A]] = FF + def G: Show[G[A]] = GF + } +} + sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { def F: Functor[F] def G: Functor[G] @@ -176,3 +187,18 @@ sealed trait ProdMonadCombine[F[_], G[_]] extends MonadCombine[λ[α => Prod[F, def F: MonadCombine[F] def G: MonadCombine[G] } + +sealed trait ProdShow[F[_], G[_], A] extends Show[Prod[F, G, A]] { + def F: Show[F[A]] + def G: Show[G[A]] + + def show(prod: Prod[F, G, A]): String = s"Prod(${F.show(prod.first)}, ${G.show(prod.second)})" +} + +sealed trait ProdOrder[F[_], G[_], A] extends Order[Prod[F, G, A]] { + def F: Order[F[A]] + def G: Order[G[A]] + + def compare(x: Prod[F, G, A], y: Prod[F, G, A]): Int = + Array(F.compare(x.first, y.first), G.compare(x.second, y.second)).find(_ != 0).getOrElse(0) +} diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index a3c572d9b3..2ccf55ee27 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -18,6 +18,8 @@ class ProdTests extends CatsSuite { checkAll("Prod[Show, Order, Int]", ContravariantTests[λ[α => Prod[Show, Order, α]]].contravariant[Int, Int, Int]) checkAll("Contravariant[Prod[Show, Order, Int]]", SerializableTests.serializable(Contravariant[λ[α => Prod[Show, Order, α]]])) + checkAll("Show[Prod[Option, Option, Int]]", SerializableTests.serializable(Show[Prod[Option, Option, Int]])) + { implicit val monoidK = ListWrapper.monoidK checkAll("Prod[ListWrapper, ListWrapper, ?]", MonoidKTests[Prod[ListWrapper, ListWrapper, ?]].monoidK[Int]) @@ -69,4 +71,23 @@ class ProdTests extends CatsSuite { checkAll("MonadCombine[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonadCombine[Prod[ListWrapper, ListWrapper, ?]])) } + test("order") { + forAll { t: Prod[Id, Id, Int] => + val u: Prod[Id, Id, Int] = Prod(t.second, t.first) + val Prod(t1, t2) = t + val Prod(u1, u2) = u + + Order[Prod[Id, Id, Int]].compare(t, u) should === (Order[(Int, Int)].compare((t1, t2), (u1, u2))) + } + } + + test("show") { + forAll { (l1: Option[Int], l2: Option[Int]) => + val showOptionInt = implicitly[Show[Option[Int]]] + val prod = Prod(l1, l2) + + Show[Prod[Option, Option, Int]].show(prod) should === (s"Prod(${showOptionInt.show(l1)}, ${showOptionInt.show(l2)})") + } + } + } From 2032ce0fdc9e3d911595196e360837267378b0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Fri, 14 Oct 2016 14:20:03 +0200 Subject: [PATCH 06/11] check OrderLaws for Prod --- .../scala/cats/laws/discipline/Arbitrary.scala | 3 +++ tests/src/test/scala/cats/tests/ProdTests.scala | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala index c9d2eb4d32..039a76fc35 100644 --- a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala +++ b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala @@ -130,6 +130,9 @@ object arbitrary extends ArbitraryInstances0 { implicit def catsLawsCogenForCoproduct[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[Coproduct[F, G, A]] = Cogen((seed, x) => x.run.fold(F.perturb(seed, _), G.perturb(seed, _))) + implicit def catLawsCogenForProd[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[Prod[F, G, A]] = + Cogen((seed, t) => F.perturb(G.perturb(seed, t.second), t.first)) + implicit def catsLawsArbitraryForShow[A: Arbitrary]: Arbitrary[Show[A]] = Arbitrary(Show.fromToString[A]) diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index 2ccf55ee27..52395416aa 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -6,6 +6,7 @@ import cats.functor.Contravariant import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ +import cats.kernel.laws.OrderLaws class ProdTests extends CatsSuite { implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[Option, List, ?]] @@ -71,14 +72,14 @@ class ProdTests extends CatsSuite { checkAll("MonadCombine[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonadCombine[Prod[ListWrapper, ListWrapper, ?]])) } - test("order") { - forAll { t: Prod[Id, Id, Int] => - val u: Prod[Id, Id, Int] = Prod(t.second, t.first) - val Prod(t1, t2) = t - val Prod(u1, u2) = u + { + implicit val E = ListWrapper.eqv[Int] + implicit val O = ListWrapper.order[Int] + implicit val P = ListWrapper.partialOrder[Int] - Order[Prod[Id, Id, Int]].compare(t, u) should === (Order[(Int, Int)].compare((t1, t2), (u1, u2))) - } + checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].eqv) + checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].order) + checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].partialOrder) } test("show") { From f8462cdd796be028ad613e7a05f5ffe6b16d4f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Fri, 14 Oct 2016 14:20:54 +0200 Subject: [PATCH 07/11] clean up Prod.scala file --- core/src/main/scala/cats/data/Prod.scala | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index d97fe6172b..ddc82e30c7 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -23,6 +23,11 @@ private[data] sealed abstract class ProdInstances extends ProdInstances0 { def eqv(x: Prod[F, G, A], y: Prod[F, G, A]): Boolean = FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) } + + implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { + def F: Show[F[A]] = FF + def G: Show[G[A]] = GF + } } private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { @@ -30,6 +35,11 @@ private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { def F: MonoidK[F] = FF def G: MonoidK[G] = GG } + + implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { + def F: Order[F[A]] = FF + def G: Order[G[A]] = GF + } } private[data] sealed abstract class ProdInstances1 extends ProdInstances2 { @@ -85,24 +95,13 @@ private[data] sealed abstract class ProdInstances7 extends ProdInstances8 { } } -private[data] sealed abstract class ProdInstances8 extends ProdInstances9 { +private[data] sealed abstract class ProdInstances8 { implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { def F: MonadCombine[F] = FF def G: MonadCombine[G] = GF } } -private[data] sealed abstract class ProdInstances9 { - implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { - def F: Order[F[A]] = FF - def G: Order[G[A]] = GF - } - implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { - def F: Show[F[A]] = FF - def G: Show[G[A]] = GF - } -} - sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { def F: Functor[F] def G: Functor[G] From 4e9c489fd74e704ba6fb1c86fdb3a7e28699672a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Wed, 19 Oct 2016 09:27:36 +0200 Subject: [PATCH 08/11] make Order have more priority than Eq --- core/src/main/scala/cats/data/Prod.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index ddc82e30c7..50d80fd7ec 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -19,9 +19,9 @@ private[data] sealed abstract class ProdInstances extends ProdInstances0 { def G: Alternative[G] = GG } - implicit def catsDataEqForProd[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Prod[F, G, A]] = new Eq[Prod[F, G, A]] { - def eqv(x: Prod[F, G, A], y: Prod[F, G, A]): Boolean = - FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) + implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { + def F: Order[F[A]] = FF + def G: Order[G[A]] = GF } implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { @@ -36,9 +36,9 @@ private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { def G: MonoidK[G] = GG } - implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { - def F: Order[F[A]] = FF - def G: Order[G[A]] = GF + implicit def catsDataEqForProd[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Prod[F, G, A]] = new Eq[Prod[F, G, A]] { + def eqv(x: Prod[F, G, A], y: Prod[F, G, A]): Boolean = + FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) } } From 000a583222074ce1df0d9c81c4dbc0c73cde548b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Thu, 20 Oct 2016 17:51:28 +0200 Subject: [PATCH 09/11] reorder Prod instances acording to its specificity --- core/src/main/scala/cats/data/Prod.scala | 43 +++++++++++------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 50d80fd7ec..9d5de25c3d 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -14,9 +14,9 @@ final case class Prod[F[_], G[_], A](first: F[A], second: G[A]) object Prod extends ProdInstances private[data] sealed abstract class ProdInstances extends ProdInstances0 { - implicit def catsDataAlternativeForProd[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Prod[F, G, α]]] = new ProdAlternative[F, G] { - def F: Alternative[F] = FF - def G: Alternative[G] = GG + implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { + def F: MonadCombine[F] = FF + def G: MonadCombine[G] = GF } implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { @@ -57,16 +57,16 @@ private[data] sealed abstract class ProdInstances2 extends ProdInstances3 { } private[data] sealed abstract class ProdInstances3 extends ProdInstances4 { - implicit def catsDataApplyForProd[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[λ[α => Prod[F, G, α]]] = new ProdApply[F, G] { - def F: Apply[F] = FF - def G: Apply[G] = GG + implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { + def F: Monad[F] = FM + def G: Monad[G] = GM } } private[data] sealed abstract class ProdInstances4 extends ProdInstances5 { - implicit def catsDataFunctorForProd[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Prod[F, G, α]]] = new ProdFunctor[F, G] { - def F: Functor[F] = FF - def G: Functor[G] = GG + implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { + def F: Traverse[F] = FF + def G: Traverse[G] = GF } implicit def catsDataContravariantForProd[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Prod[F, G, α]]] = new ProdContravariant[F, G] { def F: Contravariant[F] = FC @@ -75,30 +75,27 @@ private[data] sealed abstract class ProdInstances4 extends ProdInstances5 { } private[data] sealed abstract class ProdInstances5 extends ProdInstances6 { - implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { - def F: Monad[F] = FM - def G: Monad[G] = GM + implicit def catsDataApplyForProd[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[λ[α => Prod[F, G, α]]] = new ProdApply[F, G] { + def F: Apply[F] = FF + def G: Apply[G] = GG } } private[data] sealed abstract class ProdInstances6 extends ProdInstances7 { + implicit def catsDataFunctorForProd[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Prod[F, G, α]]] = new ProdFunctor[F, G] { + def F: Functor[F] = FF + def G: Functor[G] = GG + } implicit def catsDataFoldableForProd[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Prod[F, G, α]]] = new ProdFoldable[F, G] { def F: Foldable[F] = FF def G: Foldable[G] = GF } } -private[data] sealed abstract class ProdInstances7 extends ProdInstances8 { - implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { - def F: Traverse[F] = FF - def G: Traverse[G] = GF - } -} - -private[data] sealed abstract class ProdInstances8 { - implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { - def F: MonadCombine[F] = FF - def G: MonadCombine[G] = GF +private[data] sealed abstract class ProdInstances7 { + implicit def catsDataAlternativeForProd[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Prod[F, G, α]]] = new ProdAlternative[F, G] { + def F: Alternative[F] = FF + def G: Alternative[G] = GG } } From 405dd93d6336593e957d9e462dd250da76c342e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Mon, 24 Oct 2016 19:30:38 +0200 Subject: [PATCH 10/11] simplify test("show") --- tests/src/test/scala/cats/tests/ProdTests.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala index 52395416aa..751a3d184a 100644 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ b/tests/src/test/scala/cats/tests/ProdTests.scala @@ -84,10 +84,9 @@ class ProdTests extends CatsSuite { test("show") { forAll { (l1: Option[Int], l2: Option[Int]) => - val showOptionInt = implicitly[Show[Option[Int]]] val prod = Prod(l1, l2) - Show[Prod[Option, Option, Int]].show(prod) should === (s"Prod(${showOptionInt.show(l1)}, ${showOptionInt.show(l2)})") + Show[Prod[Option, Option, Int]].show(prod) should === (s"Prod(${Show[Option[Int]].show(l1)}, ${Show[Option[Int]].show(l2)})") } } From 867b2a2b3b6fee570966ee2108a96408dc1746b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pepe=20Garc=C3=ADa?= Date: Mon, 24 Oct 2016 19:33:41 +0200 Subject: [PATCH 11/11] reorder instances to allow ambiguous implicit values --- core/src/main/scala/cats/data/Prod.scala | 69 ++++++++++-------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala index 9d5de25c3d..3335535aef 100644 --- a/core/src/main/scala/cats/data/Prod.scala +++ b/core/src/main/scala/cats/data/Prod.scala @@ -18,24 +18,33 @@ private[data] sealed abstract class ProdInstances extends ProdInstances0 { def F: MonadCombine[F] = FF def G: MonadCombine[G] = GF } - implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { def F: Order[F[A]] = FF def G: Order[G[A]] = GF } - implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { def F: Show[F[A]] = FF def G: Show[G[A]] = GF } + implicit def catsDataContravariantForProd[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Prod[F, G, α]]] = new ProdContravariant[F, G] { + def F: Contravariant[F] = FC + def G: Contravariant[G] = GC + } } private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { - implicit def catsDataMonoidKForProd[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G]): MonoidK[λ[α => Prod[F, G, α]]] = new ProdMonoidK[F, G] { - def F: MonoidK[F] = FF - def G: MonoidK[G] = GG + implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { + def F: Traverse[F] = FF + def G: Traverse[G] = GF + } + implicit def catsDataAlternativeForProd[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Prod[F, G, α]]] = new ProdAlternative[F, G] { + def F: Alternative[F] = FF + def G: Alternative[G] = GG + } + implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { + def F: Monad[F] = FM + def G: Monad[G] = GM } - implicit def catsDataEqForProd[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Prod[F, G, A]] = new Eq[Prod[F, G, A]] { def eqv(x: Prod[F, G, A], y: Prod[F, G, A]): Boolean = FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) @@ -43,60 +52,36 @@ private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { } private[data] sealed abstract class ProdInstances1 extends ProdInstances2 { - implicit def catsDataSemigroupKForProd[F[_], G[_]](implicit FF: SemigroupK[F], GG: SemigroupK[G]): SemigroupK[λ[α => Prod[F, G, α]]] = new ProdSemigroupK[F, G] { - def F: SemigroupK[F] = FF - def G: SemigroupK[G] = GG + implicit def catsDataFoldableForProd[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Prod[F, G, α]]] = new ProdFoldable[F, G] { + def F: Foldable[F] = FF + def G: Foldable[G] = GF + } + implicit def catsDataMonoidKForProd[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G]): MonoidK[λ[α => Prod[F, G, α]]] = new ProdMonoidK[F, G] { + def F: MonoidK[F] = FF + def G: MonoidK[G] = GG } -} - -private[data] sealed abstract class ProdInstances2 extends ProdInstances3 { implicit def catsDataApplicativeForProd[F[_], G[_]](implicit FF: Applicative[F], GG: Applicative[G]): Applicative[λ[α => Prod[F, G, α]]] = new ProdApplicative[F, G] { def F: Applicative[F] = FF def G: Applicative[G] = GG } } -private[data] sealed abstract class ProdInstances3 extends ProdInstances4 { - implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { - def F: Monad[F] = FM - def G: Monad[G] = GM - } -} - -private[data] sealed abstract class ProdInstances4 extends ProdInstances5 { - implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { - def F: Traverse[F] = FF - def G: Traverse[G] = GF - } - implicit def catsDataContravariantForProd[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Prod[F, G, α]]] = new ProdContravariant[F, G] { - def F: Contravariant[F] = FC - def G: Contravariant[G] = GC +private[data] sealed abstract class ProdInstances2 extends ProdInstances3 { + implicit def catsDataSemigroupKForProd[F[_], G[_]](implicit FF: SemigroupK[F], GG: SemigroupK[G]): SemigroupK[λ[α => Prod[F, G, α]]] = new ProdSemigroupK[F, G] { + def F: SemigroupK[F] = FF + def G: SemigroupK[G] = GG } -} - -private[data] sealed abstract class ProdInstances5 extends ProdInstances6 { implicit def catsDataApplyForProd[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[λ[α => Prod[F, G, α]]] = new ProdApply[F, G] { def F: Apply[F] = FF def G: Apply[G] = GG } } -private[data] sealed abstract class ProdInstances6 extends ProdInstances7 { +private[data] sealed abstract class ProdInstances3 { implicit def catsDataFunctorForProd[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Prod[F, G, α]]] = new ProdFunctor[F, G] { def F: Functor[F] = FF def G: Functor[G] = GG } - implicit def catsDataFoldableForProd[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Prod[F, G, α]]] = new ProdFoldable[F, G] { - def F: Foldable[F] = FF - def G: Foldable[G] = GF - } -} - -private[data] sealed abstract class ProdInstances7 { - implicit def catsDataAlternativeForProd[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Prod[F, G, α]]] = new ProdAlternative[F, G] { - def F: Alternative[F] = FF - def G: Alternative[G] = GG - } } sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] {