From 880c8fb3ab609c4118bac52bb2c074cc23ba0e2a Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Sat, 7 May 2016 14:47:17 -0700 Subject: [PATCH 1/6] Replace type class composition with Compose data type We currently use cats.data.Prod for product composition - for consistency, and for reasons outlined in #968, I think we should use a cats.data.Compose data type for nested composition. I did the usual type classes first. No tests are added intentionally, putting this up as a proof of concept. If nobody yells at me for a couple of days I'll assume everything is OK and I'll clean things up, add comments, tests, etc. --- core/src/main/scala/cats/Alternative.scala | 19 +- core/src/main/scala/cats/Applicative.scala | 24 --- core/src/main/scala/cats/Apply.scala | 29 --- core/src/main/scala/cats/Foldable.scala | 30 --- core/src/main/scala/cats/Functor.scala | 42 ---- core/src/main/scala/cats/MonoidK.scala | 16 -- core/src/main/scala/cats/Reducible.scala | 38 ---- core/src/main/scala/cats/SemigroupK.scala | 16 -- core/src/main/scala/cats/data/Compose.scala | 192 ++++++++++++++++++ core/src/main/scala/cats/data/Func.scala | 19 +- .../main/scala/cats/functor/Invariant.scala | 16 -- 11 files changed, 201 insertions(+), 240 deletions(-) create mode 100644 core/src/main/scala/cats/data/Compose.scala diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 369bd0bbf8..1f86cff46b 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -2,21 +2,4 @@ package cats import simulacrum.typeclass -@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => - - /** - * Compose this `Alternative` instance with an [[Applicative]] instance. - */ - override def compose[G[_]](implicit GG: Applicative[G]): Alternative[λ[α => F[G[α]]]] = - new CompositeAlternative[F, G] { - implicit def F: Alternative[F] = self - implicit def G: Applicative[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: Applicative[G] -} +@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index 41532316cf..1c4e29f1d9 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -38,33 +38,9 @@ import cats.std.list._ def replicateA[A](n: Int, fa: F[A]): F[List[A]] = sequence(List.fill(n)(fa)) - /** - * Two sequentially dependent Applicatives can be composed. - * - * The composition of Applicatives `F` and `G`, `F[G[x]]`, is also an Applicative - * - * Applicative[Option].compose[List].pure(10) = Some(List(10)) - */ - def compose[G[_]](implicit GG : Applicative[G]): Applicative[λ[α => F[G[α]]]] = - new CompositeApplicative[F,G] { - implicit def F: Applicative[F] = self - implicit def G: Applicative[G] = GG - - } - def traverse[A, G[_], B](value: G[A])(f: A => F[B])(implicit G: Traverse[G]): F[G[B]] = G.traverse(value)(f)(this) def sequence[G[_], A](as: G[F[A]])(implicit G: Traverse[G]): F[G[A]] = G.sequence(as)(this) - -} - -trait CompositeApplicative[F[_],G[_]] - extends Applicative[λ[α => F[G[α]]]] with CompositeApply[F,G] { - - implicit def F: Applicative[F] - implicit def G: Applicative[G] - - def pure[A](a: A): F[G[A]] = F.pure(G.pure(a)) } diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index f70b153ce5..d1541300fa 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -32,33 +32,4 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[ */ def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] = map(product(fa, fb)) { case (a, b) => f(a, b) } - - /** - * Two sequentially dependent Applys can be composed. - * - * The composition of Applys `F` and `G`, `F[G[x]]`, is also an Apply. - * - * val ap = Apply[Option].compose[List] - * val x = Some(List(1, 2)) - * val y = Some(List(10, 20)) - * ap.map2(x, y)(_ + _) == Some(List(11, 12, 21, 22)) - */ - def compose[G[_]](implicit GG: Apply[G]): Apply[Lambda[X => F[G[X]]]] = - new CompositeApply[F, G] { - def F: Apply[F] = self - def G: Apply[G] = GG - } - -} - -trait CompositeApply[F[_], G[_]] - extends Apply[Lambda[X => F[G[X]]]] with Functor.Composite[F, G] { - def F: Apply[F] - def G: Apply[G] - - def ap[A, B](f: F[G[A => B]])(fa: F[G[A]]): F[G[B]] = - F.ap(F.map(f)(gab => G.ap(gab)(_)))(fa) - - override def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] = - F.map2(fa, fb)(G.product) } diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index aa83ebf49e..1ebfe830ae 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -268,36 +268,6 @@ import simulacrum.typeclass def nonEmpty[A](fa: F[A]): Boolean = !isEmpty(fa) - - /** - * Compose this `Foldable[F]` with a `Foldable[G]` to create - * a `Foldable[F[G]]` instance. - */ - def compose[G[_]](implicit ev: Foldable[G]): Foldable[λ[α => F[G[α]]]] = - new CompositeFoldable[F, G] { - val F = self - val G = ev - } -} - -/** - * Methods that apply to 2 nested Foldable instances - */ -trait CompositeFoldable[F[_], G[_]] extends Foldable[λ[α => F[G[α]]]] { - implicit def F: Foldable[F] - implicit def G: Foldable[G] - - /** - * Left associative fold on F[G[A]] using 'f' - */ - def foldLeft[A, B](fga: F[G[A]], b: B)(f: (B, A) => B): B = - F.foldLeft(fga, b)((b, a) => G.foldLeft(a, b)(f)) - - /** - * Right associative lazy fold on `F` using the folding function 'f'. - */ - def foldRight[A, B](fga: F[G[A]], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - F.foldRight(fga, lb)((ga, lb) => G.foldRight(ga, lb)(f)) } object Foldable { diff --git a/core/src/main/scala/cats/Functor.scala b/core/src/main/scala/cats/Functor.scala index ed35aa0db5..c8f1596409 100644 --- a/core/src/main/scala/cats/Functor.scala +++ b/core/src/main/scala/cats/Functor.scala @@ -1,7 +1,6 @@ package cats import simulacrum.typeclass -import functor.Contravariant /** * Functor. @@ -15,29 +14,6 @@ import functor.Contravariant def imap[A, B](fa: F[A])(f: A => B)(fi: B => A): F[B] = map(fa)(f) - /** - * Compose this functor F with a functor G to produce a composite - * Functor on G[F[_]], with a map method which uses an A => B to - * map a G[F[A]] to a G[F[B]]. - */ - def compose[G[_]](implicit GG: Functor[G]): Functor[Lambda[X => F[G[X]]]] = new Functor.Composite[F, G] { - def F: Functor[F] = self - def G: Functor[G] = GG - } - - /** - * Compose this functor F with a Contravariant Functor G to produce a new Contravariant Functor - * on F[G[_]]. - */ - override def composeWithContravariant[G[_]](implicit GG: Contravariant[G]): Contravariant[Lambda[X => F[G[X]]]] = - new Functor.ContravariantComposite[F, G] { - def F: Functor[F] = self - def G: Contravariant[G] = GG - } - - override def composeWithFunctor[G[_]: Functor]: Functor[Lambda[X => F[G[X]]]] = compose[G] - - // derived methods /** @@ -61,21 +37,3 @@ import functor.Contravariant */ def as[A, B](fa: F[A], b: B): F[B] = map(fa)(_ => b) } - -object Functor { - trait Composite[F[_], G[_]] extends Functor[Lambda[X => F[G[X]]]] { - def F: Functor[F] - def G: Functor[G] - - override def map[A, B](fa: F[G[A]])(f: A => B): F[G[B]] = - F.map(fa)(G.lift(f)) - } - - trait ContravariantComposite[F[_], G[_]] extends Contravariant[Lambda[X => F[G[X]]]] { - def F: Functor[F] - def G: Contravariant[G] - - override def contramap[A, B](fa: F[G[A]])(f: B => A): F[G[B]] = - F.map(fa)(ga => G.contramap(ga)(f)) - } -} diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index 6cdcdb7368..e55077151d 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -29,14 +29,6 @@ import simulacrum.typeclass */ def empty[A]: F[A] - /** - * Compose this MonoidK with an arbitrary type constructor - */ - override def composeK[G[_]]: MonoidK[λ[α => F[G[α]]]] = - new CompositeMonoidK[F, G] { - implicit def F: MonoidK[F] = self - } - /** * Given a type A, create a concrete Monoid[F[A]]. */ @@ -46,11 +38,3 @@ import simulacrum.typeclass def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } } - -trait CompositeMonoidK[F[_],G[_]] - extends MonoidK[λ[α => F[G[α]]]] with CompositeSemigroupK[F, G] { - - implicit def F: MonoidK[F] - - def empty[A]: F[G[A]] = F.empty -} diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 2f92905e38..2ce9dd90a7 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -99,46 +99,8 @@ import simulacrum.typeclass */ def sequence1_[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = G.map(reduceLeft(fga)((x, y) => G.map2(x, y)((_, b) => b)))(_ => ()) - - /** - * Compose two `Reducible` instances into a new one. - */ - def compose[G[_]](implicit GG: Reducible[G]): Reducible[λ[α => F[G[α]]]] = - new CompositeReducible[F, G] { - implicit def F: Reducible[F] = self - implicit def G: Reducible[G] = GG - } -} - - -/** - * This class composes two `Reducible` instances to provide an - * instance for the nested types. - * - * In other words, given a `Reducible[F]` instance (which can reduce - * `F[A]`) and a `Reducible[G]` instance (which can reduce `G[A]` - * values), this class is able to reduce `F[G[A]]` values. - */ -trait CompositeReducible[F[_], G[_]] extends Reducible[λ[α => F[G[α]]]] with CompositeFoldable[F, G] { - implicit def F: Reducible[F] - implicit def G: Reducible[G] - - override def reduceLeftTo[A, B](fga: F[G[A]])(f: A => B)(g: (B, A) => B): B = { - def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) - F.reduceLeftTo(fga)(toB) { (b, ga) => - G.foldLeft(ga, b)(g) - } - } - - override def reduceRightTo[A, B](fga: F[G[A]])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { - def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value - F.reduceRightTo(fga)(toB) { (ga, lb) => - G.foldRight(ga, lb)(g) - } - } } - /** * This class defines a `Reducible[F]` in terms of a `Foldable[G]` * together with a `split method, `F[A]` => `(A, G[A])`. diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index 113228cb3b..999d74c726 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -28,14 +28,6 @@ import simulacrum.typeclass @simulacrum.op("<+>", alias=true) def combineK[A](x: F[A], y: F[A]): F[A] - /** - * Compose this SemigroupK with an arbitrary type constructor - */ - def composeK[G[_]]: SemigroupK[λ[α => F[G[α]]]] = - new CompositeSemigroupK[F, G] { - implicit def F: SemigroupK[F] = self - } - /** * Given a type A, create a concrete Semigroup[F[A]]. */ @@ -44,11 +36,3 @@ import simulacrum.typeclass def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } } - -trait CompositeSemigroupK[F[_],G[_]] - extends SemigroupK[λ[α => F[G[α]]]] { - - implicit def F: SemigroupK[F] - - def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combineK(x, y) -} diff --git a/core/src/main/scala/cats/data/Compose.scala b/core/src/main/scala/cats/data/Compose.scala new file mode 100644 index 0000000000..50560cc5b2 --- /dev/null +++ b/core/src/main/scala/cats/data/Compose.scala @@ -0,0 +1,192 @@ +package cats +package data + +import cats.functor._ + +final case class Compose[F[_], G[_], A](value: F[G[A]]) + +object Compose extends ComposeInstances + +private[data] sealed abstract class ComposeInstances extends ComposeInstances1 { + implicit def composeTraverse[F[_]: Traverse, G[_]: Traverse]: Traverse[Compose[F, G, ?]] = + new ComposeTraverse[F, G] { + val F = Traverse[F] + val G = Traverse[G] + } +} + +private[data] sealed abstract class ComposeInstances1 extends ComposeInstances2 { + /** + * This composes two `Reducible` instances to provide an + * instance for the nested types. + * + * In other words, given a `Reducible[F]` instance (which can reduce + * `F[A]`) and a `Reducible[G]` instance (which can reduce `G[A]` + * values), this class is able to reduce `F[G[A]]` values. + */ + implicit def composeReducible[F[_]: Reducible, G[_]: Reducible]: Reducible[Compose[F, G, ?]] = + new ComposeReducible[F, G] { + val F = Reducible[F] + val G = Reducible[G] + } +} + +private[data] sealed abstract class ComposeInstances2 extends ComposeInstances3 { + implicit def composeFoldable[F[_]: Foldable, G[_]: Foldable]: Foldable[Compose[F, G, ?]] = + new ComposeFoldable[F, G] { + val F = Foldable[F] + val G = Foldable[G] + } +} + +private[data] sealed abstract class ComposeInstances3 extends ComposeInstances4 { + implicit def composeAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Compose[F, G, ?]] = + new CompositeAlternative[F, G] { + val F = Alternative[F] + val G = Applicative[G] + } +} + +private[data] sealed abstract class ComposeInstances4 extends ComposeInstances5 { + /** + * Two sequentially dependent Applicatives can be composed. + * + * The composition of Applicatives `F` and `G`, `F[G[x]]`, is also an Applicative + * + * Applicative[Option].compose[List].pure(10) = Some(List(10)) + */ + implicit def composeApplicative[F[_]: Applicative, G[_]: Applicative]: Applicative[Compose[F, G, ?]] = + new ComposeApplicative[F, G] { + val F = Applicative[F] + val G = Applicative[G] + } + + implicit def composeMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Compose[F, G, ?]] = + new ComposeMonoidK[F, G] { + val F = MonoidK[F] + } +} + +private[data] sealed abstract class ComposeInstances5 extends ComposeInstances6 { + /** + * Two sequentially dependent Applys can be composed. + * + * The composition of Applys `F` and `G`, `F[G[x]]`, is also an Apply. + * + * val ap = Apply[Option].compose[List] + * val x = Some(List(1, 2)) + * val y = Some(List(10, 20)) + * ap.map2(x, y)(_ + _) == Some(List(11, 12, 21, 22)) + */ + implicit def composeApply[F[_]: Apply, G[_]: Apply]: Apply[Compose[F, G, ?]] = + new ComposeApply[F, G] { + val F = Apply[F] + val G = Apply[G] + } + + implicit def composeSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Compose[F, G, ?]] = + new ComposeSemigroupK[F, G] { + val F = SemigroupK[F] + } +} + +private[data] sealed abstract class ComposeInstances6 extends ComposeInstances7 { + implicit def composeFunctor[F[_]: Functor, G[_]: Functor]: Functor[Compose[F, G, ?]] = + new ComposeFunctor[F, G] { + val F = Functor[F] + val G = Functor[G] + } +} + +private[data] sealed abstract class ComposeInstances7 { + implicit def composeInvariant[F[_]: Invariant, G[_]: Invariant]: Invariant[Compose[F, G, ?]] = + new ComposeInvariant[F, G] { + val F = Invariant[F] + val G = Invariant[G] + } +} + +private[data] trait ComposeInvariant[F[_], G[_]] extends Invariant[Compose[F, G, ?]] { + def F: Invariant[F] + def G: Invariant[G] + + override def imap[A, B](fga: Compose[F, G, A])(f: A => B)(g: B => A): Compose[F, G, B] = + Compose(F.imap(fga.value)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f))) +} + +private[data] trait ComposeFunctor[F[_], G[_]] extends Functor[Compose[F, G, ?]] with ComposeInvariant[F, G] { + def F: Functor[F] + def G: Functor[G] + + override def map[A, B](fga: Compose[F, G, A])(f: A => B): Compose[F, G, B] = + Compose(F.map(fga.value)(ga => G.map(ga)(f))) +} + +private[data] trait ComposeApply[F[_], G[_]] extends Apply[Compose[F, G, ?]] with ComposeFunctor[F, G] { + def F: Apply[F] + def G: Apply[G] + + override def ap[A, B](ff: Compose[F, G, A => B])(fa: Compose[F, G, A]): Compose[F, G, B] = + Compose(F.ap(F.map(ff.value)(gab => G.ap(gab)(_)))(fa.value)) +} + +private[data] trait ComposeApplicative[F[_], G[_]] extends Applicative[Compose[F, G, ?]] with ComposeApply[F, G] { + def F: Applicative[F] + def G: Applicative[G] + + override def pure[A](x: A): Compose[F, G, A] = Compose(F.pure(G.pure(x))) +} + +private[data] trait ComposeSemigroupK[F[_], G[_]] extends SemigroupK[Compose[F, G, ?]] { + def F: SemigroupK[F] + + def combineK[A](x: Compose[F, G, A], y: Compose[F, G, A]): Compose[F, G, A] = Compose(F.combineK(x.value, y.value)) +} + +private[data] trait ComposeMonoidK[F[_], G[_]] extends MonoidK[Compose[F, G, ?]] with ComposeSemigroupK[F, G] { + def F: MonoidK[F] + + def empty[A]: Compose[F, G, A] = Compose(F.empty) +} + +private[data] trait CompositeAlternative[F[_], G[_]] extends Alternative[Compose[F, G, ?]] with ComposeApplicative[F, G] with ComposeMonoidK[F, G] { + def F: Alternative[F] +} + +private[data] trait ComposeFoldable[F[_], G[_]] extends Foldable[Compose[F, G, ?]] { + def F: Foldable[F] + def G: Foldable[G] + + def foldLeft[A, B](fga: Compose[F, G, A], b: B)(f: (B, A) => B): B = + F.foldLeft(fga.value, b)((b, a) => G.foldLeft(a, b)(f)) + + def foldRight[A, B](fga: Compose[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fga.value, lb)((ga, lb) => G.foldRight(ga, lb)(f)) +} + +private[data] trait ComposeTraverse[F[_], G[_]] extends Traverse[Compose[F, G, ?]] with ComposeFoldable[F, G] with ComposeFunctor[F, G] { + def F: Traverse[F] + def G: Traverse[G] + + def traverse[H[_]: Applicative, A, B](fga: Compose[F, G, A])(f: A => H[B]): H[Compose[F, G, B]] = + Applicative[H].map(F.traverse(fga.value)(ga => G.traverse(ga)(f)))(Compose(_)) +} + +private[data] trait ComposeReducible[F[_], G[_]] extends Reducible[Compose[F, G, ?]] with ComposeFoldable[F, G] { + def F: Reducible[F] + def G: Reducible[G] + + override def reduceLeftTo[A, B](fga: Compose[F, G, A])(f: A => B)(g: (B, A) => B): B = { + def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) + F.reduceLeftTo(fga.value)(toB) { (b, ga) => + G.foldLeft(ga, b)(g) + } + } + + override def reduceRightTo[A, B](fga: Compose[F, G, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { + def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value + F.reduceRightTo(fga.value)(toB) { (ga, lb) => + G.foldRight(ga, lb)(g) + } + } +} diff --git a/core/src/main/scala/cats/data/Func.scala b/core/src/main/scala/cats/data/Func.scala index 54487031ff..e6a993c52a 100644 --- a/core/src/main/scala/cats/data/Func.scala +++ b/core/src/main/scala/cats/data/Func.scala @@ -87,17 +87,14 @@ sealed abstract class AppFunc[F[_], A, B] extends Func[F, A, B] { self => } } - def compose[G[_], C](g: AppFunc[G, C, A]): AppFunc[Lambda[X => G[F[X]]], C, B] = - { - implicit val FF: Applicative[F] = self.F - implicit val GG: Applicative[G] = g.F - implicit val GGFF: Applicative[Lambda[X => G[F[X]]]] = GG.compose(FF) - Func.appFunc[Lambda[X => G[F[X]]], C, B]({ - c: C => GG.map(g.run(c))(self.run) - }) - } - - def andThen[G[_], C](g: AppFunc[G, B, C]): AppFunc[Lambda[X => F[G[X]]], A, C] = + def compose[G[_], C](g: AppFunc[G, C, A]): AppFunc[Compose[G, F, ?], C, B] = { + implicit val gfApplicative: Applicative[Compose[G, F, ?]] = Compose.composeApplicative[G, F](g.F, F) + Func.appFunc[Compose[G, F, ?], C, B]({ + c: C => Compose(g.F.map(g.run(c))(self.run)) + }) + } + + def andThen[G[_], C](g: AppFunc[G, B, C]): AppFunc[Compose[F, G, ?], A, C] = g.compose(self) def map[C](f: B => C): AppFunc[F, A, C] = diff --git a/core/src/main/scala/cats/functor/Invariant.scala b/core/src/main/scala/cats/functor/Invariant.scala index ac2653f7b5..a8d969d8a5 100644 --- a/core/src/main/scala/cats/functor/Invariant.scala +++ b/core/src/main/scala/cats/functor/Invariant.scala @@ -9,14 +9,6 @@ import simulacrum.typeclass @typeclass trait Invariant[F[_]] { self => def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] - /** - * Compose 2 invariant Functors F and G to get a new Invariant Functor for F[G[_]]. - */ - def compose[G[_]: Invariant](implicit GG: Invariant[G]): Invariant[Lambda[X => F[G[X]]]] = new Invariant.Composite[F, G] { - def F: Invariant[F] = self - def G: Invariant[G] = GG - } - /** * Compose the Invariant Functor F with a normal (Covariant) Functor to get a new Invariant Functor for [F[G[_]]. */ @@ -35,14 +27,6 @@ import simulacrum.typeclass } object Invariant extends AlgebraInvariantInstances { - trait Composite[F[_], G[_]] extends Invariant[Lambda[X => F[G[X]]]] { - def F: Invariant[F] - def G: Invariant[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f)) - } - trait CovariantComposite[F[_], G[_]] extends Invariant[Lambda[X => F[G[X]]]] { def F: Invariant[F] def G: Functor[G] From 3c90ab39e298413efc2d1206760fb4652c710ef4 Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Sun, 15 May 2016 19:40:07 -0700 Subject: [PATCH 2/6] Rename Compose to Nested, add tests, change tut --- core/src/main/scala/cats/data/Compose.scala | 201 ------------- core/src/main/scala/cats/data/Func.scala | 10 +- core/src/main/scala/cats/data/Nested.scala | 265 ++++++++++++++++++ .../scala/cats/functor/Contravariant.scala | 30 -- .../main/scala/cats/functor/Invariant.scala | 34 +-- docs/src/main/tut/applicative.md | 4 +- docs/src/main/tut/apply.md | 8 +- docs/src/main/tut/foldable.md | 9 +- docs/src/main/tut/functor.md | 14 +- .../main/scala/cats/laws/BitraverseLaws.scala | 15 +- .../main/scala/cats/laws/TraverseLaws.scala | 11 +- .../cats/laws/discipline/Arbitrary.scala | 3 + .../test/scala/cats/tests/ComposeTests.scala | 65 ----- .../test/scala/cats/tests/FunctorTests.scala | 25 -- .../test/scala/cats/tests/ListWrapper.scala | 2 + .../test/scala/cats/tests/NestedTests.scala | 82 ++++++ .../scala/cats/tests/ReducibleTests.scala | 18 -- .../test/scala/cats/tests/WordCountTest.scala | 2 +- 18 files changed, 391 insertions(+), 407 deletions(-) delete mode 100644 core/src/main/scala/cats/data/Compose.scala create mode 100644 core/src/main/scala/cats/data/Nested.scala delete mode 100644 tests/src/test/scala/cats/tests/ComposeTests.scala create mode 100644 tests/src/test/scala/cats/tests/NestedTests.scala delete mode 100644 tests/src/test/scala/cats/tests/ReducibleTests.scala diff --git a/core/src/main/scala/cats/data/Compose.scala b/core/src/main/scala/cats/data/Compose.scala deleted file mode 100644 index 8ff58fc8ff..0000000000 --- a/core/src/main/scala/cats/data/Compose.scala +++ /dev/null @@ -1,201 +0,0 @@ -package cats -package data - -import cats.functor._ - -final case class Compose[F[_], G[_], A](value: F[G[A]]) - -object Compose extends ComposeInstances - -private[data] sealed abstract class ComposeInstances extends ComposeInstances1 { - implicit def composeTraverse[F[_]: Traverse, G[_]: Traverse]: Traverse[Compose[F, G, ?]] = - new ComposeTraverse[F, G] { - val F = Traverse[F] - val G = Traverse[G] - } -} - -private[data] sealed abstract class ComposeInstances1 extends ComposeInstances2 { - /** - * This composes two `Reducible` instances to provide an - * instance for the nested types. - * - * In other words, given a `Reducible[F]` instance (which can reduce - * `F[A]`) and a `Reducible[G]` instance (which can reduce `G[A]` - * values), this class is able to reduce `F[G[A]]` values. - */ - implicit def composeReducible[F[_]: Reducible, G[_]: Reducible]: Reducible[Compose[F, G, ?]] = - new ComposeReducible[F, G] { - val F = Reducible[F] - val G = Reducible[G] - } -} - -private[data] sealed abstract class ComposeInstances2 extends ComposeInstances3 { - implicit def composeFoldable[F[_]: Foldable, G[_]: Foldable]: Foldable[Compose[F, G, ?]] = - new ComposeFoldable[F, G] { - val F = Foldable[F] - val G = Foldable[G] - } -} - -private[data] sealed abstract class ComposeInstances3 extends ComposeInstances4 { - implicit def composeAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Compose[F, G, ?]] = - new CompositeAlternative[F, G] { - val F = Alternative[F] - val G = Applicative[G] - } -} - -private[data] sealed abstract class ComposeInstances4 extends ComposeInstances5 { - /** - * Two sequentially dependent Applicatives can be composed. - * - * The composition of Applicatives `F` and `G`, `F[G[x]]`, is also an Applicative - * - * Applicative[Option].compose[List].pure(10) = Some(List(10)) - */ - implicit def composeApplicative[F[_]: Applicative, G[_]: Applicative]: Applicative[Compose[F, G, ?]] = - new ComposeApplicative[F, G] { - val F = Applicative[F] - val G = Applicative[G] - } - - implicit def composeMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Compose[F, G, ?]] = - new ComposeMonoidK[F, G] { - val F = MonoidK[F] - } -} - -private[data] sealed abstract class ComposeInstances5 extends ComposeInstances6 { - /** - * Two sequentially dependent Applys can be composed. - * - * The composition of Applys `F` and `G`, `F[G[x]]`, is also an Apply. - * - * Example: - * {{{ - * scala> import cats.Apply - * scala> import cats.implicits._ - * scala> val ap = Apply[Option].compose[List] - * scala> val x: Option[List[Int]] = Some(List(1, 2)) - * scala> val y: Option[List[Int]] = Some(List(10, 20)) - * scala> ap.map2(x, y)(_ + _) - * res0: Option[List[Int]] = Some(List(11, 21, 12, 22)) - * }}} - */ - implicit def composeApply[F[_]: Apply, G[_]: Apply]: Apply[Compose[F, G, ?]] = - new ComposeApply[F, G] { - val F = Apply[F] - val G = Apply[G] - } - - implicit def composeSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Compose[F, G, ?]] = - new ComposeSemigroupK[F, G] { - val F = SemigroupK[F] - } -} - -private[data] sealed abstract class ComposeInstances6 extends ComposeInstances7 { - implicit def composeFunctor[F[_]: Functor, G[_]: Functor]: Functor[Compose[F, G, ?]] = - new ComposeFunctor[F, G] { - val F = Functor[F] - val G = Functor[G] - } -} - -private[data] sealed abstract class ComposeInstances7 { - implicit def composeInvariant[F[_]: Invariant, G[_]: Invariant]: Invariant[Compose[F, G, ?]] = - new ComposeInvariant[F, G] { - val F = Invariant[F] - val G = Invariant[G] - } -} - -private[data] trait ComposeInvariant[F[_], G[_]] extends Invariant[Compose[F, G, ?]] { - def F: Invariant[F] - def G: Invariant[G] - - override def imap[A, B](fga: Compose[F, G, A])(f: A => B)(g: B => A): Compose[F, G, B] = - Compose(F.imap(fga.value)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f))) -} - -private[data] trait ComposeFunctor[F[_], G[_]] extends Functor[Compose[F, G, ?]] with ComposeInvariant[F, G] { - def F: Functor[F] - def G: Functor[G] - - override def map[A, B](fga: Compose[F, G, A])(f: A => B): Compose[F, G, B] = - Compose(F.map(fga.value)(ga => G.map(ga)(f))) -} - -private[data] trait ComposeApply[F[_], G[_]] extends Apply[Compose[F, G, ?]] with ComposeFunctor[F, G] { - def F: Apply[F] - def G: Apply[G] - - override def ap[A, B](ff: Compose[F, G, A => B])(fa: Compose[F, G, A]): Compose[F, G, B] = - Compose(F.ap(F.map(ff.value)(gab => G.ap(gab)(_)))(fa.value)) - - override def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] = - F.map2(fa, fb)(G.product) -} - -private[data] trait ComposeApplicative[F[_], G[_]] extends Applicative[Compose[F, G, ?]] with ComposeApply[F, G] { - def F: Applicative[F] - def G: Applicative[G] - - override def pure[A](x: A): Compose[F, G, A] = Compose(F.pure(G.pure(x))) -} - -private[data] trait ComposeSemigroupK[F[_], G[_]] extends SemigroupK[Compose[F, G, ?]] { - def F: SemigroupK[F] - - def combineK[A](x: Compose[F, G, A], y: Compose[F, G, A]): Compose[F, G, A] = Compose(F.combineK(x.value, y.value)) -} - -private[data] trait ComposeMonoidK[F[_], G[_]] extends MonoidK[Compose[F, G, ?]] with ComposeSemigroupK[F, G] { - def F: MonoidK[F] - - def empty[A]: Compose[F, G, A] = Compose(F.empty) -} - -private[data] trait CompositeAlternative[F[_], G[_]] extends Alternative[Compose[F, G, ?]] with ComposeApplicative[F, G] with ComposeMonoidK[F, G] { - def F: Alternative[F] -} - -private[data] trait ComposeFoldable[F[_], G[_]] extends Foldable[Compose[F, G, ?]] { - def F: Foldable[F] - def G: Foldable[G] - - def foldLeft[A, B](fga: Compose[F, G, A], b: B)(f: (B, A) => B): B = - F.foldLeft(fga.value, b)((b, a) => G.foldLeft(a, b)(f)) - - def foldRight[A, B](fga: Compose[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - F.foldRight(fga.value, lb)((ga, lb) => G.foldRight(ga, lb)(f)) -} - -private[data] trait ComposeTraverse[F[_], G[_]] extends Traverse[Compose[F, G, ?]] with ComposeFoldable[F, G] with ComposeFunctor[F, G] { - def F: Traverse[F] - def G: Traverse[G] - - def traverse[H[_]: Applicative, A, B](fga: Compose[F, G, A])(f: A => H[B]): H[Compose[F, G, B]] = - Applicative[H].map(F.traverse(fga.value)(ga => G.traverse(ga)(f)))(Compose(_)) -} - -private[data] trait ComposeReducible[F[_], G[_]] extends Reducible[Compose[F, G, ?]] with ComposeFoldable[F, G] { - def F: Reducible[F] - def G: Reducible[G] - - override def reduceLeftTo[A, B](fga: Compose[F, G, A])(f: A => B)(g: (B, A) => B): B = { - def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) - F.reduceLeftTo(fga.value)(toB) { (b, ga) => - G.foldLeft(ga, b)(g) - } - } - - override def reduceRightTo[A, B](fga: Compose[F, G, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { - def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value - F.reduceRightTo(fga.value)(toB) { (ga, lb) => - G.foldRight(ga, lb)(g) - } - } -} diff --git a/core/src/main/scala/cats/data/Func.scala b/core/src/main/scala/cats/data/Func.scala index e6a993c52a..7571b1acd9 100644 --- a/core/src/main/scala/cats/data/Func.scala +++ b/core/src/main/scala/cats/data/Func.scala @@ -87,14 +87,14 @@ sealed abstract class AppFunc[F[_], A, B] extends Func[F, A, B] { self => } } - def compose[G[_], C](g: AppFunc[G, C, A]): AppFunc[Compose[G, F, ?], C, B] = { - implicit val gfApplicative: Applicative[Compose[G, F, ?]] = Compose.composeApplicative[G, F](g.F, F) - Func.appFunc[Compose[G, F, ?], C, B]({ - c: C => Compose(g.F.map(g.run(c))(self.run)) + def compose[G[_], C](g: AppFunc[G, C, A]): AppFunc[Nested[G, F, ?], C, B] = { + implicit val gfApplicative: Applicative[Nested[G, F, ?]] = Nested.nestedApplicative[G, F](g.F, F) + Func.appFunc[Nested[G, F, ?], C, B]({ + c: C => Nested(g.F.map(g.run(c))(self.run)) }) } - def andThen[G[_], C](g: AppFunc[G, B, C]): AppFunc[Compose[F, G, ?], A, C] = + def andThen[G[_], C](g: AppFunc[G, B, C]): AppFunc[Nested[F, G, ?], A, C] = g.compose(self) def map[C](f: B => C): AppFunc[F, A, C] = diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala new file mode 100644 index 0000000000..1cd3a30421 --- /dev/null +++ b/core/src/main/scala/cats/data/Nested.scala @@ -0,0 +1,265 @@ +package cats +package data + +import cats.functor._ + +/** Similar to [[cats.data.Prod]], but for nested composition. + * + * For instance, since both `List` and `Option` have a `Functor`, then so does + * `List[Option[_]]`. This is represented by this data type via the instantiation + * `Nested[List, Option, ?]`. + * + * {{{ + * scala> import cats.Functor + * scala> import cats.data.Nested + * scala> import cats.implicits._ + * scala> val listOption: List[Option[Int]] = List(Some(1), None) + * scala> val f: Int => String = i => (i * 2).toString + * scala> Functor[List].map(listOption)(opt => opt.map(f)) + * res0: List[Option[String]] = List(Some(2), None) + * scala> val nested: Nested[List, Option, Int] = Nested(listOption) + * scala> val result: Nested[List, Option, String] = Functor[Nested[List, Option, ?]].map(nested)(f) + * scala> result.value + * res1: List[Option[String]] = List(Some(2), None) + * }}} + */ +final case class Nested[F[_], G[_], A](value: F[G[A]]) + +object Nested extends NestedInstances + +private[data] sealed abstract class NestedInstances extends NestedInstances1 { + implicit def nestedEq[F[_], G[_], A](implicit FGA: Eq[F[G[A]]]): Eq[Nested[F, G, A]] = + FGA.on(_.value) + + implicit def nestedTraverse[F[_]: Traverse, G[_]: Traverse]: Traverse[Nested[F, G, ?]] = + new NestedTraverse[F, G] { + val F = Traverse[F] + val G = Traverse[G] + } +} + +private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { + implicit def nestedReducible[F[_]: Reducible, G[_]: Reducible]: Reducible[Nested[F, G, ?]] = + new NestedReducible[F, G] { + val F = Reducible[F] + val G = Reducible[G] + } + + implicit def nestedContravariant[F[_]: Contravariant, G[_]: Contravariant]: Functor[Nested[F, G, ?]] = + new NestedContravariant[F, G] { + val F = Contravariant[F] + val G = Contravariant[G] + } +} + +private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { + implicit def nestedFoldable[F[_]: Foldable, G[_]: Foldable]: Foldable[Nested[F, G, ?]] = + new NestedFoldable[F, G] { + val F = Foldable[F] + val G = Foldable[G] + } + + implicit def nestedContravariantCovariant[F[_]: Contravariant, G[_]: Functor]: Contravariant[Nested[F, G, ?]] = + new NestedContravariantCovariant[F, G] { + val F = Contravariant[F] + val G = Functor[G] + } +} + +private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { + implicit def nestedAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Nested[F, G, ?]] = + new CompositeAlternative[F, G] { + val F = Alternative[F] + val G = Applicative[G] + } + + implicit def nestedCovariantContravariant[F[_]: Functor, G[_]: Contravariant]: Contravariant[Nested[F, G, ?]] = + new NestedCovariantContravariant[F, G] { + val F = Functor[F] + val G = Contravariant[G] + } +} + +private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { + implicit def nestedApplicative[F[_]: Applicative, G[_]: Applicative]: Applicative[Nested[F, G, ?]] = + new NestedApplicative[F, G] { + val F = Applicative[F] + val G = Applicative[G] + } + + implicit def nestedMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Nested[F, G, ?]] = + new NestedMonoidK[F, G] { + val F = MonoidK[F] + } +} + +private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { + implicit def nestedApply[F[_]: Apply, G[_]: Apply]: Apply[Nested[F, G, ?]] = + new NestedApply[F, G] { + val F = Apply[F] + val G = Apply[G] + } + + implicit def nestedSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]] = + new NestedSemigroupK[F, G] { + val F = SemigroupK[F] + } +} + +private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { + implicit def nestedFunctor[F[_]: Functor, G[_]: Functor]: Functor[Nested[F, G, ?]] = + new NestedFunctor[F, G] { + val F = Functor[F] + val G = Functor[G] + } +} + +private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { + implicit def nestedInvariant[F[_]: Invariant, G[_]: Invariant]: Invariant[Nested[F, G, ?]] = + new NestedInvariant[F, G] { + val F = Invariant[F] + val G = Invariant[G] + } +} + +private[data] sealed abstract class NestedInstances8 { + implicit def nestedInvariantCovariant[F[_]: Invariant, G[_]: Functor]: Invariant[Nested[F, G, ?]] = + new NestedInvariantCovariant[F, G] { + val F = Invariant[F] + val G = Functor[G] + } + + implicit def nestedInvariantContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] = + new NestedInvariantContravariant[F, G] { + val F = Invariant[F] + val G = Contravariant[G] + } +} + +private[data] trait NestedInvariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { + def F: Invariant[F] + def G: Invariant[G] + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(F.imap(fga.value)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f))) +} + +private[data] trait NestedFunctor[F[_], G[_]] extends Functor[Nested[F, G, ?]] with NestedInvariant[F, G] { + def F: Functor[F] + def G: Functor[G] + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(F.map(fga.value)(ga => G.map(ga)(f))) +} + +private[data] trait NestedApply[F[_], G[_]] extends Apply[Nested[F, G, ?]] with NestedFunctor[F, G] { + def F: Apply[F] + def G: Apply[G] + + override def ap[A, B](ff: Nested[F, G, A => B])(fa: Nested[F, G, A]): Nested[F, G, B] = + Nested(F.ap(F.map(ff.value)(gab => G.ap(gab)(_)))(fa.value)) + + override def product[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, (A, B)] = + Nested(F.map2(fa.value, fb.value)(G.product)) +} + +private[data] trait NestedApplicative[F[_], G[_]] extends Applicative[Nested[F, G, ?]] with NestedApply[F, G] { + def F: Applicative[F] + def G: Applicative[G] + + override def pure[A](x: A): Nested[F, G, A] = Nested(F.pure(G.pure(x))) +} + +private[data] trait NestedSemigroupK[F[_], G[_]] extends SemigroupK[Nested[F, G, ?]] { + def F: SemigroupK[F] + + override def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(F.combineK(x.value, y.value)) +} + +private[data] trait NestedMonoidK[F[_], G[_]] extends MonoidK[Nested[F, G, ?]] with NestedSemigroupK[F, G] { + def F: MonoidK[F] + + override def empty[A]: Nested[F, G, A] = Nested(F.empty) +} + +private[data] trait CompositeAlternative[F[_], G[_]] extends Alternative[Nested[F, G, ?]] with NestedApplicative[F, G] with NestedMonoidK[F, G] { + def F: Alternative[F] +} + +private[data] trait NestedFoldable[F[_], G[_]] extends Foldable[Nested[F, G, ?]] { + def F: Foldable[F] + def G: Foldable[G] + + override def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + F.foldLeft(fga.value, b)((b, a) => G.foldLeft(a, b)(f)) + + override def foldRight[A, B](fga: Nested[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fga.value, lb)((ga, lb) => G.foldRight(ga, lb)(f)) +} + +private[data] trait NestedTraverse[F[_], G[_]] extends Traverse[Nested[F, G, ?]] with NestedFoldable[F, G] with NestedFunctor[F, G] { + def F: Traverse[F] + def G: Traverse[G] + + override def traverse[H[_]: Applicative, A, B](fga: Nested[F, G, A])(f: A => H[B]): H[Nested[F, G, B]] = + Applicative[H].map(F.traverse(fga.value)(ga => G.traverse(ga)(f)))(Nested(_)) +} + +private[data] trait NestedReducible[F[_], G[_]] extends Reducible[Nested[F, G, ?]] with NestedFoldable[F, G] { + def F: Reducible[F] + def G: Reducible[G] + + override def reduceLeftTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (B, A) => B): B = { + def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) + F.reduceLeftTo(fga.value)(toB) { (b, ga) => + G.foldLeft(ga, b)(g) + } + } + + override def reduceRightTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { + def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value + F.reduceRightTo(fga.value)(toB) { (ga, lb) => + G.foldRight(ga, lb)(g) + } + } +} + +private[data] trait NestedContravariant[F[_], G[_]] extends Functor[Nested[F, G, ?]] { + def F: Contravariant[F] + def G: Contravariant[G] + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(F.contramap(fga.value)(gb => G.contramap(gb)(f))) +} + +private[data] trait NestedContravariantCovariant[F[_], G[_]] extends Contravariant[Nested[F, G, ?]] { + def F: Contravariant[F] + def G: Functor[G] + + override def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(F.contramap(fga.value)(gb => G.map(gb)(f))) +} + +private[data] trait NestedCovariantContravariant[F[_], G[_]] extends Contravariant[Nested[F, G, ?]] { + def F: Functor[F] + def G: Contravariant[G] + + override def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(F.map(fga.value)(ga => G.contramap(ga)(f))) +} + +private[data] trait NestedInvariantCovariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { + def F: Invariant[F] + def G: Functor[G] + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(F.imap(fga.value)(ga => G.map(ga)(f))(gb => G.map(gb)(g))) +} + +private[data] trait NestedInvariantContravariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { + def F: Invariant[F] + def G: Contravariant[G] + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(F.imap(fga.value)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f))) +} diff --git a/core/src/main/scala/cats/functor/Contravariant.scala b/core/src/main/scala/cats/functor/Contravariant.scala index b8bec7ee01..28b249dc7e 100644 --- a/core/src/main/scala/cats/functor/Contravariant.scala +++ b/core/src/main/scala/cats/functor/Contravariant.scala @@ -9,34 +9,4 @@ import simulacrum.typeclass @typeclass trait Contravariant[F[_]] extends Invariant[F] { self => def contramap[A, B](fa: F[A])(f: B => A): F[B] override def imap[A, B](fa: F[A])(f: A => B)(fi: B => A): F[B] = contramap(fa)(fi) - - def compose[G[_]](implicit G: Contravariant[G]): Functor[Lambda[X => F[G[X]]]] = { - val G0 = G - new Contravariant.Composite[F, G] { - def F: Contravariant[F] = self - def G: Contravariant[G] = G0 - } - } - - override def composeWithFunctor[G[_]](implicit G: Functor[G]): Contravariant[Lambda[X => F[G[X]]]] = { - val G0 = G - new Contravariant.CovariantComposite[F, G] { - def F: Contravariant[F] = self - def G: Functor[G] = G0 - } - } -} - -object Contravariant { - trait Composite[F[_], G[_]] extends Functor[Lambda[X => F[G[X]]]] { - def F: Contravariant[F] - def G: Contravariant[G] - def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = F.contramap(fga)(gb => G.contramap(gb)(f)) - } - - trait CovariantComposite[F[_], G[_]] extends Contravariant[Lambda[X => F[G[X]]]] { - def F: Contravariant[F] - def G: Functor[G] - def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = F.contramap(fga)(gb => G.map(gb)(f)) - } } diff --git a/core/src/main/scala/cats/functor/Invariant.scala b/core/src/main/scala/cats/functor/Invariant.scala index a8d969d8a5..2851958418 100644 --- a/core/src/main/scala/cats/functor/Invariant.scala +++ b/core/src/main/scala/cats/functor/Invariant.scala @@ -8,41 +8,9 @@ import simulacrum.typeclass */ @typeclass trait Invariant[F[_]] { self => def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] - - /** - * Compose the Invariant Functor F with a normal (Covariant) Functor to get a new Invariant Functor for [F[G[_]]. - */ - def composeWithFunctor[G[_]](implicit GG: Functor[G]): Invariant[Lambda[X => F[G[X]]]] = new Invariant.CovariantComposite[F, G] { - def F: Invariant[F] = self - def G: Functor[G] = GG - } - - /** - * Compose the Invariant Functor F with a Contravariant Functor to get a new Invariant Functor for [F[G[_]]]. - */ - def composeWithContravariant[G[_]](implicit GG: Contravariant[G]): Invariant[Lambda[X => F[G[X]]]] = new Invariant.ContravariantComposite[F, G] { - def F: Invariant[F] = self - def G: Contravariant[G] = GG - } } -object Invariant extends AlgebraInvariantInstances { - trait CovariantComposite[F[_], G[_]] extends Invariant[Lambda[X => F[G[X]]]] { - def F: Invariant[F] - def G: Functor[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.map(ga)(f))(gb => G.map(gb)(g)) - } - - trait ContravariantComposite[F[_], G[_]] extends Invariant[Lambda[X => F[G[X]]]] { - def F: Invariant[F] - def G: Contravariant[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f)) - } -} +object Invariant extends AlgebraInvariantInstances /** * Invariant instances for types that are housed in Algebra and therefore diff --git a/docs/src/main/tut/applicative.md b/docs/src/main/tut/applicative.md index 833c7acc89..8baf35be45 100644 --- a/docs/src/main/tut/applicative.md +++ b/docs/src/main/tut/applicative.md @@ -35,7 +35,9 @@ operation will lift the passed value into one context, and the result into the other context: ```tut -(Applicative[List] compose Applicative[Option]).pure(1) +import cats.data.Nested +val nested = Applicative[Nested[List, Option, ?]].pure(1) +val unwrapped = nested.value ``` ## Applicative Functors & Monads diff --git a/docs/src/main/tut/apply.md b/docs/src/main/tut/apply.md index 9a69e14a66..cc816fb7f5 100644 --- a/docs/src/main/tut/apply.md +++ b/docs/src/main/tut/apply.md @@ -48,12 +48,14 @@ Apply[Option].map(None)(double) ### compose -And like functors, `Apply` instances also compose: +And like functors, `Apply` instances also compose (via the `Nested` data type): ```tut -val listOpt = Apply[List] compose Apply[Option] +import cats.data.Nested +val listOpt = Nested[List, Option, Int](List(Some(1), None, Some(3))) val plusOne = (x:Int) => x + 1 -listOpt.ap(List(Some(plusOne)))(List(Some(1), None, Some(3))) +val f = Nested[List, Option, Int => Int](List(Some(plusOne))) +Apply[Nested[List, Option, ?]].ap(f)(listOpt) ``` ### ap diff --git a/docs/src/main/tut/foldable.md b/docs/src/main/tut/foldable.md index 81e4ea09fa..08062ff566 100644 --- a/docs/src/main/tut/foldable.md +++ b/docs/src/main/tut/foldable.md @@ -64,10 +64,11 @@ prints.value Foldable[List].dropWhile_(List[Int](2,4,5,6,7))(_ % 2 == 0) Foldable[List].dropWhile_(List[Int](1,2,4,5,6,7))(_ % 2 == 0) -val FoldableListOption = Foldable[List].compose[Option] -FoldableListOption.fold(List(Option(1), Option(2), Option(3), Option(4))) -FoldableListOption.fold(List(Option(1), Option(2), Option(3), None)) -FoldableListOption.fold(List(Option("1"), Option("2"), Option("3"), None)) +import cats.data.Nested +val listOption0 = Nested(List(Option(1), Option(2), Option(3))) +val listOption1 = Nested(List(Option(1), Option(2), None)) +Foldable[Nested[List, Option, ?]].fold(listOption0) +Foldable[Nested[List, Option, ?]].fold(listOption1) ``` Hence when defining some new data structure, if we can define a `foldLeft` and diff --git a/docs/src/main/tut/functor.md b/docs/src/main/tut/functor.md index 1d31cd809e..4e6d52b907 100644 --- a/docs/src/main/tut/functor.md +++ b/docs/src/main/tut/functor.md @@ -109,13 +109,13 @@ Functor[List].fproduct(source)(len).toMap ### compose Functors compose! Given any functor `F[_]` and any functor `G[_]` we can -create a new functor `F[G[_]]` by composing them: +create a new functor `F[G[_]]` by composing them via the `Nested` data type: ```tut -val listOpt = Functor[List] compose Functor[Option] -listOpt.map(List(Some(1), None, Some(3)))(_ + 1) -val optList = Functor[Option] compose Functor[List] -optList.map(Some(List(1, 2, 3)))(_ + 1) -val listOptList = listOpt compose Functor[List] -listOptList.map(List(Some(List(1,2)), None, Some(List(3,4))))(_ + 1) +import cats.data.Nested +val listOpt = Nested[List, Option, Int](List(Some(1), None, Some(3))) +Functor[Nested[List, Option, ?]].map(listOpt)(_ + 1) + +val optList = Nested[Option, List, Int](Some(List(1, 2, 3))) +Functor[Nested[Option, List, ?]].map(optList)(_ + 1) ``` diff --git a/laws/src/main/scala/cats/laws/BitraverseLaws.scala b/laws/src/main/scala/cats/laws/BitraverseLaws.scala index b76573ccc3..d22172d4f3 100644 --- a/laws/src/main/scala/cats/laws/BitraverseLaws.scala +++ b/laws/src/main/scala/cats/laws/BitraverseLaws.scala @@ -1,6 +1,8 @@ package cats package laws +import cats.data.Nested + trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] { implicit override def F: Bitraverse[F] @@ -19,16 +21,13 @@ trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] { val fg = F.bitraverse(fab)(f, g) val hi = G.map(fg)(f => F.bitraverse(f)(h, i)) - type GCompose[X] = G[G[X]] - val GCompose = G.compose[G] - val c = - F.bitraverse[GCompose, A, B, E, H](fab)( - a => G.map(f(a))(h), - b => G.map(g(b))(i) - )(GCompose) + F.bitraverse[Nested[G, G, ?], A, B, E, H](fab)( + a => Nested(G.map(f(a))(h)), + b => Nested(G.map(g(b))(i)) + ) - hi <-> c + hi <-> c.value } } diff --git a/laws/src/main/scala/cats/laws/TraverseLaws.scala b/laws/src/main/scala/cats/laws/TraverseLaws.scala index 5ae13c2c21..add5bb70b1 100644 --- a/laws/src/main/scala/cats/laws/TraverseLaws.scala +++ b/laws/src/main/scala/cats/laws/TraverseLaws.scala @@ -2,7 +2,7 @@ package cats package laws import cats.Id -import cats.data.Const +import cats.data.{Const, Nested} import cats.syntax.traverse._ import cats.syntax.foldable._ @@ -20,11 +20,10 @@ trait TraverseLaws[F[_]] extends FunctorLaws[F] with FoldableLaws[F] { )(implicit N: Applicative[N], M: Applicative[M] - ): IsEq[M[N[F[C]]]] = { - implicit val MN = M.compose(N) - type MN[Z] = M[N[Z]] - val lhs: MN[F[C]] = M.map(fa.traverse(f))(fb => fb.traverse(g)) - val rhs: MN[F[C]] = fa.traverse[MN, C](a => M.map(f(a))(g)) + ): IsEq[Nested[M, N, F[C]]] = { + + val lhs = Nested(M.map(fa.traverse(f))(fb => fb.traverse(g))) + val rhs = fa.traverse[Nested[M, N, ?], C](a => Nested(M.map(f(a))(g))) lhs <-> rhs } diff --git a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala index d22eabb378..2299bf29f7 100644 --- a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala +++ b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala @@ -76,6 +76,9 @@ object arbitrary extends ArbitraryInstances0 { implicit def function0Arbitrary[A: Arbitrary]: Arbitrary[() => A] = Arbitrary(getArbitrary[A].map(() => _)) + + implicit def nestedArbitrary[F[_], G[_], A](implicit FG: Arbitrary[F[G[A]]]): Arbitrary[Nested[F, G, A]] = + Arbitrary(FG.arbitrary.map(Nested(_))) } private[discipline] sealed trait ArbitraryInstances0 { diff --git a/tests/src/test/scala/cats/tests/ComposeTests.scala b/tests/src/test/scala/cats/tests/ComposeTests.scala deleted file mode 100644 index 2cccfa1eff..0000000000 --- a/tests/src/test/scala/cats/tests/ComposeTests.scala +++ /dev/null @@ -1,65 +0,0 @@ -package cats -package tests - -import cats.data.{ NonEmptyList, NonEmptyVector } -import cats.laws.discipline.{ AlternativeTests, ApplicativeTests, FoldableTests, CartesianTests, MonoidKTests, SemigroupKTests, arbitrary }, arbitrary._ - -class ComposeTests extends CatsSuite { - // we have a lot of generated lists of lists in these tests. We have to tell - // Scalacheck to calm down a bit so we don't hit memory and test duration - // issues. - 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 = CartesianTests.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 - - implicit val applicativeListVector: Applicative[Lambda[A => List[Vector[A]]]] = Applicative[List] compose Applicative[Vector] - implicit val iso = CartesianTests.Isomorphisms.invariant[Lambda[A => List[Vector[A]]]] - - checkAll("Applicative[Lambda[A => List[Vector[A]]]]", ApplicativeTests[Lambda[A => List[Vector[A]]]].applicative[Int, Int, Int]) - } - - { - // Foldable composition - - implicit val foldableListVector: Foldable[Lambda[A => List[Vector[A]]]] = Foldable[List] compose Foldable[Vector] - - 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].composeK[Vector] - - checkAll("MonoidK[Lambda[A => List[Vector[A]]]]", MonoidKTests[Lambda[A => List[Vector[A]]]].monoidK[Int]) - } - - { - // Reducible composition - - 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]) - } - - { - // SemigroupK composition - - 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]) - } -} diff --git a/tests/src/test/scala/cats/tests/FunctorTests.scala b/tests/src/test/scala/cats/tests/FunctorTests.scala index d934e0a39c..9af4db22ae 100644 --- a/tests/src/test/scala/cats/tests/FunctorTests.scala +++ b/tests/src/test/scala/cats/tests/FunctorTests.scala @@ -1,32 +1,7 @@ package cats package tests -import cats.data.Xor -import cats.functor.Contravariant -import cats.laws.discipline.{ContravariantTests, FunctorTests, SerializableTests} -import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.eq._ -import cats.laws.discipline.eq.showEq - class FunctorTest extends CatsSuite { - type OptionXor[A] = Option[Xor[String, A]] - - val optionXorFunctor: Functor[OptionXor] = - Functor[Option].compose[Xor[String, ?]] - checkAll("Option compose Xor", FunctorTests(optionXorFunctor).functor[Int, Int, Int]) - checkAll("Functor[Option compose Xor]", SerializableTests.serializable(optionXorFunctor)) - - val optionComposeWithFunctorXor: Functor[OptionXor] = - Functor[Option].composeWithFunctor[Xor[String, ?]] - checkAll("Option composeWithFunctor Xor", FunctorTests(optionComposeWithFunctorXor).functor[Int, Int, Int]) - checkAll("Functor[Option composeWithFunctor Xor]", SerializableTests.serializable(optionComposeWithFunctorXor)) - - type OptionShow[A] = Option[Show[A]] - val optionShowContravariant: Contravariant[OptionShow] = - Functor[Option].composeWithContravariant[Show] - checkAll("Option composeWithContravariant Show", ContravariantTests(optionShowContravariant).contravariant[Int, Int, Int]) - checkAll("Contravariant[Option composeWithContravariant Show]", SerializableTests.serializable(optionShowContravariant)) - test("void replaces values with unit preserving structure") { forAll { (l: List[Int], o: Option[Int], m: Map[String, Int]) => l.void should === (List.fill(l.length)(())) diff --git a/tests/src/test/scala/cats/tests/ListWrapper.scala b/tests/src/test/scala/cats/tests/ListWrapper.scala index 06d58e5d4b..8a6a8faf2d 100644 --- a/tests/src/test/scala/cats/tests/ListWrapper.scala +++ b/tests/src/test/scala/cats/tests/ListWrapper.scala @@ -84,6 +84,8 @@ object ListWrapper { val monad: Monad[ListWrapper] = monadCombine + val applicative: Applicative[ListWrapper] = monadCombine + /** apply is taken due to ListWrapper being a case class */ val applyInstance: Apply[ListWrapper] = monadCombine diff --git a/tests/src/test/scala/cats/tests/NestedTests.scala b/tests/src/test/scala/cats/tests/NestedTests.scala new file mode 100644 index 0000000000..6d3296f624 --- /dev/null +++ b/tests/src/test/scala/cats/tests/NestedTests.scala @@ -0,0 +1,82 @@ +package cats +package tests + +import cats.data._ +import cats.functor.Contravariant +import cats.laws.discipline._ +import cats.laws.discipline.CartesianTests.Isomorphisms._ +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq.showEq + +class NestedTests extends CatsSuite { + // we have a lot of generated lists of lists in these tests. We have to tell + // Scalacheck to calm down a bit so we don't hit memory and test duration + // issues. + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = + PropertyCheckConfig(maxSize = 5, minSuccessful = 20) + + implicit val iso = { + implicit val instance = ListWrapper.functor + invariant[Nested[List, ListWrapper, ?]] + } + + { + // Functor composition + implicit val instance = ListWrapper.functor + checkAll("Nested[Option, ListWrapper, ?]", FunctorTests[Nested[Option, ListWrapper, ?]].functor[Int, Int, Int]) + checkAll("Functor[Nested[Option, ListWrapper, ?]]", SerializableTests.serializable(Functor[Nested[Option, ListWrapper, ?]])) + } + + { + // Covariant + contravariant functor composition + checkAll("Nested[Option, Show, ?]", ContravariantTests[Nested[Option, Show, ?]].contravariant[Int, Int, Int]) + checkAll("Contravariant[Nested[Option, Show, ?]]", SerializableTests.serializable(Contravariant[Nested[Option, Show, ?]])) + } + + { + // Applicative composition + implicit val instance = ListWrapper.applicative + checkAll("Nested[List, ListWrapper, ?]", ApplicativeTests[Nested[List, ListWrapper, ?]].applicative[Int, Int, Int]) + checkAll("Applicative[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(Applicative[Nested[List, ListWrapper, ?]])) + } + + { + // Alternative composition + implicit val instance = ListWrapper.alternative + checkAll("Nested[List, ListWrapper, ?]", AlternativeTests[Nested[List, ListWrapper, ?]].alternative[Int, Int, Int]) + checkAll("Alternative[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(Alternative[Nested[List, ListWrapper, ?]])) + } + + { + // Foldable composition + implicit val instance = ListWrapper.foldable + checkAll("Nested[List, ListWrapper, ?]", FoldableTests[Nested[List, ListWrapper, ?]].foldable[Int, Int]) + checkAll("Foldable[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(Foldable[Nested[List, ListWrapper, ?]])) + } + + { + // SI-2712? It can resolve Reducible[NonEmptyList] and Reducible[NonEmptyVector] but not + // Reducible[Nested[NonEmptyList, NonEmptyVector, ?]] + // Similarly for Arbitrary. + implicit val reducible = Nested.nestedReducible[NonEmptyList, NonEmptyVector] + implicit val arbitrary0 = nestedArbitrary[NonEmptyList, NonEmptyVector, Int] + implicit val arbitrary1 = nestedArbitrary[NonEmptyList, NonEmptyVector, Option[Int]] + + checkAll("Nested[NonEmptyList, NonEmptyVector, ?]", ReducibleTests[Nested[NonEmptyList, NonEmptyVector, ?]].reducible[Option, Int, Int]) + checkAll("Reducible[Nested[NonEmptyList, NonEmptyVector, ?]]", SerializableTests.serializable(reducible)) + } + + { + // SemigroupK composition + implicit val instance = ListWrapper.semigroupK + checkAll("Nested[List, ListWrapper, ?]", SemigroupKTests[Nested[List, ListWrapper, ?]].semigroupK[Int]) + checkAll("SemigroupK[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(SemigroupK[Nested[List, ListWrapper, ?]])) + } + + { + // MonoidK composition + implicit val instance = ListWrapper.monoidK + checkAll("Nested[List, ListWrapper, ?]", MonoidKTests[Nested[List, ListWrapper, ?]].monoidK[Int]) + checkAll("MonoidK[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(MonoidK[Nested[List, ListWrapper, ?]])) + } +} diff --git a/tests/src/test/scala/cats/tests/ReducibleTests.scala b/tests/src/test/scala/cats/tests/ReducibleTests.scala deleted file mode 100644 index d834a99e02..0000000000 --- a/tests/src/test/scala/cats/tests/ReducibleTests.scala +++ /dev/null @@ -1,18 +0,0 @@ -package cats -package tests - -import cats.data.{NonEmptyList, NonEmptyVector} -import cats.laws.discipline.{ReducibleTests, SerializableTests} -import cats.laws.discipline.arbitrary.oneAndArbitrary - -class ReducibleTest extends CatsSuite { - // Lots of collections here.. telling ScalaCheck to calm down a bit - implicit override val generatorDrivenConfig: PropertyCheckConfiguration = - PropertyCheckConfig(maxSize = 5, minSuccessful = 20) - - type NEVL[A] = NonEmptyList[NonEmptyVector[A]] - val nevlReducible: Reducible[NEVL] = - Reducible[NonEmptyList].compose[NonEmptyVector] - checkAll("NonEmptyList compose NonEmptyVector", ReducibleTests(nevlReducible).reducible[Option, Int, String]) - checkAll("Reducible[NonEmptyList compose NonEmptyVector]", SerializableTests.serializable(nevlReducible)) -} diff --git a/tests/src/test/scala/cats/tests/WordCountTest.scala b/tests/src/test/scala/cats/tests/WordCountTest.scala index e1dfaeb154..131b70cadd 100644 --- a/tests/src/test/scala/cats/tests/WordCountTest.scala +++ b/tests/src/test/scala/cats/tests/WordCountTest.scala @@ -43,7 +43,7 @@ class WordCountTest extends CatsSuite { val wordCountState = allResults.first.first val lineCount = allResults.first.second val charCount = allResults.second - val wordCount = wordCountState.runA(false).value + val wordCount = wordCountState.value.runA(false).value charCount.getConst should === (96) lineCount.getConst should === (2) wordCount.getConst should === (17) From 7a73d19d58d472fa5fa72276fa2e2db4f8b5bd46 Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Sun, 15 May 2016 21:05:25 -0700 Subject: [PATCH 3/6] More Nested composition code coverage --- core/src/main/scala/cats/data/Nested.scala | 2 + .../test/scala/cats/tests/ListWrapper.scala | 3 ++ .../test/scala/cats/tests/NestedTests.scala | 48 +++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 1cd3a30421..3d97e2c8c8 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -128,7 +128,9 @@ private[data] sealed abstract class NestedInstances8 { val F = Invariant[F] val G = Functor[G] } +} +private[data] sealed abstract class NestedInstances9 { implicit def nestedInvariantContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] = new NestedInvariantContravariant[F, G] { val F = Invariant[F] diff --git a/tests/src/test/scala/cats/tests/ListWrapper.scala b/tests/src/test/scala/cats/tests/ListWrapper.scala index 8a6a8faf2d..1536f25603 100644 --- a/tests/src/test/scala/cats/tests/ListWrapper.scala +++ b/tests/src/test/scala/cats/tests/ListWrapper.scala @@ -1,6 +1,7 @@ package cats package tests +import cats.functor.Invariant import cats.std.list._ import org.scalacheck.Arbitrary @@ -58,6 +59,8 @@ object ListWrapper { ListWrapper(Functor[List].map(fa.list)(f)) } + val invariant: Invariant[ListWrapper] = functor + val semigroupK: SemigroupK[ListWrapper] = new SemigroupK[ListWrapper] { def combineK[A](x: ListWrapper[A], y: ListWrapper[A]): ListWrapper[A] = diff --git a/tests/src/test/scala/cats/tests/NestedTests.scala b/tests/src/test/scala/cats/tests/NestedTests.scala index 6d3296f624..12aca17254 100644 --- a/tests/src/test/scala/cats/tests/NestedTests.scala +++ b/tests/src/test/scala/cats/tests/NestedTests.scala @@ -2,7 +2,7 @@ package cats package tests import cats.data._ -import cats.functor.Contravariant +import cats.functor._ import cats.laws.discipline._ import cats.laws.discipline.CartesianTests.Isomorphisms._ import cats.laws.discipline.arbitrary._ @@ -20,6 +20,27 @@ class NestedTests extends CatsSuite { invariant[Nested[List, ListWrapper, ?]] } + { + // Invariant composition + implicit val instance = ListWrapper.invariant + checkAll("Nested[ListWrapper, ListWrapper]", InvariantTests[Nested[ListWrapper, ListWrapper, ?]].invariant[Int, Int, Int]) + checkAll("Invariant[Nested[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Invariant[Nested[ListWrapper, ListWrapper, ?]])) + } + + { + // Invariant + Covariant = Invariant + implicit val instance = ListWrapper.invariant + checkAll("Nested[ListWrapper, Option]", InvariantTests[Nested[ListWrapper, Option, ?]].invariant[Int, Int, Int]) + checkAll("Invariant[Nested[ListWrapper, Option, ?]]", SerializableTests.serializable(Invariant[Nested[ListWrapper, Option, ?]])) + } + + { + // Invariant + Contravariant = Invariant + implicit val instance = ListWrapper.invariant + checkAll("Nested[ListWrapper, Show]", InvariantTests[Nested[ListWrapper, Show, ?]].invariant[Int, Int, Int]) + checkAll("Invariant[Nested[ListWrapper, Show, ?]]", SerializableTests.serializable(Invariant[Nested[ListWrapper, Show, ?]])) + } + { // Functor composition implicit val instance = ListWrapper.functor @@ -33,6 +54,23 @@ class NestedTests extends CatsSuite { checkAll("Contravariant[Nested[Option, Show, ?]]", SerializableTests.serializable(Contravariant[Nested[Option, Show, ?]])) } + { + // Contravariant + Contravariant = Functor + type ConstInt[A] = Const[Int, A] + // SI-2712 + implicit val instance = Nested.nestedContravariant[ConstInt, Show] + implicit val arbitrary = nestedArbitrary[ConstInt, Show, Int] + implicit val eqv = Nested.nestedEq[ConstInt, Show, Int] + checkAll("Nested[Const[Int, ?], Show, ?]", FunctorTests[Nested[ConstInt, Show, ?]].functor[Int, Int, Int]) + checkAll("Functor[Nested[Const[Int, ?], Show, ?]]", SerializableTests.serializable(instance)) + } + + { + // Contravariant + Functor = Contravariant + checkAll("Nested[Show, Option, ?]", ContravariantTests[Nested[Show, Option, ?]].contravariant[Int, Int, Int]) + checkAll("Contravariant[Nested[Show, Option, ?]]", SerializableTests.serializable(Contravariant[Nested[Show, Option, ?]])) + } + { // Applicative composition implicit val instance = ListWrapper.applicative @@ -69,14 +107,14 @@ class NestedTests extends CatsSuite { { // SemigroupK composition implicit val instance = ListWrapper.semigroupK - checkAll("Nested[List, ListWrapper, ?]", SemigroupKTests[Nested[List, ListWrapper, ?]].semigroupK[Int]) - checkAll("SemigroupK[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(SemigroupK[Nested[List, ListWrapper, ?]])) + checkAll("Nested[ListWrapper, Option, ?]", SemigroupKTests[Nested[ListWrapper, Option, ?]].semigroupK[Int]) + checkAll("SemigroupK[Nested[ListWrapper, Option, ?]]", SerializableTests.serializable(SemigroupK[Nested[ListWrapper, Option, ?]])) } { // MonoidK composition implicit val instance = ListWrapper.monoidK - checkAll("Nested[List, ListWrapper, ?]", MonoidKTests[Nested[List, ListWrapper, ?]].monoidK[Int]) - checkAll("MonoidK[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(MonoidK[Nested[List, ListWrapper, ?]])) + checkAll("Nested[ListWrapper, Option, ?]", MonoidKTests[Nested[ListWrapper, Option, ?]].monoidK[Int]) + checkAll("MonoidK[Nested[ListWrapper, Option, ?]]", SerializableTests.serializable(MonoidK[Nested[ListWrapper, Option, ?]])) } } From 667f3b9337544bb948d1ecf948d373e8ab2482da Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Sun, 15 May 2016 22:09:52 -0700 Subject: [PATCH 4/6] Some more tests for Nested --- core/src/main/scala/cats/data/Nested.scala | 2 +- tests/src/test/scala/cats/tests/NestedTests.scala | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 3d97e2c8c8..3406d1dded 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -122,7 +122,7 @@ private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { } } -private[data] sealed abstract class NestedInstances8 { +private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { implicit def nestedInvariantCovariant[F[_]: Invariant, G[_]: Functor]: Invariant[Nested[F, G, ?]] = new NestedInvariantCovariant[F, G] { val F = Invariant[F] diff --git a/tests/src/test/scala/cats/tests/NestedTests.scala b/tests/src/test/scala/cats/tests/NestedTests.scala index 12aca17254..7625b70d86 100644 --- a/tests/src/test/scala/cats/tests/NestedTests.scala +++ b/tests/src/test/scala/cats/tests/NestedTests.scala @@ -29,16 +29,16 @@ class NestedTests extends CatsSuite { { // Invariant + Covariant = Invariant - implicit val instance = ListWrapper.invariant - checkAll("Nested[ListWrapper, Option]", InvariantTests[Nested[ListWrapper, Option, ?]].invariant[Int, Int, Int]) - checkAll("Invariant[Nested[ListWrapper, Option, ?]]", SerializableTests.serializable(Invariant[Nested[ListWrapper, Option, ?]])) + val instance = Nested.nestedInvariantCovariant(ListWrapper.invariant, ListWrapper.functor) + checkAll("Nested[ListWrapper, ListWrapper] - Invariant + Covariant", InvariantTests[Nested[ListWrapper, ListWrapper, ?]](instance).invariant[Int, Int, Int]) + checkAll("Invariant[Nested[ListWrapper, ListWrapper, ?]] - Invariant + Covariant", SerializableTests.serializable(instance)) } { // Invariant + Contravariant = Invariant - implicit val instance = ListWrapper.invariant - checkAll("Nested[ListWrapper, Show]", InvariantTests[Nested[ListWrapper, Show, ?]].invariant[Int, Int, Int]) - checkAll("Invariant[Nested[ListWrapper, Show, ?]]", SerializableTests.serializable(Invariant[Nested[ListWrapper, Show, ?]])) + val instance = Nested.nestedInvariantContravariant(ListWrapper.invariant, Contravariant[Show]) + checkAll("Nested[ListWrapper, Show]", InvariantTests[Nested[ListWrapper, Show, ?]](instance).invariant[Int, Int, Int]) + checkAll("Invariant[Nested[ListWrapper, Show, ?]]", SerializableTests.serializable(instance)) } { From e85a7524f3c011b9cc5ae6a1f4dce12f7781c2f6 Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Sat, 21 May 2016 14:56:52 -0700 Subject: [PATCH 5/6] Add nest methods to type classes Nested instances are no longer wrapped in Nested, but instances delegate to the unwrapped instances. --- core/src/main/scala/cats/Alternative.scala | 10 +- core/src/main/scala/cats/Applicative.scala | 9 +- core/src/main/scala/cats/Apply.scala | 8 + core/src/main/scala/cats/Foldable.scala | 7 + core/src/main/scala/cats/Functor.scala | 15 + core/src/main/scala/cats/MonoidK.scala | 7 + core/src/main/scala/cats/Reducible.scala | 8 + core/src/main/scala/cats/SemigroupK.scala | 7 + core/src/main/scala/cats/Traverse.scala | 7 + core/src/main/scala/cats/data/Nested.scala | 275 ++++++++++++------ .../scala/cats/functor/Contravariant.scala | 14 + .../main/scala/cats/functor/Invariant.scala | 20 ++ 12 files changed, 296 insertions(+), 91 deletions(-) diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 1f86cff46b..407530849b 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -1,5 +1,13 @@ package cats +import cats.data.NestedAlternative + import simulacrum.typeclass -@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] +@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => + override def nest[G[_]: Applicative]: Alternative[Lambda[A => F[G[A]]]] = + new NestedAlternative[F, G] { + val F = self + val G = Applicative[G] + } +} diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index 1c4e29f1d9..f65b9b133f 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -1,7 +1,8 @@ package cats -import simulacrum.typeclass +import cats.data.NestedApplicative import cats.std.list._ +import simulacrum.typeclass /** * Applicative functor. @@ -43,4 +44,10 @@ import cats.std.list._ def sequence[G[_], A](as: G[F[A]])(implicit G: Traverse[G]): F[G[A]] = G.sequence(as)(this) + + def nest[G[_]: Applicative]: Applicative[Lambda[A => F[G[A]]]] = + new NestedApplicative[F, G] { + val F = self + val G = Applicative[G] + } } diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index e142433fb7..4444aacf4a 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -1,5 +1,7 @@ package cats +import cats.data.NestedApply + import simulacrum.typeclass /** @@ -57,4 +59,10 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[ */ def map2Eval[A, B, Z](fa: F[A], fb: Eval[F[B]])(f: (A, B) => Z): Eval[F[Z]] = fb.map(fb => map2(fa, fb)(f)) + + def nest[G[_]: Apply]: Apply[Lambda[A => F[G[A]]]] = + new NestedApply[F, G] { + val F = self + val G = Apply[G] + } } diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index fad4fb6b7a..4ad4a12eca 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -1,5 +1,6 @@ package cats +import cats.data.NestedFoldable import scala.collection.mutable import simulacrum.typeclass @@ -268,6 +269,12 @@ import simulacrum.typeclass def nonEmpty[A](fa: F[A]): Boolean = !isEmpty(fa) + + def nest[G[_]: Foldable]: Foldable[Lambda[A => F[G[A]]]] = + new NestedFoldable[F, G] { + val F = self + val G = Foldable[G] + } } object Foldable { diff --git a/core/src/main/scala/cats/Functor.scala b/core/src/main/scala/cats/Functor.scala index c8f1596409..aa8e8f170d 100644 --- a/core/src/main/scala/cats/Functor.scala +++ b/core/src/main/scala/cats/Functor.scala @@ -1,5 +1,8 @@ package cats +import cats.data.{NestedCovariantContravariant, NestedFunctor} +import cats.functor.Contravariant + import simulacrum.typeclass /** @@ -36,4 +39,16 @@ import simulacrum.typeclass * Replaces the `A` value in `F[A]` with the supplied value. */ def as[A, B](fa: F[A], b: B): F[B] = map(fa)(_ => b) + + def nest[G[_]: Functor]: Functor[Lambda[A => F[G[A]]]] = + new NestedFunctor[F, G] { + val F = self + val G = Functor[G] + } + + override def nestContravariant[G[_]: Contravariant]: Contravariant[Lambda[A => F[G[A]]]] = + new NestedCovariantContravariant[F, G] { + val F = self + val G = Contravariant[G] + } } diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index e55077151d..c1e5c77a70 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -1,5 +1,7 @@ package cats +import cats.data.NestedMonoidK + import simulacrum.typeclass /** @@ -37,4 +39,9 @@ import simulacrum.typeclass def empty: F[A] = self.empty def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } + + override def nest[G[_]]: MonoidK[Lambda[A => F[G[A]]]] = + new NestedMonoidK[F, G] { + val F = self + } } diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index fd72a8376a..b26b88d3ff 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -1,5 +1,7 @@ package cats +import cats.data.NestedReducible + import simulacrum.typeclass /** @@ -106,6 +108,12 @@ import simulacrum.typeclass */ def sequence1_[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = G.map(reduceLeft(fga)((x, y) => G.map2(x, y)((_, b) => b)))(_ => ()) + + def nest[G[_]: Reducible]: Reducible[Lambda[A => F[G[A]]]] = + new NestedReducible[F, G] { + val F = self + val G = Reducible[G] + } } /** diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index 999d74c726..10c1c97cea 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -1,5 +1,7 @@ package cats +import cats.data.NestedSemigroupK + import simulacrum.typeclass /** @@ -35,4 +37,9 @@ import simulacrum.typeclass new Semigroup[F[A]] { def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } + + def nest[G[_]]: SemigroupK[Lambda[A => F[G[A]]]] = + new NestedSemigroupK[F, G] { + val F = self + } } diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index 299acb844b..7df0f70fc7 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -1,5 +1,7 @@ package cats +import cats.data.NestedTraverse + import simulacrum.typeclass /** @@ -49,6 +51,11 @@ import simulacrum.typeclass def sequenceU[GA](fga: F[GA])(implicit U: Unapply[Applicative,GA]): U.M[F[U.A]] = traverse(fga)(U.subst)(U.TC) + def nest[G[_]: Traverse]: Traverse[Lambda[A => F[G[A]]]] = new NestedTraverse[F, G] { + val F = self + val G = Traverse[G] + } + override def map[A, B](fa: F[A])(f: A => B): F[B] = traverse[Id, A, B](fa)(f) } diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 3406d1dded..2525d353a1 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -32,236 +32,333 @@ private[data] sealed abstract class NestedInstances extends NestedInstances1 { FGA.on(_.value) implicit def nestedTraverse[F[_]: Traverse, G[_]: Traverse]: Traverse[Nested[F, G, ?]] = - new NestedTraverse[F, G] { - val F = Traverse[F] - val G = Traverse[G] + new Traverse[Nested[F, G, ?]] { + val instance = Traverse[F].nest[G] + + def traverse[H[_]: Applicative, A, B](fga: Nested[F, G, A])(f: A => H[B]): H[Nested[F, G, B]] = + Applicative[H].map(instance.traverse(fga.value)(f))(Nested(_)) + + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + instance.foldLeft(fga.value, b)(f) + + def foldRight[A, B](fga: Nested[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + instance.foldRight(fga.value, lb)(f) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) } } private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { implicit def nestedReducible[F[_]: Reducible, G[_]: Reducible]: Reducible[Nested[F, G, ?]] = - new NestedReducible[F, G] { - val F = Reducible[F] - val G = Reducible[G] + new Reducible[Nested[F, G, ?]] { + val instance = Reducible[F].nest[G] + + def reduceLeftTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (B, A) => B): B = + instance.reduceLeftTo(fga.value)(f)(g) + + def reduceRightTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = + instance.reduceRightTo(fga.value)(f)(g) + + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + instance.foldLeft(fga.value, b)(f) + + def foldRight[A, B](fga: Nested[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + instance.foldRight(fga.value, lb)(f) } implicit def nestedContravariant[F[_]: Contravariant, G[_]: Contravariant]: Functor[Nested[F, G, ?]] = - new NestedContravariant[F, G] { - val F = Contravariant[F] - val G = Contravariant[G] + new Functor[Nested[F, G, ?]] { + val instance = Contravariant[F].nest[G] + + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) } + } private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { implicit def nestedFoldable[F[_]: Foldable, G[_]: Foldable]: Foldable[Nested[F, G, ?]] = - new NestedFoldable[F, G] { - val F = Foldable[F] - val G = Foldable[G] + new Foldable[Nested[F, G, ?]] { + val instance = Foldable[F].nest[G] + + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + instance.foldLeft(fga.value, b)(f) + + def foldRight[A, B](fga: Nested[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + instance.foldRight(fga.value, lb)(f) } + implicit def nestedContravariantCovariant[F[_]: Contravariant, G[_]: Functor]: Contravariant[Nested[F, G, ?]] = - new NestedContravariantCovariant[F, G] { - val F = Contravariant[F] - val G = Functor[G] + new Contravariant[Nested[F, G, ?]] { + val instance = Contravariant[F].nestFunctor[G] + + def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(instance.contramap(fga.value)(f)) } } private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { implicit def nestedAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Nested[F, G, ?]] = - new CompositeAlternative[F, G] { - val F = Alternative[F] - val G = Applicative[G] + new Alternative[Nested[F, G, ?]] { + val instance = Alternative[F].nest[G] + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) + + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(instance.ap(fgf.value)(fga.value)) + + override def product[A, B](fga: Nested[F, G, A], fgb: Nested[F, G, B]): Nested[F, G, (A, B)] = + Nested(instance.product(fga.value, fgb.value)) + + def pure[A](x: A): Nested[F, G, A] = Nested(instance.pure(x)) + + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(instance.combineK(x.value, y.value)) + + def empty[A]: Nested[F, G, A] = Nested(instance.empty[A]) } implicit def nestedCovariantContravariant[F[_]: Functor, G[_]: Contravariant]: Contravariant[Nested[F, G, ?]] = - new NestedCovariantContravariant[F, G] { - val F = Functor[F] - val G = Contravariant[G] + new Contravariant[Nested[F, G, ?]] { + val instance = Functor[F].nestContravariant[G] + + def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(instance.contramap(fga.value)(f)) } } private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { implicit def nestedApplicative[F[_]: Applicative, G[_]: Applicative]: Applicative[Nested[F, G, ?]] = - new NestedApplicative[F, G] { - val F = Applicative[F] - val G = Applicative[G] + new Applicative[Nested[F, G, ?]] { + val instance = Applicative[F].nest[G] + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) + + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(instance.ap(fgf.value)(fga.value)) + + override def product[A, B](fga: Nested[F, G, A], fgb: Nested[F, G, B]): Nested[F, G, (A, B)] = + Nested(instance.product(fga.value, fgb.value)) + + def pure[A](x: A): Nested[F, G, A] = Nested(instance.pure(x)) } implicit def nestedMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Nested[F, G, ?]] = - new NestedMonoidK[F, G] { - val F = MonoidK[F] + new MonoidK[Nested[F, G, ?]] { + val instance = MonoidK[F].nest[G] + + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(instance.combineK(x.value, y.value)) + + def empty[A]: Nested[F, G, A] = Nested(instance.empty[A]) } } private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { implicit def nestedApply[F[_]: Apply, G[_]: Apply]: Apply[Nested[F, G, ?]] = - new NestedApply[F, G] { - val F = Apply[F] - val G = Apply[G] + new Apply[Nested[F, G, ?]] { + val instance = Apply[F].nest[G] + + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(instance.ap(fgf.value)(fga.value)) + + override def product[A, B](fga: Nested[F, G, A], fgb: Nested[F, G, B]): Nested[F, G, (A, B)] = + Nested(instance.product(fga.value, fgb.value)) + + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) } implicit def nestedSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]] = - new NestedSemigroupK[F, G] { - val F = SemigroupK[F] + new SemigroupK[Nested[F, G, ?]] { + val instance = SemigroupK[F].nest[G] + + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(instance.combineK(x.value, y.value)) } } private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { implicit def nestedFunctor[F[_]: Functor, G[_]: Functor]: Functor[Nested[F, G, ?]] = - new NestedFunctor[F, G] { - val F = Functor[F] - val G = Functor[G] + new Functor[Nested[F, G, ?]] { + val instance = Functor[F].nest[G] + + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(instance.map(fga.value)(f)) + + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) } } private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { implicit def nestedInvariant[F[_]: Invariant, G[_]: Invariant]: Invariant[Nested[F, G, ?]] = - new NestedInvariant[F, G] { - val F = Invariant[F] - val G = Invariant[G] + new Invariant[Nested[F, G, ?]] { + val instance = Invariant[F].nest[G] + + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) } } private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { implicit def nestedInvariantCovariant[F[_]: Invariant, G[_]: Functor]: Invariant[Nested[F, G, ?]] = - new NestedInvariantCovariant[F, G] { - val F = Invariant[F] - val G = Functor[G] + new Invariant[Nested[F, G, ?]] { + val instance = Invariant[F].nestFunctor[G] + + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) } } private[data] sealed abstract class NestedInstances9 { implicit def nestedInvariantContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] = - new NestedInvariantContravariant[F, G] { - val F = Invariant[F] - val G = Contravariant[G] + new Invariant[Nested[F, G, ?]] { + val instance = Invariant[F].nestContravariant[G] + + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(instance.imap(fga.value)(f)(g)) } } -private[data] trait NestedInvariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { +/******************** +** Implementations ** +********************/ + +private[cats] trait NestedInvariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => def F: Invariant[F] def G: Invariant[G] - override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = - Nested(F.imap(fga.value)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f))) + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f)) } -private[data] trait NestedFunctor[F[_], G[_]] extends Functor[Nested[F, G, ?]] with NestedInvariant[F, G] { +private[cats] trait NestedFunctor[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] with NestedInvariant[F, G] { outer => def F: Functor[F] def G: Functor[G] - override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = - Nested(F.map(fga.value)(ga => G.map(ga)(f))) + override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = + F.map(fga)(ga => G.map(ga)(f)) } -private[data] trait NestedApply[F[_], G[_]] extends Apply[Nested[F, G, ?]] with NestedFunctor[F, G] { +private[cats] trait NestedApply[F[_], G[_]] extends Apply[Lambda[A => F[G[A]]]] with NestedFunctor[F, G] { outer => def F: Apply[F] def G: Apply[G] - override def ap[A, B](ff: Nested[F, G, A => B])(fa: Nested[F, G, A]): Nested[F, G, B] = - Nested(F.ap(F.map(ff.value)(gab => G.ap(gab)(_)))(fa.value)) + override def ap[A, B](fgf: F[G[A => B]])(fga: F[G[A]]): F[G[B]] = + F.ap(F.map(fgf)(gf => G.ap(gf)(_)))(fga) - override def product[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, (A, B)] = - Nested(F.map2(fa.value, fb.value)(G.product)) + override def product[A, B](fga: F[G[A]], fgb: F[G[B]]): F[G[(A, B)]] = + F.map2(fga, fgb)(G.product) } -private[data] trait NestedApplicative[F[_], G[_]] extends Applicative[Nested[F, G, ?]] with NestedApply[F, G] { +private[cats] trait NestedApplicative[F[_], G[_]] extends Applicative[Lambda[A => F[G[A]]]] with NestedApply[F, G] { outer => def F: Applicative[F] def G: Applicative[G] - override def pure[A](x: A): Nested[F, G, A] = Nested(F.pure(G.pure(x))) + override def pure[A](x: A): F[G[A]] = F.pure(G.pure(x)) } -private[data] trait NestedSemigroupK[F[_], G[_]] extends SemigroupK[Nested[F, G, ?]] { +private[cats] trait NestedSemigroupK[F[_], G[_]] extends SemigroupK[Lambda[A => F[G[A]]]] { outer => def F: SemigroupK[F] - override def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(F.combineK(x.value, y.value)) + override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combineK(x, y) } -private[data] trait NestedMonoidK[F[_], G[_]] extends MonoidK[Nested[F, G, ?]] with NestedSemigroupK[F, G] { +private[cats] trait NestedMonoidK[F[_], G[_]] extends MonoidK[Lambda[A => F[G[A]]]] with NestedSemigroupK[F, G] { outer => def F: MonoidK[F] - override def empty[A]: Nested[F, G, A] = Nested(F.empty) + override def empty[A]: F[G[A]] = F.empty } -private[data] trait CompositeAlternative[F[_], G[_]] extends Alternative[Nested[F, G, ?]] with NestedApplicative[F, G] with NestedMonoidK[F, G] { +private[cats] trait NestedAlternative[F[_], G[_]] extends Alternative[Lambda[A => F[G[A]]]] with NestedApplicative[F, G] with NestedMonoidK[F, G] { outer => def F: Alternative[F] } -private[data] trait NestedFoldable[F[_], G[_]] extends Foldable[Nested[F, G, ?]] { +private[cats] trait NestedFoldable[F[_], G[_]] extends Foldable[Lambda[A => F[G[A]]]] { outer => def F: Foldable[F] def G: Foldable[G] - override def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = - F.foldLeft(fga.value, b)((b, a) => G.foldLeft(a, b)(f)) + override def foldLeft[A, B](fga: F[G[A]], b: B)(f: (B, A) => B): B = + F.foldLeft(fga, b)((b, a) => G.foldLeft(a, b)(f)) - override def foldRight[A, B](fga: Nested[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - F.foldRight(fga.value, lb)((ga, lb) => G.foldRight(ga, lb)(f)) + override def foldRight[A, B](fga: F[G[A]], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fga, lb)((ga, lb) => G.foldRight(ga, lb)(f)) } -private[data] trait NestedTraverse[F[_], G[_]] extends Traverse[Nested[F, G, ?]] with NestedFoldable[F, G] with NestedFunctor[F, G] { +private[cats] trait NestedTraverse[F[_], G[_]] extends Traverse[Lambda[A => F[G[A]]]] with NestedFoldable[F, G] with NestedFunctor[F, G] { outer => def F: Traverse[F] def G: Traverse[G] - override def traverse[H[_]: Applicative, A, B](fga: Nested[F, G, A])(f: A => H[B]): H[Nested[F, G, B]] = - Applicative[H].map(F.traverse(fga.value)(ga => G.traverse(ga)(f)))(Nested(_)) + override def traverse[H[_]: Applicative, A, B](fga: F[G[A]])(f: A => H[B]): H[F[G[B]]] = + F.traverse(fga)(ga => G.traverse(ga)(f)) } -private[data] trait NestedReducible[F[_], G[_]] extends Reducible[Nested[F, G, ?]] with NestedFoldable[F, G] { +private[cats] trait NestedReducible[F[_], G[_]] extends Reducible[Lambda[A => F[G[A]]]] with NestedFoldable[F, G] { outer => def F: Reducible[F] def G: Reducible[G] - override def reduceLeftTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (B, A) => B): B = { + override def reduceLeftTo[A, B](fga: F[G[A]])(f: A => B)(g: (B, A) => B): B = { def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) - F.reduceLeftTo(fga.value)(toB) { (b, ga) => + F.reduceLeftTo(fga)(toB) { (b, ga) => G.foldLeft(ga, b)(g) } } - override def reduceRightTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { + override def reduceRightTo[A, B](fga: F[G[A]])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value - F.reduceRightTo(fga.value)(toB) { (ga, lb) => + F.reduceRightTo(fga)(toB) { (ga, lb) => G.foldRight(ga, lb)(g) } } } -private[data] trait NestedContravariant[F[_], G[_]] extends Functor[Nested[F, G, ?]] { +private[cats] trait NestedContravariant[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] { outer => def F: Contravariant[F] def G: Contravariant[G] - override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = - Nested(F.contramap(fga.value)(gb => G.contramap(gb)(f))) + override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = + F.contramap(fga)(gb => G.contramap(gb)(f)) } -private[data] trait NestedContravariantCovariant[F[_], G[_]] extends Contravariant[Nested[F, G, ?]] { +private[cats] trait NestedContravariantCovariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => def F: Contravariant[F] def G: Functor[G] - override def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = - Nested(F.contramap(fga.value)(gb => G.map(gb)(f))) + override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = + F.contramap(fga)(gb => G.map(gb)(f)) } -private[data] trait NestedCovariantContravariant[F[_], G[_]] extends Contravariant[Nested[F, G, ?]] { +private[cats] trait NestedCovariantContravariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => def F: Functor[F] def G: Contravariant[G] - override def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = - Nested(F.map(fga.value)(ga => G.contramap(ga)(f))) + override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = + F.map(fga)(ga => G.contramap(ga)(f)) } -private[data] trait NestedInvariantCovariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { +private[cats] trait NestedInvariantCovariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => def F: Invariant[F] def G: Functor[G] - override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = - Nested(F.imap(fga.value)(ga => G.map(ga)(f))(gb => G.map(gb)(g))) + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.map(ga)(f))(gb => G.map(gb)(g)) } -private[data] trait NestedInvariantContravariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] { +private[cats] trait NestedInvariantContravariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => def F: Invariant[F] def G: Contravariant[G] - override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = - Nested(F.imap(fga.value)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f))) + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f)) } diff --git a/core/src/main/scala/cats/functor/Contravariant.scala b/core/src/main/scala/cats/functor/Contravariant.scala index 28b249dc7e..59339c1640 100644 --- a/core/src/main/scala/cats/functor/Contravariant.scala +++ b/core/src/main/scala/cats/functor/Contravariant.scala @@ -1,6 +1,8 @@ package cats package functor +import cats.data.{NestedContravariant, NestedContravariantCovariant} + import simulacrum.typeclass /** @@ -9,4 +11,16 @@ import simulacrum.typeclass @typeclass trait Contravariant[F[_]] extends Invariant[F] { self => def contramap[A, B](fa: F[A])(f: B => A): F[B] override def imap[A, B](fa: F[A])(f: A => B)(fi: B => A): F[B] = contramap(fa)(fi) + + def nest[G[_]: Contravariant]: Functor[Lambda[A => F[G[A]]]] = + new NestedContravariant[F, G] { + val F = self + val G = Contravariant[G] + } + + override def nestFunctor[G[_]: Functor]: Contravariant[Lambda[A => F[G[A]]]] = + new NestedContravariantCovariant[F, G] { + val F = self + val G = Functor[G] + } } diff --git a/core/src/main/scala/cats/functor/Invariant.scala b/core/src/main/scala/cats/functor/Invariant.scala index 2851958418..bf3e3753b1 100644 --- a/core/src/main/scala/cats/functor/Invariant.scala +++ b/core/src/main/scala/cats/functor/Invariant.scala @@ -1,6 +1,8 @@ package cats package functor +import cats.data.{NestedInvariant, NestedInvariantContravariant, NestedInvariantCovariant} + import simulacrum.typeclass /** @@ -8,6 +10,24 @@ import simulacrum.typeclass */ @typeclass trait Invariant[F[_]] { self => def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] + + def nest[G[_]: Invariant]: Invariant[Lambda[A => F[G[A]]]] = + new NestedInvariant[F, G] { + val F = self + val G = Invariant[G] + } + + def nestFunctor[G[_]: Functor]: Invariant[Lambda[A => F[G[A]]]] = + new NestedInvariantCovariant[F, G] { + val F = self + val G = Functor[G] + } + + def nestContravariant[G[_]: Contravariant]: Invariant[Lambda[A => F[G[A]]]] = + new NestedInvariantContravariant[F, G] { + val F = self + val G = Contravariant[G] + } } object Invariant extends AlgebraInvariantInstances From 86ce5ed737b3312fcf3f09c9af2e762b1585949e Mon Sep 17 00:00:00 2001 From: Adelbert Chang Date: Thu, 2 Jun 2016 19:27:51 -0700 Subject: [PATCH 6/6] nest to compose - Rename unwrapped composed instances to Composed instead of Nested - Move instances to Composed.scala - Rename methods from nest to compose --- core/src/main/scala/cats/Alternative.scala | 6 +- core/src/main/scala/cats/Applicative.scala | 5 +- core/src/main/scala/cats/Apply.scala | 6 +- core/src/main/scala/cats/Composed.scala | 131 ++++++++++++++ core/src/main/scala/cats/Foldable.scala | 5 +- core/src/main/scala/cats/Functor.scala | 9 +- core/src/main/scala/cats/MonoidK.scala | 6 +- core/src/main/scala/cats/Reducible.scala | 6 +- core/src/main/scala/cats/SemigroupK.scala | 6 +- core/src/main/scala/cats/Traverse.scala | 11 +- core/src/main/scala/cats/data/Nested.scala | 162 ++---------------- .../scala/cats/functor/Contravariant.scala | 10 +- .../main/scala/cats/functor/Invariant.scala | 14 +- 13 files changed, 179 insertions(+), 198 deletions(-) create mode 100644 core/src/main/scala/cats/Composed.scala diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 407530849b..122d7627c2 100644 --- a/core/src/main/scala/cats/Alternative.scala +++ b/core/src/main/scala/cats/Alternative.scala @@ -1,12 +1,10 @@ package cats -import cats.data.NestedAlternative - import simulacrum.typeclass @typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self => - override def nest[G[_]: Applicative]: Alternative[Lambda[A => F[G[A]]]] = - new NestedAlternative[F, G] { + override def compose[G[_]: Applicative]: Alternative[Lambda[A => F[G[A]]]] = + new ComposedAlternative[F, G] { val F = self val G = Applicative[G] } diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index f65b9b133f..bd05b5df0a 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -1,6 +1,5 @@ package cats -import cats.data.NestedApplicative import cats.std.list._ import simulacrum.typeclass @@ -45,8 +44,8 @@ import simulacrum.typeclass def sequence[G[_], A](as: G[F[A]])(implicit G: Traverse[G]): F[G[A]] = G.sequence(as)(this) - def nest[G[_]: Applicative]: Applicative[Lambda[A => F[G[A]]]] = - new NestedApplicative[F, G] { + def compose[G[_]: Applicative]: Applicative[Lambda[A => F[G[A]]]] = + new ComposedApplicative[F, G] { val F = self val G = Applicative[G] } diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 4444aacf4a..0907ccc331 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -1,7 +1,5 @@ package cats -import cats.data.NestedApply - import simulacrum.typeclass /** @@ -60,8 +58,8 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[ def map2Eval[A, B, Z](fa: F[A], fb: Eval[F[B]])(f: (A, B) => Z): Eval[F[Z]] = fb.map(fb => map2(fa, fb)(f)) - def nest[G[_]: Apply]: Apply[Lambda[A => F[G[A]]]] = - new NestedApply[F, G] { + def compose[G[_]: Apply]: Apply[Lambda[A => F[G[A]]]] = + new ComposedApply[F, G] { val F = self val G = Apply[G] } diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala new file mode 100644 index 0000000000..5a64507e2c --- /dev/null +++ b/core/src/main/scala/cats/Composed.scala @@ -0,0 +1,131 @@ +package cats + +import cats.functor._ + +private[cats] trait ComposedInvariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => + def F: Invariant[F] + def G: Invariant[G] + + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f)) +} + +private[cats] trait ComposedFunctor[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] with ComposedInvariant[F, G] { outer => + def F: Functor[F] + def G: Functor[G] + + override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = + F.map(fga)(ga => G.map(ga)(f)) +} + +private[cats] trait ComposedApply[F[_], G[_]] extends Apply[Lambda[A => F[G[A]]]] with ComposedFunctor[F, G] { outer => + def F: Apply[F] + def G: Apply[G] + + override def ap[A, B](fgf: F[G[A => B]])(fga: F[G[A]]): F[G[B]] = + F.ap(F.map(fgf)(gf => G.ap(gf)(_)))(fga) + + override def product[A, B](fga: F[G[A]], fgb: F[G[B]]): F[G[(A, B)]] = + F.map2(fga, fgb)(G.product) +} + +private[cats] trait ComposedApplicative[F[_], G[_]] extends Applicative[Lambda[A => F[G[A]]]] with ComposedApply[F, G] { outer => + def F: Applicative[F] + def G: Applicative[G] + + override def pure[A](x: A): F[G[A]] = F.pure(G.pure(x)) +} + +private[cats] trait ComposedSemigroupK[F[_], G[_]] extends SemigroupK[Lambda[A => F[G[A]]]] { outer => + def F: SemigroupK[F] + + override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combineK(x, y) +} + +private[cats] trait ComposedMonoidK[F[_], G[_]] extends MonoidK[Lambda[A => F[G[A]]]] with ComposedSemigroupK[F, G] { outer => + def F: MonoidK[F] + + override def empty[A]: F[G[A]] = F.empty +} + +private[cats] trait ComposedAlternative[F[_], G[_]] extends Alternative[Lambda[A => F[G[A]]]] with ComposedApplicative[F, G] with ComposedMonoidK[F, G] { outer => + def F: Alternative[F] +} + +private[cats] trait ComposedFoldable[F[_], G[_]] extends Foldable[Lambda[A => F[G[A]]]] { outer => + def F: Foldable[F] + def G: Foldable[G] + + override def foldLeft[A, B](fga: F[G[A]], b: B)(f: (B, A) => B): B = + F.foldLeft(fga, b)((b, a) => G.foldLeft(a, b)(f)) + + override def foldRight[A, B](fga: F[G[A]], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fga, lb)((ga, lb) => G.foldRight(ga, lb)(f)) +} + +private[cats] trait ComposedTraverse[F[_], G[_]] extends Traverse[Lambda[A => F[G[A]]]] with ComposedFoldable[F, G] with ComposedFunctor[F, G] { outer => + def F: Traverse[F] + def G: Traverse[G] + + override def traverse[H[_]: Applicative, A, B](fga: F[G[A]])(f: A => H[B]): H[F[G[B]]] = + F.traverse(fga)(ga => G.traverse(ga)(f)) +} + +private[cats] trait ComposedReducible[F[_], G[_]] extends Reducible[Lambda[A => F[G[A]]]] with ComposedFoldable[F, G] { outer => + def F: Reducible[F] + def G: Reducible[G] + + override def reduceLeftTo[A, B](fga: F[G[A]])(f: A => B)(g: (B, A) => B): B = { + def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) + F.reduceLeftTo(fga)(toB) { (b, ga) => + G.foldLeft(ga, b)(g) + } + } + + override def reduceRightTo[A, B](fga: F[G[A]])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { + def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value + F.reduceRightTo(fga)(toB) { (ga, lb) => + G.foldRight(ga, lb)(g) + } + } +} + +private[cats] trait ComposedContravariant[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] { outer => + def F: Contravariant[F] + def G: Contravariant[G] + + override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = + F.contramap(fga)(gb => G.contramap(gb)(f)) +} + +private[cats] trait ComposedContravariantCovariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => + def F: Contravariant[F] + def G: Functor[G] + + override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = + F.contramap(fga)(gb => G.map(gb)(f)) +} + +private[cats] trait ComposedCovariantContravariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => + def F: Functor[F] + def G: Contravariant[G] + + override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = + F.map(fga)(ga => G.contramap(ga)(f)) +} + +private[cats] trait ComposedInvariantCovariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => + def F: Invariant[F] + def G: Functor[G] + + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.map(ga)(f))(gb => G.map(gb)(g)) +} + +private[cats] trait ComposedInvariantContravariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => + def F: Invariant[F] + def G: Contravariant[G] + + override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = + F.imap(fga)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f)) +} diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 4ad4a12eca..942d70d93b 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -1,6 +1,5 @@ package cats -import cats.data.NestedFoldable import scala.collection.mutable import simulacrum.typeclass @@ -270,8 +269,8 @@ import simulacrum.typeclass def nonEmpty[A](fa: F[A]): Boolean = !isEmpty(fa) - def nest[G[_]: Foldable]: Foldable[Lambda[A => F[G[A]]]] = - new NestedFoldable[F, G] { + def compose[G[_]: Foldable]: Foldable[Lambda[A => F[G[A]]]] = + new ComposedFoldable[F, G] { val F = self val G = Foldable[G] } diff --git a/core/src/main/scala/cats/Functor.scala b/core/src/main/scala/cats/Functor.scala index aa8e8f170d..5c247c4704 100644 --- a/core/src/main/scala/cats/Functor.scala +++ b/core/src/main/scala/cats/Functor.scala @@ -1,6 +1,5 @@ package cats -import cats.data.{NestedCovariantContravariant, NestedFunctor} import cats.functor.Contravariant import simulacrum.typeclass @@ -40,14 +39,14 @@ import simulacrum.typeclass */ def as[A, B](fa: F[A], b: B): F[B] = map(fa)(_ => b) - def nest[G[_]: Functor]: Functor[Lambda[A => F[G[A]]]] = - new NestedFunctor[F, G] { + def compose[G[_]: Functor]: Functor[Lambda[A => F[G[A]]]] = + new ComposedFunctor[F, G] { val F = self val G = Functor[G] } - override def nestContravariant[G[_]: Contravariant]: Contravariant[Lambda[A => F[G[A]]]] = - new NestedCovariantContravariant[F, G] { + override def composeContravariant[G[_]: Contravariant]: Contravariant[Lambda[A => F[G[A]]]] = + new ComposedCovariantContravariant[F, G] { val F = self val G = Contravariant[G] } diff --git a/core/src/main/scala/cats/MonoidK.scala b/core/src/main/scala/cats/MonoidK.scala index c1e5c77a70..1534e4720f 100644 --- a/core/src/main/scala/cats/MonoidK.scala +++ b/core/src/main/scala/cats/MonoidK.scala @@ -1,7 +1,5 @@ package cats -import cats.data.NestedMonoidK - import simulacrum.typeclass /** @@ -40,8 +38,8 @@ import simulacrum.typeclass def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } - override def nest[G[_]]: MonoidK[Lambda[A => F[G[A]]]] = - new NestedMonoidK[F, G] { + override def compose[G[_]]: MonoidK[Lambda[A => F[G[A]]]] = + new ComposedMonoidK[F, G] { val F = self } } diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index b26b88d3ff..4d3a6f4e1a 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -1,7 +1,5 @@ package cats -import cats.data.NestedReducible - import simulacrum.typeclass /** @@ -109,8 +107,8 @@ import simulacrum.typeclass def sequence1_[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = G.map(reduceLeft(fga)((x, y) => G.map2(x, y)((_, b) => b)))(_ => ()) - def nest[G[_]: Reducible]: Reducible[Lambda[A => F[G[A]]]] = - new NestedReducible[F, G] { + def compose[G[_]: Reducible]: Reducible[Lambda[A => F[G[A]]]] = + new ComposedReducible[F, G] { val F = self val G = Reducible[G] } diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index 10c1c97cea..e1a7009cee 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -1,7 +1,5 @@ package cats -import cats.data.NestedSemigroupK - import simulacrum.typeclass /** @@ -38,8 +36,8 @@ import simulacrum.typeclass def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y) } - def nest[G[_]]: SemigroupK[Lambda[A => F[G[A]]]] = - new NestedSemigroupK[F, G] { + def compose[G[_]]: SemigroupK[Lambda[A => F[G[A]]]] = + new ComposedSemigroupK[F, G] { val F = self } } diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index 7df0f70fc7..0d7068a13d 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -1,7 +1,5 @@ package cats -import cats.data.NestedTraverse - import simulacrum.typeclass /** @@ -51,10 +49,11 @@ import simulacrum.typeclass def sequenceU[GA](fga: F[GA])(implicit U: Unapply[Applicative,GA]): U.M[F[U.A]] = traverse(fga)(U.subst)(U.TC) - def nest[G[_]: Traverse]: Traverse[Lambda[A => F[G[A]]]] = new NestedTraverse[F, G] { - val F = self - val G = Traverse[G] - } + def compose[G[_]: Traverse]: Traverse[Lambda[A => F[G[A]]]] = + new ComposedTraverse[F, G] { + val F = self + val G = Traverse[G] + } override def map[A, B](fa: F[A])(f: A => B): F[B] = traverse[Id, A, B](fa)(f) diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 2525d353a1..7dbdf00ee8 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -33,7 +33,7 @@ private[data] sealed abstract class NestedInstances extends NestedInstances1 { implicit def nestedTraverse[F[_]: Traverse, G[_]: Traverse]: Traverse[Nested[F, G, ?]] = new Traverse[Nested[F, G, ?]] { - val instance = Traverse[F].nest[G] + val instance = Traverse[F].compose[G] def traverse[H[_]: Applicative, A, B](fga: Nested[F, G, A])(f: A => H[B]): H[Nested[F, G, B]] = Applicative[H].map(instance.traverse(fga.value)(f))(Nested(_)) @@ -55,7 +55,7 @@ private[data] sealed abstract class NestedInstances extends NestedInstances1 { private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { implicit def nestedReducible[F[_]: Reducible, G[_]: Reducible]: Reducible[Nested[F, G, ?]] = new Reducible[Nested[F, G, ?]] { - val instance = Reducible[F].nest[G] + val instance = Reducible[F].compose[G] def reduceLeftTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (B, A) => B): B = instance.reduceLeftTo(fga.value)(f)(g) @@ -72,7 +72,7 @@ private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { implicit def nestedContravariant[F[_]: Contravariant, G[_]: Contravariant]: Functor[Nested[F, G, ?]] = new Functor[Nested[F, G, ?]] { - val instance = Contravariant[F].nest[G] + val instance = Contravariant[F].compose[G] def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = Nested(instance.map(fga.value)(f)) @@ -83,7 +83,7 @@ private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { implicit def nestedFoldable[F[_]: Foldable, G[_]: Foldable]: Foldable[Nested[F, G, ?]] = new Foldable[Nested[F, G, ?]] { - val instance = Foldable[F].nest[G] + val instance = Foldable[F].compose[G] def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = instance.foldLeft(fga.value, b)(f) @@ -95,7 +95,7 @@ private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { implicit def nestedContravariantCovariant[F[_]: Contravariant, G[_]: Functor]: Contravariant[Nested[F, G, ?]] = new Contravariant[Nested[F, G, ?]] { - val instance = Contravariant[F].nestFunctor[G] + val instance = Contravariant[F].composeFunctor[G] def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = Nested(instance.contramap(fga.value)(f)) @@ -105,7 +105,7 @@ private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { implicit def nestedAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Nested[F, G, ?]] = new Alternative[Nested[F, G, ?]] { - val instance = Alternative[F].nest[G] + val instance = Alternative[F].compose[G] override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = Nested(instance.imap(fga.value)(f)(g)) @@ -128,7 +128,7 @@ private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { implicit def nestedCovariantContravariant[F[_]: Functor, G[_]: Contravariant]: Contravariant[Nested[F, G, ?]] = new Contravariant[Nested[F, G, ?]] { - val instance = Functor[F].nestContravariant[G] + val instance = Functor[F].composeContravariant[G] def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = Nested(instance.contramap(fga.value)(f)) @@ -138,7 +138,7 @@ private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { implicit def nestedApplicative[F[_]: Applicative, G[_]: Applicative]: Applicative[Nested[F, G, ?]] = new Applicative[Nested[F, G, ?]] { - val instance = Applicative[F].nest[G] + val instance = Applicative[F].compose[G] override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = Nested(instance.imap(fga.value)(f)(g)) @@ -157,7 +157,7 @@ private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { implicit def nestedMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Nested[F, G, ?]] = new MonoidK[Nested[F, G, ?]] { - val instance = MonoidK[F].nest[G] + val instance = MonoidK[F].compose[G] def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(instance.combineK(x.value, y.value)) @@ -168,7 +168,7 @@ private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { implicit def nestedApply[F[_]: Apply, G[_]: Apply]: Apply[Nested[F, G, ?]] = new Apply[Nested[F, G, ?]] { - val instance = Apply[F].nest[G] + val instance = Apply[F].compose[G] def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = Nested(instance.ap(fgf.value)(fga.value)) @@ -182,7 +182,7 @@ private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { implicit def nestedSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]] = new SemigroupK[Nested[F, G, ?]] { - val instance = SemigroupK[F].nest[G] + val instance = SemigroupK[F].compose[G] def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(instance.combineK(x.value, y.value)) } @@ -191,7 +191,7 @@ private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { implicit def nestedFunctor[F[_]: Functor, G[_]: Functor]: Functor[Nested[F, G, ?]] = new Functor[Nested[F, G, ?]] { - val instance = Functor[F].nest[G] + val instance = Functor[F].compose[G] def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = Nested(instance.map(fga.value)(f)) @@ -204,7 +204,7 @@ private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { implicit def nestedInvariant[F[_]: Invariant, G[_]: Invariant]: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { - val instance = Invariant[F].nest[G] + val instance = Invariant[F].compose[G] def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = Nested(instance.imap(fga.value)(f)(g)) @@ -214,7 +214,7 @@ private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { implicit def nestedInvariantCovariant[F[_]: Invariant, G[_]: Functor]: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { - val instance = Invariant[F].nestFunctor[G] + val instance = Invariant[F].composeFunctor[G] def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = Nested(instance.imap(fga.value)(f)(g)) @@ -224,141 +224,9 @@ private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { private[data] sealed abstract class NestedInstances9 { implicit def nestedInvariantContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { - val instance = Invariant[F].nestContravariant[G] + val instance = Invariant[F].composeContravariant[G] def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = Nested(instance.imap(fga.value)(f)(g)) } } - -/******************** -** Implementations ** -********************/ - -private[cats] trait NestedInvariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => - def F: Invariant[F] - def G: Invariant[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.imap(ga)(f)(g))(gb => G.imap(gb)(g)(f)) -} - -private[cats] trait NestedFunctor[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] with NestedInvariant[F, G] { outer => - def F: Functor[F] - def G: Functor[G] - - override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = - F.map(fga)(ga => G.map(ga)(f)) -} - -private[cats] trait NestedApply[F[_], G[_]] extends Apply[Lambda[A => F[G[A]]]] with NestedFunctor[F, G] { outer => - def F: Apply[F] - def G: Apply[G] - - override def ap[A, B](fgf: F[G[A => B]])(fga: F[G[A]]): F[G[B]] = - F.ap(F.map(fgf)(gf => G.ap(gf)(_)))(fga) - - override def product[A, B](fga: F[G[A]], fgb: F[G[B]]): F[G[(A, B)]] = - F.map2(fga, fgb)(G.product) -} - -private[cats] trait NestedApplicative[F[_], G[_]] extends Applicative[Lambda[A => F[G[A]]]] with NestedApply[F, G] { outer => - def F: Applicative[F] - def G: Applicative[G] - - override def pure[A](x: A): F[G[A]] = F.pure(G.pure(x)) -} - -private[cats] trait NestedSemigroupK[F[_], G[_]] extends SemigroupK[Lambda[A => F[G[A]]]] { outer => - def F: SemigroupK[F] - - override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combineK(x, y) -} - -private[cats] trait NestedMonoidK[F[_], G[_]] extends MonoidK[Lambda[A => F[G[A]]]] with NestedSemigroupK[F, G] { outer => - def F: MonoidK[F] - - override def empty[A]: F[G[A]] = F.empty -} - -private[cats] trait NestedAlternative[F[_], G[_]] extends Alternative[Lambda[A => F[G[A]]]] with NestedApplicative[F, G] with NestedMonoidK[F, G] { outer => - def F: Alternative[F] -} - -private[cats] trait NestedFoldable[F[_], G[_]] extends Foldable[Lambda[A => F[G[A]]]] { outer => - def F: Foldable[F] - def G: Foldable[G] - - override def foldLeft[A, B](fga: F[G[A]], b: B)(f: (B, A) => B): B = - F.foldLeft(fga, b)((b, a) => G.foldLeft(a, b)(f)) - - override def foldRight[A, B](fga: F[G[A]], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - F.foldRight(fga, lb)((ga, lb) => G.foldRight(ga, lb)(f)) -} - -private[cats] trait NestedTraverse[F[_], G[_]] extends Traverse[Lambda[A => F[G[A]]]] with NestedFoldable[F, G] with NestedFunctor[F, G] { outer => - def F: Traverse[F] - def G: Traverse[G] - - override def traverse[H[_]: Applicative, A, B](fga: F[G[A]])(f: A => H[B]): H[F[G[B]]] = - F.traverse(fga)(ga => G.traverse(ga)(f)) -} - -private[cats] trait NestedReducible[F[_], G[_]] extends Reducible[Lambda[A => F[G[A]]]] with NestedFoldable[F, G] { outer => - def F: Reducible[F] - def G: Reducible[G] - - override def reduceLeftTo[A, B](fga: F[G[A]])(f: A => B)(g: (B, A) => B): B = { - def toB(ga: G[A]): B = G.reduceLeftTo(ga)(f)(g) - F.reduceLeftTo(fga)(toB) { (b, ga) => - G.foldLeft(ga, b)(g) - } - } - - override def reduceRightTo[A, B](fga: F[G[A]])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = { - def toB(ga: G[A]): B = G.reduceRightTo(ga)(f)(g).value - F.reduceRightTo(fga)(toB) { (ga, lb) => - G.foldRight(ga, lb)(g) - } - } -} - -private[cats] trait NestedContravariant[F[_], G[_]] extends Functor[Lambda[A => F[G[A]]]] { outer => - def F: Contravariant[F] - def G: Contravariant[G] - - override def map[A, B](fga: F[G[A]])(f: A => B): F[G[B]] = - F.contramap(fga)(gb => G.contramap(gb)(f)) -} - -private[cats] trait NestedContravariantCovariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => - def F: Contravariant[F] - def G: Functor[G] - - override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = - F.contramap(fga)(gb => G.map(gb)(f)) -} - -private[cats] trait NestedCovariantContravariant[F[_], G[_]] extends Contravariant[Lambda[A => F[G[A]]]] { outer => - def F: Functor[F] - def G: Contravariant[G] - - override def contramap[A, B](fga: F[G[A]])(f: B => A): F[G[B]] = - F.map(fga)(ga => G.contramap(ga)(f)) -} - -private[cats] trait NestedInvariantCovariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => - def F: Invariant[F] - def G: Functor[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.map(ga)(f))(gb => G.map(gb)(g)) -} - -private[cats] trait NestedInvariantContravariant[F[_], G[_]] extends Invariant[Lambda[A => F[G[A]]]] { outer => - def F: Invariant[F] - def G: Contravariant[G] - - override def imap[A, B](fga: F[G[A]])(f: A => B)(g: B => A): F[G[B]] = - F.imap(fga)(ga => G.contramap(ga)(g))(gb => G.contramap(gb)(f)) -} diff --git a/core/src/main/scala/cats/functor/Contravariant.scala b/core/src/main/scala/cats/functor/Contravariant.scala index 59339c1640..45174209af 100644 --- a/core/src/main/scala/cats/functor/Contravariant.scala +++ b/core/src/main/scala/cats/functor/Contravariant.scala @@ -1,8 +1,6 @@ package cats package functor -import cats.data.{NestedContravariant, NestedContravariantCovariant} - import simulacrum.typeclass /** @@ -12,14 +10,14 @@ import simulacrum.typeclass def contramap[A, B](fa: F[A])(f: B => A): F[B] override def imap[A, B](fa: F[A])(f: A => B)(fi: B => A): F[B] = contramap(fa)(fi) - def nest[G[_]: Contravariant]: Functor[Lambda[A => F[G[A]]]] = - new NestedContravariant[F, G] { + def compose[G[_]: Contravariant]: Functor[Lambda[A => F[G[A]]]] = + new ComposedContravariant[F, G] { val F = self val G = Contravariant[G] } - override def nestFunctor[G[_]: Functor]: Contravariant[Lambda[A => F[G[A]]]] = - new NestedContravariantCovariant[F, G] { + override def composeFunctor[G[_]: Functor]: Contravariant[Lambda[A => F[G[A]]]] = + new ComposedContravariantCovariant[F, G] { val F = self val G = Functor[G] } diff --git a/core/src/main/scala/cats/functor/Invariant.scala b/core/src/main/scala/cats/functor/Invariant.scala index bf3e3753b1..0bcd1dd6f5 100644 --- a/core/src/main/scala/cats/functor/Invariant.scala +++ b/core/src/main/scala/cats/functor/Invariant.scala @@ -1,8 +1,6 @@ package cats package functor -import cats.data.{NestedInvariant, NestedInvariantContravariant, NestedInvariantCovariant} - import simulacrum.typeclass /** @@ -11,20 +9,20 @@ import simulacrum.typeclass @typeclass trait Invariant[F[_]] { self => def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] - def nest[G[_]: Invariant]: Invariant[Lambda[A => F[G[A]]]] = - new NestedInvariant[F, G] { + def compose[G[_]: Invariant]: Invariant[Lambda[A => F[G[A]]]] = + new ComposedInvariant[F, G] { val F = self val G = Invariant[G] } - def nestFunctor[G[_]: Functor]: Invariant[Lambda[A => F[G[A]]]] = - new NestedInvariantCovariant[F, G] { + def composeFunctor[G[_]: Functor]: Invariant[Lambda[A => F[G[A]]]] = + new ComposedInvariantCovariant[F, G] { val F = self val G = Functor[G] } - def nestContravariant[G[_]: Contravariant]: Invariant[Lambda[A => F[G[A]]]] = - new NestedInvariantContravariant[F, G] { + def composeContravariant[G[_]: Contravariant]: Invariant[Lambda[A => F[G[A]]]] = + new ComposedInvariantContravariant[F, G] { val F = self val G = Contravariant[G] }