diff --git a/core/src/main/scala/cats/Alternative.scala b/core/src/main/scala/cats/Alternative.scala index 1f86cff46b4..8e18e3ba77c 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 => + def nestApplicative[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 1c4e29f1d92..f65b9b133fc 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 e142433fb79..4444aacf4a1 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 fad4fb6b7a5..4ad4a12eca8 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 c8f15964096..aa8e8f170de 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 e55077151d7..c1e5c77a70d 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 fd72a8376a8..b26b88d3fff 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 999d74c726f..10c1c97cea0 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 299acb844b1..7df0f70fc7d 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 3406d1dded8..db3091d8142 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -35,7 +35,7 @@ private[data] sealed abstract class NestedInstances extends NestedInstances1 { new NestedTraverse[F, G] { val F = Traverse[F] val G = Traverse[G] - } + }.toNested } private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { @@ -43,13 +43,13 @@ private[data] sealed abstract class NestedInstances1 extends NestedInstances2 { new NestedReducible[F, G] { val F = Reducible[F] val G = Reducible[G] - } + }.toNested implicit def nestedContravariant[F[_]: Contravariant, G[_]: Contravariant]: Functor[Nested[F, G, ?]] = new NestedContravariant[F, G] { val F = Contravariant[F] val G = Contravariant[G] - } + }.toNested } private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { @@ -57,27 +57,27 @@ private[data] sealed abstract class NestedInstances2 extends NestedInstances3 { new NestedFoldable[F, G] { val F = Foldable[F] val G = Foldable[G] - } + }.toNested implicit def nestedContravariantCovariant[F[_]: Contravariant, G[_]: Functor]: Contravariant[Nested[F, G, ?]] = new NestedContravariantCovariant[F, G] { val F = Contravariant[F] val G = Functor[G] - } + }.toNested } private[data] sealed abstract class NestedInstances3 extends NestedInstances4 { implicit def nestedAlternative[F[_]: Alternative, G[_]: Applicative]: Alternative[Nested[F, G, ?]] = - new CompositeAlternative[F, G] { + new NestedAlternative[F, G] { val F = Alternative[F] val G = Applicative[G] - } + }.toNested implicit def nestedCovariantContravariant[F[_]: Functor, G[_]: Contravariant]: Contravariant[Nested[F, G, ?]] = new NestedCovariantContravariant[F, G] { val F = Functor[F] val G = Contravariant[G] - } + }.toNested } private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { @@ -85,12 +85,12 @@ private[data] sealed abstract class NestedInstances4 extends NestedInstances5 { new NestedApplicative[F, G] { val F = Applicative[F] val G = Applicative[G] - } + }.toNested implicit def nestedMonoidK[F[_]: MonoidK, G[_]]: MonoidK[Nested[F, G, ?]] = new NestedMonoidK[F, G] { val F = MonoidK[F] - } + }.toNested } private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { @@ -98,12 +98,12 @@ private[data] sealed abstract class NestedInstances5 extends NestedInstances6 { new NestedApply[F, G] { val F = Apply[F] val G = Apply[G] - } + }.toNested implicit def nestedSemigroupK[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]] = new NestedSemigroupK[F, G] { val F = SemigroupK[F] - } + }.toNested } private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { @@ -111,7 +111,7 @@ private[data] sealed abstract class NestedInstances6 extends NestedInstances7 { new NestedFunctor[F, G] { val F = Functor[F] val G = Functor[G] - } + }.toNested } private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { @@ -119,7 +119,7 @@ private[data] sealed abstract class NestedInstances7 extends NestedInstances8 { new NestedInvariant[F, G] { val F = Invariant[F] val G = Invariant[G] - } + }.toNested } private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { @@ -127,7 +127,7 @@ private[data] sealed abstract class NestedInstances8 extends NestedInstances9 { new NestedInvariantCovariant[F, G] { val F = Invariant[F] val G = Functor[G] - } + }.toNested } private[data] sealed abstract class NestedInstances9 { @@ -135,133 +135,271 @@ private[data] sealed abstract class NestedInstances9 { new NestedInvariantContravariant[F, G] { val F = Invariant[F] val G = Contravariant[G] - } + }.toNested } -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))) + def toNested: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(outer.imap(fga.value)(f)(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[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 toNested: Functor[Nested[F, G, ?]] = new Functor[Nested[F, G, ?]] { + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.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(outer.imap(fga.value)(f)(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[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 toNested: Apply[Nested[F, G, ?]] = new Apply[Nested[F, G, ?]] { + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(outer.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(outer.product(fga.value, fgb.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)) + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.map(fga.value)(f)) + } + + 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[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 toNested: Applicative[Nested[F, G, ?]] = new Applicative[Nested[F, G, ?]] { + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(outer.imap(fga.value)(f)(g)) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.map(fga.value)(f)) + + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(outer.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(outer.product(fga.value, fgb.value)) + + def pure[A](x: A): Nested[F, G, A] = Nested(outer.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)) + def toNested: SemigroupK[Nested[F, G, ?]] = new SemigroupK[Nested[F, G, ?]] { + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(outer.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 toNested: MonoidK[Nested[F, G, ?]] = new MonoidK[Nested[F, G, ?]] { + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(outer.combineK(x.value, y.value)) + + def empty[A]: Nested[F, G, A] = Nested(outer.empty[A]) + } + + 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] + + override def toNested: Alternative[Nested[F, G, ?]] = new Alternative[Nested[F, G, ?]] { + override def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(outer.imap(fga.value)(f)(g)) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.map(fga.value)(f)) + + def ap[A, B](fgf: Nested[F, G, A => B])(fga: Nested[F, G, A]): Nested[F, G, B] = + Nested(outer.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(outer.product(fga.value, fgb.value)) + + def pure[A](x: A): Nested[F, G, A] = Nested(outer.pure(x)) + + def combineK[A](x: Nested[F, G, A], y: Nested[F, G, A]): Nested[F, G, A] = Nested(outer.combineK(x.value, y.value)) + + def empty[A]: Nested[F, G, A] = Nested(outer.empty[A]) + } } -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)) + def toNested: Foldable[Nested[F, G, ?]] = new Foldable[Nested[F, G, ?]] { + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + outer.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] = + outer.foldRight(fga.value, lb)(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 toNested: Traverse[Nested[F, G, ?]] = new Traverse[Nested[F, G, ?]] { + def traverse[H[_]: Applicative, A, B](fga: Nested[F, G, A])(f: A => H[B]): H[Nested[F, G, B]] = + Applicative[H].map(outer.traverse(fga.value)(f))(Nested(_)) + + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + outer.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] = + outer.foldRight(fga.value, lb)(f) + + override def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.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(outer.imap(fga.value)(f)(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[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 toNested: Reducible[Nested[F, G, ?]] = new Reducible[Nested[F, G, ?]] { + def reduceLeftTo[A, B](fga: Nested[F, G, A])(f: A => B)(g: (B, A) => B): B = + outer.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] = + outer.reduceRightTo(fga.value)(f)(g) + + def foldLeft[A, B](fga: Nested[F, G, A], b: B)(f: (B, A) => B): B = + outer.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] = + outer.foldRight(fga.value, lb)(f) + } + + 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))) + def toNested: Functor[Nested[F, G, ?]] = new Functor[Nested[F, G, ?]] { + def map[A, B](fga: Nested[F, G, A])(f: A => B): Nested[F, G, B] = + Nested(outer.map(fga.value)(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))) + def toNested: Contravariant[Nested[F, G, ?]] = new Contravariant[Nested[F, G, ?]] { + def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(outer.contramap(fga.value)(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))) + def toNested: Contravariant[Nested[F, G, ?]] = new Contravariant[Nested[F, G, ?]] { + def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] = + Nested(outer.contramap(fga.value)(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))) + def toNested: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(outer.imap(fga.value)(f)(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))) + def toNested: Invariant[Nested[F, G, ?]] = new Invariant[Nested[F, G, ?]] { + def imap[A, B](fga: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] = + Nested(outer.imap(fga.value)(f)(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 28b249dc7e4..59339c1640a 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 28519584182..bf3e3753b1a 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