From f6ded9ef5b19ba91ff412c8fd52e41ab8e320e68 Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Wed, 16 Dec 2015 09:35:19 +0000 Subject: [PATCH 1/6] Added Reducible instance for OneAnd. --- core/src/main/scala/cats/data/OneAnd.scala | 6 ++++++ tests/src/test/scala/cats/tests/ComposeTests.scala | 13 ++----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5500d15548..a0a470770b 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -161,6 +161,12 @@ trait OneAndLowPriority1 extends OneAndLowPriority0 { def map[A, B](fa: OneAnd[F, A])(f: A => B): OneAnd[F, B] = OneAnd(f(fa.head), F.map(fa.tail)(f)) } + + implicit def oneAndReducible[F[_]](implicit foldable: Foldable[F]): Reducible[OneAnd[F, ?]] = + new NonEmptyReducible[OneAnd[F, ?], F] { + def split[A](fa: OneAnd[F, A]): (A, F[A]) = (fa.head, fa.tail) + } + } object OneAnd extends OneAndInstances diff --git a/tests/src/test/scala/cats/tests/ComposeTests.scala b/tests/src/test/scala/cats/tests/ComposeTests.scala index 5aca2b5628..2c177b2774 100644 --- a/tests/src/test/scala/cats/tests/ComposeTests.scala +++ b/tests/src/test/scala/cats/tests/ComposeTests.scala @@ -32,17 +32,8 @@ class ComposeTests extends CatsSuite { { // Reducible composition - val nelReducible = - new NonEmptyReducible[NonEmptyList, List] { - def split[A](fa: NonEmptyList[A]): (A, List[A]) = (fa.head, fa.tail) - } - - val nevReducible = - new NonEmptyReducible[NonEmptyVector, Vector] { - def split[A](fa: NonEmptyVector[A]): (A, Vector[A]) = (fa.head, fa.tail) - } - - implicit val reducibleListVector: Reducible[Lambda[A => NonEmptyList[NonEmptyVector[A]]]] = nelReducible compose nevReducible + implicit val reducibleListVector: Reducible[Lambda[A => NonEmptyList[NonEmptyVector[A]]]] = + Reducible[NonEmptyList] compose Reducible[NonEmptyVector] // No Reducible-specific laws, so check the Foldable laws are satisfied checkAll("Reducible[Lambda[A => List[Vector[A]]]]", FoldableTests[Lambda[A => NonEmptyList[NonEmptyVector[A]]]].foldable[Int, Int]) From 5c67d9efc0030c5f60edc430b5daf068e236763c Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Wed, 16 Dec 2015 10:06:52 +0000 Subject: [PATCH 2/6] Added Alternative#compose and MonoidK#compose. --- core/src/main/scala/cats/Alternative.scala | 17 +++++++++++++++- core/src/main/scala/cats/MonoidK.scala | 19 ++++++++++++++++++ .../test/scala/cats/tests/ComposeTests.scala | 20 ++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 41a095f703..d3679388f6 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -2,5 +2,20 @@ package cats import simulacrum.typeclass -@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] +@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => + /** + * Compose two Alternative intsances. + */ + def compose[G[_]](implicit GG: Alternative[G]): Alternative[λ[α => F[G[α]]]] = + new CompositeAlternative[F, G] { + implicit def F: Alternative[F] = self + implicit def G: Alternative[G] = GG + } +} +trait CompositeAlternative[F[_], G[_]] + extends Alternative[λ[α => F[G[α]]]] with CompositeApplicative[F, G] with CompositeMonoidK[F, G] { + + implicit def F: Alternative[F] + implicit def G: Alternative[G] +} diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index b43e23c968..34ad024529 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -29,6 +29,15 @@ import simulacrum.typeclass */ def empty[A]: F[A] + /** + * Compose two MonoidK intsances. + */ + def compose[G[_]](implicit GG: MonoidK[G]): MonoidK[λ[α => F[G[α]]]] = + new CompositeMonoidK[F, G] { + implicit def F: MonoidK[F] = self + implicit def G: MonoidK[G] = GG + } + /** * Given a type A, create a concrete Monoid[F[A]]. */ @@ -38,3 +47,13 @@ import simulacrum.typeclass def combine(x: F[A], y: F[A]): F[A] = self.combine(x, y) } } + +trait CompositeMonoidK[F[_],G[_]] + extends MonoidK[λ[α => F[G[α]]]] { + + implicit def F: MonoidK[F] + implicit def G: MonoidK[G] + + def empty[A]: F[G[A]] = F.empty + def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combine(x, y) +} diff --git a/tests/src/test/scala/cats/tests/ComposeTests.scala b/tests/src/test/scala/cats/tests/ComposeTests.scala index 2c177b2774..230adefd45 100644 --- a/tests/src/test/scala/cats/tests/ComposeTests.scala +++ b/tests/src/test/scala/cats/tests/ComposeTests.scala @@ -2,7 +2,8 @@ package cats package tests import cats.data.{ NonEmptyList, NonEmptyVector, OneAnd } -import cats.laws.discipline.{ ApplicativeTests, FoldableTests, MonoidalTests, SemigroupKTests, arbitrary, eq }, arbitrary._, eq._ +import cats.laws.discipline.{ AlternativeTests, ApplicativeTests, FoldableTests, MonoidKTests, MonoidalTests, SemigroupKTests } +import cats.laws.discipline.{ arbitrary, eq }, arbitrary._, eq._ import org.scalacheck.Arbitrary class ComposeTests extends CatsSuite { @@ -12,6 +13,15 @@ class ComposeTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfig(maxSize = 5, minSuccessful = 20) + { + // Alternative composition + + implicit val alternativeListVector: Alternative[Lambda[A => List[Vector[A]]]] = Alternative[List] compose Alternative[Vector] + implicit val iso = MonoidalTests.Isomorphisms.invariant[Lambda[A => List[Vector[A]]]] + + checkAll("Alternative[Lambda[A => List[Vector[A]]]]", AlternativeTests[Lambda[A => List[Vector[A]]]].alternative[Int, Int, Int]) + } + { // Applicative composition @@ -29,6 +39,14 @@ class ComposeTests extends CatsSuite { checkAll("Foldable[Lambda[A => List[Vector[A]]]]", FoldableTests[Lambda[A => List[Vector[A]]]].foldable[Int, Int]) } + { + // MonoidK composition + + implicit val monoidKListVector: MonoidK[Lambda[A => List[Vector[A]]]] = MonoidK[List] compose MonoidK[Vector] + + checkAll("MonoidK[Lambda[A => List[Vector[A]]]]", MonoidKTests[Lambda[A => List[Vector[A]]]].monoidK[Int]) + } + { // Reducible composition From b415188364ad44ecb7d0ce2a968e93344beec624 Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Wed, 16 Dec 2015 12:57:40 +0000 Subject: [PATCH 3/6] Reinstate composedWith on MonoidK and SemigroupK as an unconstrained operation. --- core/src/main/scala/cats/MonoidK.scala | 14 ++++++++------ core/src/main/scala/cats/SemigroupK.scala | 21 +++++++++++++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index 34ad024529..bdebd619dc 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -30,14 +30,18 @@ import simulacrum.typeclass def empty[A]: F[A] /** - * Compose two MonoidK intsances. + * Compose two MonoidK instances. */ - def compose[G[_]](implicit GG: MonoidK[G]): MonoidK[λ[α => F[G[α]]]] = + override def composedWith[G[_]]: MonoidK[λ[α => F[G[α]]]] = new CompositeMonoidK[F, G] { implicit def F: MonoidK[F] = self - implicit def G: MonoidK[G] = GG } + /** + * Compose two MonoidK instances. + */ + def compose[G[_]](implicit GG: MonoidK[G]): MonoidK[λ[α => F[G[α]]]] = composedWith[G] + /** * Given a type A, create a concrete Monoid[F[A]]. */ @@ -49,11 +53,9 @@ import simulacrum.typeclass } trait CompositeMonoidK[F[_],G[_]] - extends MonoidK[λ[α => F[G[α]]]] { + extends MonoidK[λ[α => F[G[α]]]] with CompositeSemigroupK[F, G] { implicit def F: MonoidK[F] - implicit def G: MonoidK[G] def empty[A]: F[G[A]] = F.empty - def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combine(x, y) } diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index adfdb3504b..04e0e1c88a 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -29,13 +29,18 @@ import simulacrum.{op, typeclass} def combine[A](x: F[A], y: F[A]): F[A] /** - * Compose two SemigroupK intsances. + * Compose this SemigroupK with an arbitrary type constructor */ - def compose[G[_]: SemigroupK]: SemigroupK[λ[α => F[G[α]]]] = - new SemigroupK[λ[α => F[G[α]]]] { - def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = self.combine(x, y) + def composedWith[G[_]]: SemigroupK[λ[α => F[G[α]]]] = + new CompositeSemigroupK[F, G] { + implicit def F: SemigroupK[F] = self } + /** + * Compose two SemigroupK instances. + */ + def compose[G[_]](implicit GG: SemigroupK[G]): SemigroupK[λ[α => F[G[α]]]] = composedWith[G] + /** * Given a type A, create a concrete Semigroup[F[A]]. */ @@ -44,3 +49,11 @@ import simulacrum.{op, typeclass} def combine(x: F[A], y: F[A]): F[A] = self.combine(x, y) } } + +trait CompositeSemigroupK[F[_],G[_]] + extends SemigroupK[λ[α => F[G[α]]]] { + + implicit def F: SemigroupK[F] + + def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combine(x, y) +} From ec829479abeaad249a7e90e68e4313e4050a6c20 Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Wed, 16 Dec 2015 13:01:28 +0000 Subject: [PATCH 4/6] Tweaked doc. --- core/src/main/scala/cats/MonoidK.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index bdebd619dc..ecbd251b68 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -30,7 +30,7 @@ import simulacrum.typeclass def empty[A]: F[A] /** - * Compose two MonoidK instances. + * Compose this MonoidK with an arbitrary type constructor */ override def composedWith[G[_]]: MonoidK[λ[α => F[G[α]]]] = new CompositeMonoidK[F, G] { From 4aab63e529eaefdea381693c7dbe1c2d1c09c441 Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Wed, 16 Dec 2015 13:38:05 +0000 Subject: [PATCH 5/6] Weakened constraint of RHS of Alternative#compose to Applicative. --- core/src/main/scala/cats/Alternative.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index d3679388f6..6fe269833a 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -6,10 +6,10 @@ import simulacrum.typeclass /** * Compose two Alternative intsances. */ - def compose[G[_]](implicit GG: Alternative[G]): Alternative[λ[α => F[G[α]]]] = + override def compose[G[_]](implicit GG: Applicative[G]): Alternative[λ[α => F[G[α]]]] = new CompositeAlternative[F, G] { implicit def F: Alternative[F] = self - implicit def G: Alternative[G] = GG + implicit def G: Applicative[G] = GG } } @@ -17,5 +17,5 @@ trait CompositeAlternative[F[_], G[_]] extends Alternative[λ[α => F[G[α]]]] with CompositeApplicative[F, G] with CompositeMonoidK[F, G] { implicit def F: Alternative[F] - implicit def G: Alternative[G] + implicit def G: Applicative[G] } From 58b3f5b24fd6b3e3be5dd185fce315d159d4ed70 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Sun, 31 Jan 2016 11:29:17 -0500 Subject: [PATCH 6/6] Update SemigroupK/MonoidK composition Per feedback on #757. --- core/src/main/scala/cats/Alternative.scala | 3 ++- core/src/main/scala/cats/MonoidK.scala | 7 +------ core/src/main/scala/cats/SemigroupK.scala | 7 +------ tests/src/test/scala/cats/tests/ComposeTests.scala | 4 ++-- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 6fe269833a..369bd0bbf8 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -3,8 +3,9 @@ package cats import simulacrum.typeclass @typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => + /** - * Compose two Alternative intsances. + * Compose this `Alternative` instance with an [[Applicative]] instance. */ override def compose[G[_]](implicit GG: Applicative[G]): Alternative[λ[α => F[G[α]]]] = new CompositeAlternative[F, G] { diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index e1c9d39f88..6cdcdb7368 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -32,16 +32,11 @@ import simulacrum.typeclass /** * Compose this MonoidK with an arbitrary type constructor */ - override def composedWith[G[_]]: MonoidK[λ[α => F[G[α]]]] = + override def composeK[G[_]]: MonoidK[λ[α => F[G[α]]]] = new CompositeMonoidK[F, G] { implicit def F: MonoidK[F] = self } - /** - * Compose two MonoidK instances. - */ - def compose[G[_]](implicit GG: MonoidK[G]): MonoidK[λ[α => F[G[α]]]] = composedWith[G] - /** * Given a type A, create a concrete Monoid[F[A]]. */ diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index 8b81c0fa35..4372ea0e26 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -31,16 +31,11 @@ import simulacrum.{op, typeclass} /** * Compose this SemigroupK with an arbitrary type constructor */ - def composedWith[G[_]]: SemigroupK[λ[α => F[G[α]]]] = + def composeK[G[_]]: SemigroupK[λ[α => F[G[α]]]] = new CompositeSemigroupK[F, G] { implicit def F: SemigroupK[F] = self } - /** - * Compose two SemigroupK instances. - */ - def compose[G[_]](implicit GG: SemigroupK[G]): SemigroupK[λ[α => F[G[α]]]] = composedWith[G] - /** * Given a type A, create a concrete Semigroup[F[A]]. */ diff --git a/tests/src/test/scala/cats/tests/ComposeTests.scala b/tests/src/test/scala/cats/tests/ComposeTests.scala index 38a8fa10c6..4ba655529c 100644 --- a/tests/src/test/scala/cats/tests/ComposeTests.scala +++ b/tests/src/test/scala/cats/tests/ComposeTests.scala @@ -41,7 +41,7 @@ class ComposeTests extends CatsSuite { { // MonoidK composition - implicit val monoidKListVector: MonoidK[Lambda[A => List[Vector[A]]]] = MonoidK[List] compose MonoidK[Vector] + implicit val monoidKListVector: MonoidK[Lambda[A => List[Vector[A]]]] = MonoidK[List].composeK[Vector] checkAll("MonoidK[Lambda[A => List[Vector[A]]]]", MonoidKTests[Lambda[A => List[Vector[A]]]].monoidK[Int]) } @@ -59,7 +59,7 @@ class ComposeTests extends CatsSuite { { // SemigroupK composition - implicit val semigroupKListVector: SemigroupK[Lambda[A => List[Vector[A]]]] = SemigroupK[List] compose SemigroupK[Vector] + implicit val semigroupKListVector: SemigroupK[Lambda[A => List[Vector[A]]]] = SemigroupK[List].composeK[Vector] checkAll("SemigroupK[Lambda[A => List[Vector[A]]]]", SemigroupKTests[Lambda[A => List[Vector[A]]]].semigroupK[Int]) }