From 2a32e37bb60aecfdba6a82db02d7ea9127333a86 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Wed, 5 Apr 2017 17:39:39 -0400 Subject: [PATCH] Rename prod coproduct (#1589) * renamed Coproduct and Prod to EitherK and Tuple2K in code * renamed files accordingly --- core/src/main/scala/cats/Inject.scala | 18 +- .../src/main/scala/cats/arrow/FunctionK.scala | 16 +- core/src/main/scala/cats/data/Coproduct.scala | 231 ------------------ core/src/main/scala/cats/data/EitherK.scala | 231 ++++++++++++++++++ core/src/main/scala/cats/data/Func.scala | 6 +- core/src/main/scala/cats/data/Nested.scala | 2 +- core/src/main/scala/cats/data/Prod.scala | 185 -------------- core/src/main/scala/cats/data/Tuple2K.scala | 185 ++++++++++++++ core/src/main/scala/cats/syntax/all.scala | 2 +- .../main/scala/cats/syntax/coproduct.scala | 43 ---- core/src/main/scala/cats/syntax/eitherK.scala | 43 ++++ core/src/main/scala/cats/syntax/package.scala | 2 +- .../src/main/tut/datatypes/freeapplicative.md | 4 +- docs/src/main/tut/datatypes/freemonad.md | 10 +- free/src/main/scala/cats/free/Free.scala | 4 +- free/src/test/scala/cats/free/FreeTests.scala | 8 +- .../cats/laws/discipline/Arbitrary.scala | 14 +- .../scala/cats/tests/CoproductTests.scala | 61 ----- .../test/scala/cats/tests/EitherKTests.scala | 61 +++++ .../scala/cats/tests/FunctionKTests.scala | 6 +- .../test/scala/cats/tests/InjectTests.scala | 8 +- .../src/test/scala/cats/tests/ProdTests.scala | 93 ------- .../test/scala/cats/tests/Tuple2KTests.scala | 93 +++++++ 23 files changed, 663 insertions(+), 663 deletions(-) delete mode 100644 core/src/main/scala/cats/data/Coproduct.scala create mode 100644 core/src/main/scala/cats/data/EitherK.scala delete mode 100644 core/src/main/scala/cats/data/Prod.scala create mode 100644 core/src/main/scala/cats/data/Tuple2K.scala delete mode 100644 core/src/main/scala/cats/syntax/coproduct.scala create mode 100644 core/src/main/scala/cats/syntax/eitherK.scala delete mode 100644 tests/src/test/scala/cats/tests/CoproductTests.scala create mode 100644 tests/src/test/scala/cats/tests/EitherKTests.scala delete mode 100644 tests/src/test/scala/cats/tests/ProdTests.scala create mode 100644 tests/src/test/scala/cats/tests/Tuple2KTests.scala diff --git a/core/src/main/scala/cats/Inject.scala b/core/src/main/scala/cats/Inject.scala index 7963fd9cd7..db6e76e218 100644 --- a/core/src/main/scala/cats/Inject.scala +++ b/core/src/main/scala/cats/Inject.scala @@ -1,7 +1,7 @@ package cats import cats.arrow.FunctionK -import cats.data.Coproduct +import cats.data.EitherK /** * Inject type class as described in "Data types a la carte" (Swierstra 2008). @@ -26,18 +26,18 @@ private[cats] sealed abstract class InjectInstances { val prj = λ[FunctionK[F, λ[α => Option[F[α]]]]](Some(_)) } - implicit def catsLeftInjectInstance[F[_], G[_]]: Inject[F, Coproduct[F, G, ?]] = - new Inject[F, Coproduct[F, G, ?]] { - val inj = λ[FunctionK[F, Coproduct[F, G, ?]]](Coproduct.leftc(_)) + implicit def catsLeftInjectInstance[F[_], G[_]]: Inject[F, EitherK[F, G, ?]] = + new Inject[F, EitherK[F, G, ?]] { + val inj = λ[FunctionK[F, EitherK[F, G, ?]]](EitherK.leftc(_)) - val prj = λ[FunctionK[Coproduct[F, G, ?], λ[α => Option[F[α]]]]](_.run.left.toOption) + val prj = λ[FunctionK[EitherK[F, G, ?], λ[α => Option[F[α]]]]](_.run.left.toOption) } - implicit def catsRightInjectInstance[F[_], G[_], H[_]](implicit I: Inject[F, G]): Inject[F, Coproduct[H, G, ?]] = - new Inject[F, Coproduct[H, G, ?]] { - val inj = λ[FunctionK[G, Coproduct[H, G, ?]]](Coproduct.rightc(_)) compose I.inj + implicit def catsRightInjectInstance[F[_], G[_], H[_]](implicit I: Inject[F, G]): Inject[F, EitherK[H, G, ?]] = + new Inject[F, EitherK[H, G, ?]] { + val inj = λ[FunctionK[G, EitherK[H, G, ?]]](EitherK.rightc(_)) compose I.inj - val prj = λ[FunctionK[Coproduct[H, G, ?], λ[α => Option[F[α]]]]](_.run.right.toOption.flatMap(I.prj(_))) + val prj = λ[FunctionK[EitherK[H, G, ?], λ[α => Option[F[α]]]]](_.run.right.toOption.flatMap(I.prj(_))) } } diff --git a/core/src/main/scala/cats/arrow/FunctionK.scala b/core/src/main/scala/cats/arrow/FunctionK.scala index 6657312c03..a7aa6cd47e 100644 --- a/core/src/main/scala/cats/arrow/FunctionK.scala +++ b/core/src/main/scala/cats/arrow/FunctionK.scala @@ -1,7 +1,7 @@ package cats package arrow -import cats.data.{Coproduct, Prod} +import cats.data.{EitherK, Tuple2K} import cats.macros.MacroCompat @@ -38,17 +38,17 @@ trait FunctionK[F[_], G[_]] extends Serializable { self => /** * Composes two instances of FunctionK into a new FunctionK that transforms - * a [[cats.data.Coproduct]] to a single functor. + * a [[cats.data.EitherK]] to a single functor. * * This transformation will be used to transform left `F` values while * `h` will be used to transform right `H` values. */ - def or[H[_]](h: FunctionK[H, G]): FunctionK[Coproduct[F, H, ?], G] = - λ[FunctionK[Coproduct[F, H, ?], G]](fa => fa.fold(self, h)) + def or[H[_]](h: FunctionK[H, G]): FunctionK[EitherK[F, H, ?], G] = + λ[FunctionK[EitherK[F, H, ?], G]](fa => fa.fold(self, h)) /** * Composes two instances of `FunctionK` into a new `FunctionK` that transforms - * one single functor to a [[cats.data.Prod]] of two functors. + * one single functor to a [[cats.data.Tuple2K]] of two functors. * * {{{ * scala> import cats.arrow.FunctionK @@ -56,11 +56,11 @@ trait FunctionK[F[_], G[_]] extends Serializable { self => * scala> val list2vector = λ[FunctionK[List, Vector]](_.toVector) * scala> val optionAndVector = list2option and list2vector * scala> optionAndVector(List(1,2,3)) - * res0: cats.data.Prod[Option,Vector,Int] = Prod(Some(1),Vector(1, 2, 3)) + * res0: cats.data.Tuple2K[Option,Vector,Int] = Tuple2K(Some(1),Vector(1, 2, 3)) * }}} */ - def and[H[_]](h: FunctionK[F, H]): FunctionK[F, Prod[G, H, ?]] = - λ[FunctionK[F, Prod[G, H, ?]]](fa => Prod(self(fa), h(fa))) + def and[H[_]](h: FunctionK[F, H]): FunctionK[F, Tuple2K[G, H, ?]] = + λ[FunctionK[F, Tuple2K[G, H, ?]]](fa => Tuple2K(self(fa), h(fa))) } object FunctionK { diff --git a/core/src/main/scala/cats/data/Coproduct.scala b/core/src/main/scala/cats/data/Coproduct.scala deleted file mode 100644 index 405289a233..0000000000 --- a/core/src/main/scala/cats/data/Coproduct.scala +++ /dev/null @@ -1,231 +0,0 @@ -package cats -package data - -import cats.arrow.FunctionK -import cats.functor.Contravariant -import cats.syntax.either._ - -/** `F` on the left and `G` on the right of [[scala.util.Either]]. - * - * @param run The underlying [[scala.util.Either]]. - */ -final case class Coproduct[F[_], G[_], A](run: Either[F[A], G[A]]) { - - import Coproduct._ - - def map[B](f: A => B)(implicit F: Functor[F], G: Functor[G]): Coproduct[F, G, B] = - Coproduct(run.bimap(F.lift(f), G.lift(f))) - - def coflatMap[B](f: Coproduct[F, G, A] => B)(implicit F: CoflatMap[F], G: CoflatMap[G]): Coproduct[F, G, B] = - Coproduct( - run.bimap(a => F.coflatMap(a)(x => f(leftc(x))), a => G.coflatMap(a)(x => f(rightc(x)))) - ) - - def coflatten(implicit F: CoflatMap[F], G: CoflatMap[G]): Coproduct[F, G, Coproduct[F, G, A]] = - Coproduct(run.bimap( - x => F.coflatMap(x)(a => leftc(a)) - , x => G.coflatMap(x)(a => rightc(a))) - ) - - def extract(implicit F: Comonad[F], G: Comonad[G]): A = - run.fold(F.extract, G.extract) - - def contramap[B](f: B => A)(implicit F: Contravariant[F], G: Contravariant[G]): Coproduct[F, G, B] = - Coproduct(run.bimap(F.contramap(_)(f), G.contramap(_)(f))) - - def foldRight[B](z: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F], G: Foldable[G]): Eval[B] = - run.fold(a => F.foldRight(a, z)(f), a => G.foldRight(a, z)(f)) - - def foldLeft[B](z: B)(f: (B, A) => B)(implicit F: Foldable[F], G: Foldable[G]): B = - run.fold(a => F.foldLeft(a, z)(f), a => G.foldLeft(a, z)(f)) - - def foldMap[B](f: A => B)(implicit F: Foldable[F], G: Foldable[G], M: Monoid[B]): B = - run.fold(F.foldMap(_)(f), G.foldMap(_)(f)) - - def traverse[X[_], B](g: A => X[B])(implicit F: Traverse[F], G: Traverse[G], A: Applicative[X]): X[Coproduct[F, G, B]] = - run.fold( - x => A.map(F.traverse(x)(g))(leftc(_)) - , x => A.map(G.traverse(x)(g))(rightc(_)) - ) - - def isLeft: Boolean = - run.isLeft - - def isRight: Boolean = - run.isRight - - def swap: Coproduct[G, F, A] = - Coproduct(run.swap) - - def toValidated: Validated[F[A], G[A]] = - run.toValidated - - /** - * Fold this coproduct into a new type constructor using two natural transformations. - * - * Example: - * {{{ - * scala> import cats.arrow.FunctionK - * scala> import cats.data.Coproduct - * scala> val listToOption = λ[FunctionK[List, Option]](_.headOption) - * scala> val optionToOption = FunctionK.id[Option] - * scala> val cp1: Coproduct[List, Option, Int] = Coproduct.leftc(List(1,2,3)) - * scala> val cp2: Coproduct[List, Option, Int] = Coproduct.rightc(Some(4)) - * scala> cp1.fold(listToOption, optionToOption) - * res0: Option[Int] = Some(1) - * scala> cp2.fold(listToOption, optionToOption) - * res1: Option[Int] = Some(4) - * }}} - */ - def fold[H[_]](f: FunctionK[F, H], g: FunctionK[G, H]): H[A] = - run.fold(f.apply, g.apply) -} - -object Coproduct extends CoproductInstances { - - def leftc[F[_], G[_], A](x: F[A]): Coproduct[F, G, A] = - Coproduct(Left(x)) - - def rightc[F[_], G[_], A](x: G[A]): Coproduct[F, G, A] = - Coproduct(Right(x)) - - final class CoproductLeft[G[_]] private[Coproduct] { - def apply[F[_], A](fa: F[A]): Coproduct[F, G, A] = Coproduct(Left(fa)) - } - - final class CoproductRight[F[_]] private[Coproduct] { - def apply[G[_], A](ga: G[A]): Coproduct[F, G, A] = Coproduct(Right(ga)) - } - - def left[G[_]]: CoproductLeft[G] = new CoproductLeft[G] - - def right[F[_]]: CoproductRight[F] = new CoproductRight[F] -} - -private[data] sealed abstract class CoproductInstances3 { - - implicit def catsDataEqForCoproduct[F[_], G[_], A](implicit E: Eq[Either[F[A], G[A]]]): Eq[Coproduct[F, G, A]] = - Eq.by(_.run) - - implicit def catsDataFunctorForCoproduct[F[_], G[_]](implicit F0: Functor[F], G0: Functor[G]): Functor[Coproduct[F, G, ?]] = - new CoproductFunctor[F, G] { - implicit def F: Functor[F] = F0 - - implicit def G: Functor[G] = G0 - } - - implicit def catsDataFoldableForCoproduct[F[_], G[_]](implicit F0: Foldable[F], G0: Foldable[G]): Foldable[Coproduct[F, G, ?]] = - new CoproductFoldable[F, G] { - implicit def F: Foldable[F] = F0 - - implicit def G: Foldable[G] = G0 - } -} - -private[data] sealed abstract class CoproductInstances2 extends CoproductInstances3 { - - implicit def catsDataContravariantForCoproduct[F[_], G[_]](implicit F0: Contravariant[F], G0: Contravariant[G]): Contravariant[Coproduct[F, G, ?]] = - new CoproductContravariant[F, G] { - implicit def F: Contravariant[F] = F0 - - implicit def G: Contravariant[G] = G0 - } -} - -private[data] sealed abstract class CoproductInstances1 extends CoproductInstances2 { - implicit def catsDataCoflatMapForCoproduct[F[_], G[_]](implicit F0: CoflatMap[F], G0: CoflatMap[G]): CoflatMap[Coproduct[F, G, ?]] = - new CoproductCoflatMap[F, G] { - implicit def F: CoflatMap[F] = F0 - - implicit def G: CoflatMap[G] = G0 - } -} - -private[data] sealed abstract class CoproductInstances0 extends CoproductInstances1 { - implicit def catsDataTraverseForCoproduct[F[_], G[_]](implicit F0: Traverse[F], G0: Traverse[G]): Traverse[Coproduct[F, G, ?]] = - new CoproductTraverse[F, G] { - implicit def F: Traverse[F] = F0 - - implicit def G: Traverse[G] = G0 - } -} - -private[data] sealed abstract class CoproductInstances extends CoproductInstances0 { - - implicit def catsDataComonadForCoproduct[F[_], G[_]](implicit F0: Comonad[F], G0: Comonad[G]): Comonad[Coproduct[F, G, ?]] = - new CoproductComonad[F, G] { - implicit def F: Comonad[F] = F0 - - implicit def G: Comonad[G] = G0 - } -} - -private[data] trait CoproductFunctor[F[_], G[_]] extends Functor[Coproduct[F, G, ?]] { - implicit def F: Functor[F] - - implicit def G: Functor[G] - - def map[A, B](a: Coproduct[F, G, A])(f: A => B): Coproduct[F, G, B] = - a map f -} - -private[data] trait CoproductContravariant[F[_], G[_]] extends Contravariant[Coproduct[F, G, ?]] { - implicit def F: Contravariant[F] - - implicit def G: Contravariant[G] - - def contramap[A, B](a: Coproduct[F, G, A])(f: B => A): Coproduct[F, G, B] = - a contramap f -} - -private[data] trait CoproductFoldable[F[_], G[_]] extends Foldable[Coproduct[F, G, ?]] { - implicit def F: Foldable[F] - - implicit def G: Foldable[G] - - def foldRight[A, B](fa: Coproduct[F, G, A], z: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - fa.foldRight(z)(f) - - def foldLeft[A, B](fa: Coproduct[F, G, A], z: B)(f: (B, A) => B): B = - fa.foldLeft(z)(f) - - override def foldMap[A, B](fa: Coproduct[F, G, A])(f: A => B)(implicit M: Monoid[B]): B = - fa foldMap f -} - -private[data] trait CoproductTraverse[F[_], G[_]] extends CoproductFoldable[F, G] with Traverse[Coproduct[F, G, ?]] { - implicit def F: Traverse[F] - - implicit def G: Traverse[G] - - override def map[A, B](a: Coproduct[F, G, A])(f: A => B): Coproduct[F, G, B] = - a map f - - override def traverse[X[_] : Applicative, A, B](fa: Coproduct[F, G, A])(f: A => X[B]): X[Coproduct[F, G, B]] = - fa traverse f -} - -private[data] trait CoproductCoflatMap[F[_], G[_]] extends CoflatMap[Coproduct[F, G, ?]] { - implicit def F: CoflatMap[F] - - implicit def G: CoflatMap[G] - - def map[A, B](a: Coproduct[F, G, A])(f: A => B): Coproduct[F, G, B] = - a map f - - def coflatMap[A, B](a: Coproduct[F, G, A])(f: Coproduct[F, G, A] => B): Coproduct[F, G, B] = - a coflatMap f - - override def coflatten[A](fa: Coproduct[F, G, A]): Coproduct[F, G, Coproduct[F, G, A]] = - fa.coflatten -} - -private[data] trait CoproductComonad[F[_], G[_]] extends Comonad[Coproduct[F, G, ?]] with CoproductCoflatMap[F, G] { - implicit def F: Comonad[F] - - implicit def G: Comonad[G] - - def extract[A](p: Coproduct[F, G, A]): A = - p.extract -} - diff --git a/core/src/main/scala/cats/data/EitherK.scala b/core/src/main/scala/cats/data/EitherK.scala new file mode 100644 index 0000000000..31b5bbd582 --- /dev/null +++ b/core/src/main/scala/cats/data/EitherK.scala @@ -0,0 +1,231 @@ +package cats +package data + +import cats.arrow.FunctionK +import cats.functor.Contravariant +import cats.syntax.either._ + +/** `F` on the left and `G` on the right of [[scala.util.Either]]. + * + * @param run The underlying [[scala.util.Either]]. + */ +final case class EitherK[F[_], G[_], A](run: Either[F[A], G[A]]) { + + import EitherK._ + + def map[B](f: A => B)(implicit F: Functor[F], G: Functor[G]): EitherK[F, G, B] = + EitherK(run.bimap(F.lift(f), G.lift(f))) + + def coflatMap[B](f: EitherK[F, G, A] => B)(implicit F: CoflatMap[F], G: CoflatMap[G]): EitherK[F, G, B] = + EitherK( + run.bimap(a => F.coflatMap(a)(x => f(leftc(x))), a => G.coflatMap(a)(x => f(rightc(x)))) + ) + + def coflatten(implicit F: CoflatMap[F], G: CoflatMap[G]): EitherK[F, G, EitherK[F, G, A]] = + EitherK(run.bimap( + x => F.coflatMap(x)(a => leftc(a)) + , x => G.coflatMap(x)(a => rightc(a))) + ) + + def extract(implicit F: Comonad[F], G: Comonad[G]): A = + run.fold(F.extract, G.extract) + + def contramap[B](f: B => A)(implicit F: Contravariant[F], G: Contravariant[G]): EitherK[F, G, B] = + EitherK(run.bimap(F.contramap(_)(f), G.contramap(_)(f))) + + def foldRight[B](z: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F], G: Foldable[G]): Eval[B] = + run.fold(a => F.foldRight(a, z)(f), a => G.foldRight(a, z)(f)) + + def foldLeft[B](z: B)(f: (B, A) => B)(implicit F: Foldable[F], G: Foldable[G]): B = + run.fold(a => F.foldLeft(a, z)(f), a => G.foldLeft(a, z)(f)) + + def foldMap[B](f: A => B)(implicit F: Foldable[F], G: Foldable[G], M: Monoid[B]): B = + run.fold(F.foldMap(_)(f), G.foldMap(_)(f)) + + def traverse[X[_], B](g: A => X[B])(implicit F: Traverse[F], G: Traverse[G], A: Applicative[X]): X[EitherK[F, G, B]] = + run.fold( + x => A.map(F.traverse(x)(g))(leftc(_)) + , x => A.map(G.traverse(x)(g))(rightc(_)) + ) + + def isLeft: Boolean = + run.isLeft + + def isRight: Boolean = + run.isRight + + def swap: EitherK[G, F, A] = + EitherK(run.swap) + + def toValidated: Validated[F[A], G[A]] = + run.toValidated + + /** + * Fold this eitherK into a new type constructor using two natural transformations. + * + * Example: + * {{{ + * scala> import cats.arrow.FunctionK + * scala> import cats.data.EitherK + * scala> val listToOption = λ[FunctionK[List, Option]](_.headOption) + * scala> val optionToOption = FunctionK.id[Option] + * scala> val cp1: EitherK[List, Option, Int] = EitherK.leftc(List(1,2,3)) + * scala> val cp2: EitherK[List, Option, Int] = EitherK.rightc(Some(4)) + * scala> cp1.fold(listToOption, optionToOption) + * res0: Option[Int] = Some(1) + * scala> cp2.fold(listToOption, optionToOption) + * res1: Option[Int] = Some(4) + * }}} + */ + def fold[H[_]](f: FunctionK[F, H], g: FunctionK[G, H]): H[A] = + run.fold(f.apply, g.apply) +} + +object EitherK extends EitherKInstances { + + def leftc[F[_], G[_], A](x: F[A]): EitherK[F, G, A] = + EitherK(Left(x)) + + def rightc[F[_], G[_], A](x: G[A]): EitherK[F, G, A] = + EitherK(Right(x)) + + final class EitherKLeft[G[_]] private[EitherK] { + def apply[F[_], A](fa: F[A]): EitherK[F, G, A] = EitherK(Left(fa)) + } + + final class EitherKRight[F[_]] private[EitherK] { + def apply[G[_], A](ga: G[A]): EitherK[F, G, A] = EitherK(Right(ga)) + } + + def left[G[_]]: EitherKLeft[G] = new EitherKLeft[G] + + def right[F[_]]: EitherKRight[F] = new EitherKRight[F] +} + +private[data] sealed abstract class EitherKInstances3 { + + implicit def catsDataEqForEitherK[F[_], G[_], A](implicit E: Eq[Either[F[A], G[A]]]): Eq[EitherK[F, G, A]] = + Eq.by(_.run) + + implicit def catsDataFunctorForEitherK[F[_], G[_]](implicit F0: Functor[F], G0: Functor[G]): Functor[EitherK[F, G, ?]] = + new EitherKFunctor[F, G] { + implicit def F: Functor[F] = F0 + + implicit def G: Functor[G] = G0 + } + + implicit def catsDataFoldableForEitherK[F[_], G[_]](implicit F0: Foldable[F], G0: Foldable[G]): Foldable[EitherK[F, G, ?]] = + new EitherKFoldable[F, G] { + implicit def F: Foldable[F] = F0 + + implicit def G: Foldable[G] = G0 + } +} + +private[data] sealed abstract class EitherKInstances2 extends EitherKInstances3 { + + implicit def catsDataContravariantForEitherK[F[_], G[_]](implicit F0: Contravariant[F], G0: Contravariant[G]): Contravariant[EitherK[F, G, ?]] = + new EitherKContravariant[F, G] { + implicit def F: Contravariant[F] = F0 + + implicit def G: Contravariant[G] = G0 + } +} + +private[data] sealed abstract class EitherKInstances1 extends EitherKInstances2 { + implicit def catsDataCoflatMapForEitherK[F[_], G[_]](implicit F0: CoflatMap[F], G0: CoflatMap[G]): CoflatMap[EitherK[F, G, ?]] = + new EitherKCoflatMap[F, G] { + implicit def F: CoflatMap[F] = F0 + + implicit def G: CoflatMap[G] = G0 + } +} + +private[data] sealed abstract class EitherKInstances0 extends EitherKInstances1 { + implicit def catsDataTraverseForEitherK[F[_], G[_]](implicit F0: Traverse[F], G0: Traverse[G]): Traverse[EitherK[F, G, ?]] = + new EitherKTraverse[F, G] { + implicit def F: Traverse[F] = F0 + + implicit def G: Traverse[G] = G0 + } +} + +private[data] sealed abstract class EitherKInstances extends EitherKInstances0 { + + implicit def catsDataComonadForEitherK[F[_], G[_]](implicit F0: Comonad[F], G0: Comonad[G]): Comonad[EitherK[F, G, ?]] = + new EitherKComonad[F, G] { + implicit def F: Comonad[F] = F0 + + implicit def G: Comonad[G] = G0 + } +} + +private[data] trait EitherKFunctor[F[_], G[_]] extends Functor[EitherK[F, G, ?]] { + implicit def F: Functor[F] + + implicit def G: Functor[G] + + def map[A, B](a: EitherK[F, G, A])(f: A => B): EitherK[F, G, B] = + a map f +} + +private[data] trait EitherKContravariant[F[_], G[_]] extends Contravariant[EitherK[F, G, ?]] { + implicit def F: Contravariant[F] + + implicit def G: Contravariant[G] + + def contramap[A, B](a: EitherK[F, G, A])(f: B => A): EitherK[F, G, B] = + a contramap f +} + +private[data] trait EitherKFoldable[F[_], G[_]] extends Foldable[EitherK[F, G, ?]] { + implicit def F: Foldable[F] + + implicit def G: Foldable[G] + + def foldRight[A, B](fa: EitherK[F, G, A], z: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + fa.foldRight(z)(f) + + def foldLeft[A, B](fa: EitherK[F, G, A], z: B)(f: (B, A) => B): B = + fa.foldLeft(z)(f) + + override def foldMap[A, B](fa: EitherK[F, G, A])(f: A => B)(implicit M: Monoid[B]): B = + fa foldMap f +} + +private[data] trait EitherKTraverse[F[_], G[_]] extends EitherKFoldable[F, G] with Traverse[EitherK[F, G, ?]] { + implicit def F: Traverse[F] + + implicit def G: Traverse[G] + + override def map[A, B](a: EitherK[F, G, A])(f: A => B): EitherK[F, G, B] = + a map f + + override def traverse[X[_] : Applicative, A, B](fa: EitherK[F, G, A])(f: A => X[B]): X[EitherK[F, G, B]] = + fa traverse f +} + +private[data] trait EitherKCoflatMap[F[_], G[_]] extends CoflatMap[EitherK[F, G, ?]] { + implicit def F: CoflatMap[F] + + implicit def G: CoflatMap[G] + + def map[A, B](a: EitherK[F, G, A])(f: A => B): EitherK[F, G, B] = + a map f + + def coflatMap[A, B](a: EitherK[F, G, A])(f: EitherK[F, G, A] => B): EitherK[F, G, B] = + a coflatMap f + + override def coflatten[A](fa: EitherK[F, G, A]): EitherK[F, G, EitherK[F, G, A]] = + fa.coflatten +} + +private[data] trait EitherKComonad[F[_], G[_]] extends Comonad[EitherK[F, G, ?]] with EitherKCoflatMap[F, G] { + implicit def F: Comonad[F] + + implicit def G: Comonad[G] + + def extract[A](p: EitherK[F, G, A]): A = + p.extract +} + diff --git a/core/src/main/scala/cats/data/Func.scala b/core/src/main/scala/cats/data/Func.scala index 9594bcc844..0f3535aa06 100644 --- a/core/src/main/scala/cats/data/Func.scala +++ b/core/src/main/scala/cats/data/Func.scala @@ -91,12 +91,12 @@ private[data] sealed trait FuncApplicative[F[_], C] extends Applicative[λ[α => sealed abstract class AppFunc[F[_], A, B] extends Func[F, A, B] { self => def F: Applicative[F] - def product[G[_]](g: AppFunc[G, A, B]): AppFunc[λ[α => Prod[F, G, α]], A, B] = + def product[G[_]](g: AppFunc[G, A, B]): AppFunc[λ[α => Tuple2K[F, G, α]], A, B] = { implicit val FF: Applicative[F] = self.F implicit val GG: Applicative[G] = g.F - Func.appFunc[λ[α => Prod[F, G, α]], A, B]{ - a: A => Prod(self.run(a), g.run(a)) + Func.appFunc[λ[α => Tuple2K[F, G, α]], A, B]{ + a: A => Tuple2K(self.run(a), g.run(a)) } } diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index fc5fb50873..2d25b3bf85 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -3,7 +3,7 @@ package data import cats.functor._ -/** Similar to [[cats.data.Prod]], but for nested composition. +/** Similar to [[cats.data.Tuple2K]], 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 diff --git a/core/src/main/scala/cats/data/Prod.scala b/core/src/main/scala/cats/data/Prod.scala deleted file mode 100644 index 0179ec012d..0000000000 --- a/core/src/main/scala/cats/data/Prod.scala +++ /dev/null @@ -1,185 +0,0 @@ -package cats -package data - -import cats.functor.Contravariant -import cats.syntax.cartesian._ - -/** - * [[Prod]] is a product to two independent functor values. - * - * See: [[https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf The Essence of the Iterator Pattern]] - */ -final case class Prod[F[_], G[_], A](first: F[A], second: G[A]) - -object Prod extends ProdInstances - -private[data] sealed abstract class ProdInstances extends ProdInstances0 { - implicit def catsDataMonadCombineForProd[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Prod[F, G, α]]] = new ProdMonadCombine[F, G] { - def F: MonadCombine[F] = FF - def G: MonadCombine[G] = GF - } - implicit def catsDataOrderForProd[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Prod[F, G, A]] = new ProdOrder[F, G, A] { - def F: Order[F[A]] = FF - def G: Order[G[A]] = GF - } - implicit def catsDataShowForProd[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Prod[F, G, A]] = new ProdShow[F, G, A] { - def F: Show[F[A]] = FF - def G: Show[G[A]] = GF - } - implicit def catsDataContravariantForProd[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Prod[F, G, α]]] = new ProdContravariant[F, G] { - def F: Contravariant[F] = FC - def G: Contravariant[G] = GC - } -} - -private[data] sealed abstract class ProdInstances0 extends ProdInstances1 { - implicit def catsDataTraverseForProd[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Prod[F, G, α]]] = new ProdTraverse[F, G] { - def F: Traverse[F] = FF - def G: Traverse[G] = GF - } - implicit def catsDataAlternativeForProd[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Prod[F, G, α]]] = new ProdAlternative[F, G] { - def F: Alternative[F] = FF - def G: Alternative[G] = GG - } - implicit def catsDataMonadForProd[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Prod[F, G, α]]] = new ProdMonad[F, G] { - def F: Monad[F] = FM - def G: Monad[G] = GM - } - implicit def catsDataEqForProd[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Prod[F, G, A]] = new Eq[Prod[F, G, A]] { - def eqv(x: Prod[F, G, A], y: Prod[F, G, A]): Boolean = - FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) - } -} - -private[data] sealed abstract class ProdInstances1 extends ProdInstances2 { - implicit def catsDataFoldableForProd[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Prod[F, G, α]]] = new ProdFoldable[F, G] { - def F: Foldable[F] = FF - def G: Foldable[G] = GF - } - implicit def catsDataMonoidKForProd[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G]): MonoidK[λ[α => Prod[F, G, α]]] = new ProdMonoidK[F, G] { - def F: MonoidK[F] = FF - def G: MonoidK[G] = GG - } - implicit def catsDataApplicativeForProd[F[_], G[_]](implicit FF: Applicative[F], GG: Applicative[G]): Applicative[λ[α => Prod[F, G, α]]] = new ProdApplicative[F, G] { - def F: Applicative[F] = FF - def G: Applicative[G] = GG - } -} - -private[data] sealed abstract class ProdInstances2 extends ProdInstances3 { - implicit def catsDataSemigroupKForProd[F[_], G[_]](implicit FF: SemigroupK[F], GG: SemigroupK[G]): SemigroupK[λ[α => Prod[F, G, α]]] = new ProdSemigroupK[F, G] { - def F: SemigroupK[F] = FF - def G: SemigroupK[G] = GG - } - implicit def catsDataApplyForProd[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[λ[α => Prod[F, G, α]]] = new ProdApply[F, G] { - def F: Apply[F] = FF - def G: Apply[G] = GG - } -} - -private[data] sealed abstract class ProdInstances3 { - implicit def catsDataFunctorForProd[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Prod[F, G, α]]] = new ProdFunctor[F, G] { - def F: Functor[F] = FF - def G: Functor[G] = GG - } -} - -private[data] sealed trait ProdFunctor[F[_], G[_]] extends Functor[λ[α => Prod[F, G, α]]] { - def F: Functor[F] - def G: Functor[G] - override def map[A, B](fa: Prod[F, G, A])(f: A => B): Prod[F, G, B] = Prod(F.map(fa.first)(f), G.map(fa.second)(f)) -} - -private[data] sealed trait ProdContravariant[F[_], G[_]] extends Contravariant[λ[α => Prod[F, G, α]]] { - def F: Contravariant[F] - def G: Contravariant[G] - def contramap[A, B](fa: Prod[F, G, A])(f: B => A): Prod[F, G, B] = Prod(F.contramap(fa.first)(f), G.contramap(fa.second)(f)) -} - -private[data] sealed trait ProdApply[F[_], G[_]] extends Apply[λ[α => Prod[F, G, α]]] with ProdFunctor[F, G] { - def F: Apply[F] - def G: Apply[G] - override def ap[A, B](f: Prod[F, G, A => B])(fa: Prod[F, G, A]): Prod[F, G, B] = - Prod(F.ap(f.first)(fa.first), G.ap(f.second)(fa.second)) - override def product[A, B](fa: Prod[F, G, A], fb: Prod[F, G, B]): Prod[F, G, (A, B)] = - Prod(F.product(fa.first, fb.first), G.product(fa.second, fb.second)) -} - -private[data] sealed trait ProdApplicative[F[_], G[_]] extends Applicative[λ[α => Prod[F, G, α]]] with ProdApply[F, G] { - def F: Applicative[F] - def G: Applicative[G] - def pure[A](a: A): Prod[F, G, A] = Prod(F.pure(a), G.pure(a)) -} - -private[data] sealed trait ProdSemigroupK[F[_], G[_]] extends SemigroupK[λ[α => Prod[F, G, α]]] { - def F: SemigroupK[F] - def G: SemigroupK[G] - override def combineK[A](x: Prod[F, G, A], y: Prod[F, G, A]): Prod[F, G, A] = - Prod(F.combineK(x.first, y.first), G.combineK(x.second, y.second)) -} - -private[data] sealed trait ProdMonoidK[F[_], G[_]] extends MonoidK[λ[α => Prod[F, G, α]]] with ProdSemigroupK[F, G] { - def F: MonoidK[F] - def G: MonoidK[G] - override def empty[A]: Prod[F, G, A] = - Prod(F.empty[A], G.empty[A]) -} - -private[data] sealed trait ProdAlternative[F[_], G[_]] extends Alternative[λ[α => Prod[F, G, α]]] - with ProdApplicative[F, G] with ProdMonoidK[F, G] { - def F: Alternative[F] - def G: Alternative[G] -} - -private[data] sealed trait ProdMonad[F[_], G[_]] extends Monad[λ[α => Prod[F, G, α]]] with ProdApplicative[F, G] { - def F: Monad[F] - def G: Monad[G] - override def pure[A](a: A): Prod[F, G, A] = - Prod(F.pure(a), G.pure(a)) - - override def flatMap[A, B](p: Prod[F, G, A])(f: A => Prod[F, G, B]): Prod[F, G, B] = - Prod(F.flatMap(p.first)(f(_).first), G.flatMap(p.second)(f(_).second)) - - def tailRecM[A, B](a: A)(f: A => Prod[F, G, Either[A, B]]): Prod[F, G, B] = - Prod(F.tailRecM(a)(f(_).first), G.tailRecM(a)(f(_).second)) -} - -private[data] sealed trait ProdFoldable[F[_], G[_]] extends Foldable[λ[α => Prod[F, G, α]]] { - def F: Foldable[F] - def G: Foldable[G] - - override def foldLeft[A, B](fa: Prod[F, G, A], b: B)(f: (B, A) => B): B = - G.foldLeft(fa.second, F.foldLeft(fa.first, b)(f))(f) - - override def foldRight[A, B](fa: Prod[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - F.foldRight(fa.first, G.foldRight(fa.second, lb)(f))(f) -} - -private[data] sealed trait ProdTraverse[F[_], G[_]] extends Traverse[λ[α => Prod[F, G, α]]] with ProdFoldable[F, G] { - def F: Traverse[F] - def G: Traverse[G] - - override def traverse[H[_]: Applicative, A, B](fa: Prod[F, G, A])(f: A => H[B]): H[Prod[F, G, B]] = - (F.traverse(fa.first)(f) |@| G.traverse(fa.second)(f)).map(Prod(_, _)) -} - -private[data] sealed trait ProdMonadCombine[F[_], G[_]] extends MonadCombine[λ[α => Prod[F, G, α]]] - with ProdMonad[F, G] with ProdAlternative[F, G] { - def F: MonadCombine[F] - def G: MonadCombine[G] -} - -private[data] sealed trait ProdShow[F[_], G[_], A] extends Show[Prod[F, G, A]] { - def F: Show[F[A]] - def G: Show[G[A]] - - def show(prod: Prod[F, G, A]): String = s"Prod(${F.show(prod.first)}, ${G.show(prod.second)})" -} - -private[data] sealed trait ProdOrder[F[_], G[_], A] extends Order[Prod[F, G, A]] { - def F: Order[F[A]] - def G: Order[G[A]] - - def compare(x: Prod[F, G, A], y: Prod[F, G, A]): Int = - Array(F.compare(x.first, y.first), G.compare(x.second, y.second)).find(_ != 0).getOrElse(0) -} diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala new file mode 100644 index 0000000000..7543da0172 --- /dev/null +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -0,0 +1,185 @@ +package cats +package data + +import cats.functor.Contravariant +import cats.syntax.cartesian._ + +/** + * [[Tuple2K]] is a product to two independent functor values. + * + * See: [[https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf The Essence of the Iterator Pattern]] + */ +final case class Tuple2K[F[_], G[_], A](first: F[A], second: G[A]) + +object Tuple2K extends Tuple2KInstances + +private[data] sealed abstract class Tuple2KInstances extends Tuple2KInstances0 { + implicit def catsDataMonadCombineForTuple2K[F[_], G[_]](implicit FF: MonadCombine[F], GF: MonadCombine[G]): MonadCombine[λ[α => Tuple2K[F, G, α]]] = new Tuple2KMonadCombine[F, G] { + def F: MonadCombine[F] = FF + def G: MonadCombine[G] = GF + } + implicit def catsDataOrderForTuple2K[F[_], G[_], A](implicit FF: Order[F[A]], GF: Order[G[A]]): Order[Tuple2K[F, G, A]] = new Tuple2KOrder[F, G, A] { + def F: Order[F[A]] = FF + def G: Order[G[A]] = GF + } + implicit def catsDataShowForTuple2K[F[_], G[_], A](implicit FF: Show[F[A]], GF: Show[G[A]]): Show[Tuple2K[F, G, A]] = new Tuple2KShow[F, G, A] { + def F: Show[F[A]] = FF + def G: Show[G[A]] = GF + } + implicit def catsDataContravariantForTuple2K[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Tuple2K[F, G, α]]] = new Tuple2KContravariant[F, G] { + def F: Contravariant[F] = FC + def G: Contravariant[G] = GC + } +} + +private[data] sealed abstract class Tuple2KInstances0 extends Tuple2KInstances1 { + implicit def catsDataTraverseForTuple2K[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Tuple2K[F, G, α]]] = new Tuple2KTraverse[F, G] { + def F: Traverse[F] = FF + def G: Traverse[G] = GF + } + implicit def catsDataAlternativeForTuple2K[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[λ[α => Tuple2K[F, G, α]]] = new Tuple2KAlternative[F, G] { + def F: Alternative[F] = FF + def G: Alternative[G] = GG + } + implicit def catsDataMonadForTuple2K[F[_], G[_]](implicit FM: Monad[F], GM: Monad[G]): Monad[λ[α => Tuple2K[F, G, α]]] = new Tuple2KMonad[F, G] { + def F: Monad[F] = FM + def G: Monad[G] = GM + } + implicit def catsDataEqForTuple2K[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Tuple2K[F, G, A]] = new Eq[Tuple2K[F, G, A]] { + def eqv(x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Boolean = + FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second) + } +} + +private[data] sealed abstract class Tuple2KInstances1 extends Tuple2KInstances2 { + implicit def catsDataFoldableForTuple2K[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G]): Foldable[λ[α => Tuple2K[F, G, α]]] = new Tuple2KFoldable[F, G] { + def F: Foldable[F] = FF + def G: Foldable[G] = GF + } + implicit def catsDataMonoidKForTuple2K[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G]): MonoidK[λ[α => Tuple2K[F, G, α]]] = new Tuple2KMonoidK[F, G] { + def F: MonoidK[F] = FF + def G: MonoidK[G] = GG + } + implicit def catsDataApplicativeForTuple2K[F[_], G[_]](implicit FF: Applicative[F], GG: Applicative[G]): Applicative[λ[α => Tuple2K[F, G, α]]] = new Tuple2KApplicative[F, G] { + def F: Applicative[F] = FF + def G: Applicative[G] = GG + } +} + +private[data] sealed abstract class Tuple2KInstances2 extends Tuple2KInstances3 { + implicit def catsDataSemigroupKForTuple2K[F[_], G[_]](implicit FF: SemigroupK[F], GG: SemigroupK[G]): SemigroupK[λ[α => Tuple2K[F, G, α]]] = new Tuple2KSemigroupK[F, G] { + def F: SemigroupK[F] = FF + def G: SemigroupK[G] = GG + } + implicit def catsDataApplyForTuple2K[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[λ[α => Tuple2K[F, G, α]]] = new Tuple2KApply[F, G] { + def F: Apply[F] = FF + def G: Apply[G] = GG + } +} + +private[data] sealed abstract class Tuple2KInstances3 { + implicit def catsDataFunctorForTuple2K[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Tuple2K[F, G, α]]] = new Tuple2KFunctor[F, G] { + def F: Functor[F] = FF + def G: Functor[G] = GG + } +} + +private[data] sealed trait Tuple2KFunctor[F[_], G[_]] extends Functor[λ[α => Tuple2K[F, G, α]]] { + def F: Functor[F] + def G: Functor[G] + override def map[A, B](fa: Tuple2K[F, G, A])(f: A => B): Tuple2K[F, G, B] = Tuple2K(F.map(fa.first)(f), G.map(fa.second)(f)) +} + +private[data] sealed trait Tuple2KContravariant[F[_], G[_]] extends Contravariant[λ[α => Tuple2K[F, G, α]]] { + def F: Contravariant[F] + def G: Contravariant[G] + def contramap[A, B](fa: Tuple2K[F, G, A])(f: B => A): Tuple2K[F, G, B] = Tuple2K(F.contramap(fa.first)(f), G.contramap(fa.second)(f)) +} + +private[data] sealed trait Tuple2KApply[F[_], G[_]] extends Apply[λ[α => Tuple2K[F, G, α]]] with Tuple2KFunctor[F, G] { + def F: Apply[F] + def G: Apply[G] + override def ap[A, B](f: Tuple2K[F, G, A => B])(fa: Tuple2K[F, G, A]): Tuple2K[F, G, B] = + Tuple2K(F.ap(f.first)(fa.first), G.ap(f.second)(fa.second)) + override def product[A, B](fa: Tuple2K[F, G, A], fb: Tuple2K[F, G, B]): Tuple2K[F, G, (A, B)] = + Tuple2K(F.product(fa.first, fb.first), G.product(fa.second, fb.second)) +} + +private[data] sealed trait Tuple2KApplicative[F[_], G[_]] extends Applicative[λ[α => Tuple2K[F, G, α]]] with Tuple2KApply[F, G] { + def F: Applicative[F] + def G: Applicative[G] + def pure[A](a: A): Tuple2K[F, G, A] = Tuple2K(F.pure(a), G.pure(a)) +} + +private[data] sealed trait Tuple2KSemigroupK[F[_], G[_]] extends SemigroupK[λ[α => Tuple2K[F, G, α]]] { + def F: SemigroupK[F] + def G: SemigroupK[G] + override def combineK[A](x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Tuple2K[F, G, A] = + Tuple2K(F.combineK(x.first, y.first), G.combineK(x.second, y.second)) +} + +private[data] sealed trait Tuple2KMonoidK[F[_], G[_]] extends MonoidK[λ[α => Tuple2K[F, G, α]]] with Tuple2KSemigroupK[F, G] { + def F: MonoidK[F] + def G: MonoidK[G] + override def empty[A]: Tuple2K[F, G, A] = + Tuple2K(F.empty[A], G.empty[A]) +} + +private[data] sealed trait Tuple2KAlternative[F[_], G[_]] extends Alternative[λ[α => Tuple2K[F, G, α]]] + with Tuple2KApplicative[F, G] with Tuple2KMonoidK[F, G] { + def F: Alternative[F] + def G: Alternative[G] +} + +private[data] sealed trait Tuple2KMonad[F[_], G[_]] extends Monad[λ[α => Tuple2K[F, G, α]]] with Tuple2KApplicative[F, G] { + def F: Monad[F] + def G: Monad[G] + override def pure[A](a: A): Tuple2K[F, G, A] = + Tuple2K(F.pure(a), G.pure(a)) + + override def flatMap[A, B](p: Tuple2K[F, G, A])(f: A => Tuple2K[F, G, B]): Tuple2K[F, G, B] = + Tuple2K(F.flatMap(p.first)(f(_).first), G.flatMap(p.second)(f(_).second)) + + def tailRecM[A, B](a: A)(f: A => Tuple2K[F, G, Either[A, B]]): Tuple2K[F, G, B] = + Tuple2K(F.tailRecM(a)(f(_).first), G.tailRecM(a)(f(_).second)) +} + +private[data] sealed trait Tuple2KFoldable[F[_], G[_]] extends Foldable[λ[α => Tuple2K[F, G, α]]] { + def F: Foldable[F] + def G: Foldable[G] + + override def foldLeft[A, B](fa: Tuple2K[F, G, A], b: B)(f: (B, A) => B): B = + G.foldLeft(fa.second, F.foldLeft(fa.first, b)(f))(f) + + override def foldRight[A, B](fa: Tuple2K[F, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + F.foldRight(fa.first, G.foldRight(fa.second, lb)(f))(f) +} + +private[data] sealed trait Tuple2KTraverse[F[_], G[_]] extends Traverse[λ[α => Tuple2K[F, G, α]]] with Tuple2KFoldable[F, G] { + def F: Traverse[F] + def G: Traverse[G] + + override def traverse[H[_]: Applicative, A, B](fa: Tuple2K[F, G, A])(f: A => H[B]): H[Tuple2K[F, G, B]] = + (F.traverse(fa.first)(f) |@| G.traverse(fa.second)(f)).map(Tuple2K(_, _)) +} + +private[data] sealed trait Tuple2KMonadCombine[F[_], G[_]] extends MonadCombine[λ[α => Tuple2K[F, G, α]]] + with Tuple2KMonad[F, G] with Tuple2KAlternative[F, G] { + def F: MonadCombine[F] + def G: MonadCombine[G] +} + +private[data] sealed trait Tuple2KShow[F[_], G[_], A] extends Show[Tuple2K[F, G, A]] { + def F: Show[F[A]] + def G: Show[G[A]] + + def show(tuple: Tuple2K[F, G, A]): String = s"Tuple2K(${F.show(tuple.first)}, ${G.show(tuple.second)})" +} + +private[data] sealed trait Tuple2KOrder[F[_], G[_], A] extends Order[Tuple2K[F, G, A]] { + def F: Order[F[A]] + def G: Order[G[A]] + + def compare(x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Int = + Array(F.compare(x.first, y.first), G.compare(x.second, y.second)).find(_ != 0).getOrElse(0) +} diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index ec98e2a6e3..6cc6c6e4d4 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -13,7 +13,7 @@ trait AllSyntax with ComonadSyntax with ComposeSyntax with ContravariantSyntax - with CoproductSyntax + with EitherKSyntax with EitherSyntax with EqSyntax with FlatMapSyntax diff --git a/core/src/main/scala/cats/syntax/coproduct.scala b/core/src/main/scala/cats/syntax/coproduct.scala deleted file mode 100644 index af6b45760a..0000000000 --- a/core/src/main/scala/cats/syntax/coproduct.scala +++ /dev/null @@ -1,43 +0,0 @@ -package cats -package syntax - -import cats.data.Coproduct - -trait CoproductSyntax { - implicit def catsSyntaxCoproduct[F[_], A](a: F[A]): CoproductOps[F, A] = new CoproductOps(a) -} - -final class CoproductOps[F[_], A](val fa: F[A]) extends AnyVal { - - /** - * Lift an `F[A]` into a `Coproduct[F, G, A]` for any type constructor `G[_]`. - * - * @see [[rightc]] to swap the order of `F` and `G` in the result type. - * - * Example: - * {{{ - * scala> import cats.data.Coproduct - * scala> import cats.Eval - * scala> import cats.implicits._ - * scala> List(1, 2, 3).leftc[Eval] - * res0: Coproduct[List, Eval, Int] = Coproduct(Left(List(1, 2, 3))) - * }}} - */ - def leftc[G[_]]: Coproduct[F, G, A] = Coproduct.leftc(fa) - - /** - * Lift an `F[A]` into a `Coproduct[G, F, A]` for any type constructor `G[_]`. - * - * @see [[leftc]] to swap the order of `F` and `G` in the result type. - * - * Example: - * {{{ - * scala> import cats.data.Coproduct - * scala> import cats.Eval - * scala> import cats.implicits._ - * scala> List(1, 2, 3).rightc[Eval] - * res0: Coproduct[Eval, List, Int] = Coproduct(Right(List(1, 2, 3))) - * }}} - */ - def rightc[G[_]]: Coproduct[G, F, A] = Coproduct.rightc(fa) -} diff --git a/core/src/main/scala/cats/syntax/eitherK.scala b/core/src/main/scala/cats/syntax/eitherK.scala new file mode 100644 index 0000000000..574b18b5c6 --- /dev/null +++ b/core/src/main/scala/cats/syntax/eitherK.scala @@ -0,0 +1,43 @@ +package cats +package syntax + +import cats.data.EitherK + +trait EitherKSyntax { + implicit def catsSyntaxEitherK[F[_], A](a: F[A]): EitherKOps[F, A] = new EitherKOps(a) +} + +final class EitherKOps[F[_], A](val fa: F[A]) extends AnyVal { + + /** + * Lift an `F[A]` into a `EitherK[F, G, A]` for any type constructor `G[_]`. + * + * @see [[rightc]] to swap the order of `F` and `G` in the result type. + * + * Example: + * {{{ + * scala> import cats.data.EitherK + * scala> import cats.Eval + * scala> import cats.implicits._ + * scala> List(1, 2, 3).leftc[Eval] + * res0: EitherK[List, Eval, Int] = EitherK(Left(List(1, 2, 3))) + * }}} + */ + def leftc[G[_]]: EitherK[F, G, A] = EitherK.leftc(fa) + + /** + * Lift an `F[A]` into a `EitherK[G, F, A]` for any type constructor `G[_]`. + * + * @see [[leftc]] to swap the order of `F` and `G` in the result type. + * + * Example: + * {{{ + * scala> import cats.data.EitherK + * scala> import cats.Eval + * scala> import cats.implicits._ + * scala> List(1, 2, 3).rightc[Eval] + * res0: EitherK[Eval, List, Int] = EitherK(Right(List(1, 2, 3))) + * }}} + */ + def rightc[G[_]]: EitherK[G, F, A] = EitherK.rightc(fa) +} diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index 725c8d7bbd..ed39f39a65 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -10,7 +10,7 @@ package object syntax { object bitraverse extends BitraverseSyntax object cartesian extends CartesianSyntax object coflatMap extends CoflatMapSyntax - object coproduct extends CoproductSyntax + object eitherK extends EitherKSyntax object comonad extends ComonadSyntax object compose extends ComposeSyntax object contravariant extends ContravariantSyntax diff --git a/docs/src/main/tut/datatypes/freeapplicative.md b/docs/src/main/tut/datatypes/freeapplicative.md index f5ec9f9503..fbf7263bbd 100644 --- a/docs/src/main/tut/datatypes/freeapplicative.md +++ b/docs/src/main/tut/datatypes/freeapplicative.md @@ -156,9 +156,9 @@ Therefore, we can write an interpreter that uses the product of the `ParValidato to interpret our program in one go. We can create this interpreter easily by using `FunctionK#and`. ```tut:silent -import cats.data.Prod +import cats.data.Tuple2K -type ValidateAndLog[A] = Prod[ParValidator, Log, A] +type ValidateAndLog[A] = Tuple2K[ParValidator, Log, A] val prodCompiler: FunctionK[ValidationOp, ValidateAndLog] = parCompiler and logCompiler diff --git a/docs/src/main/tut/datatypes/freemonad.md b/docs/src/main/tut/datatypes/freemonad.md index dfdcddc5b8..dc1d0b344f 100644 --- a/docs/src/main/tut/datatypes/freemonad.md +++ b/docs/src/main/tut/datatypes/freemonad.md @@ -301,10 +301,10 @@ Real world applications often time combine different algebras. The `Inject` type class described by Swierstra in [Data types à la carte](http://www.staff.science.uu.nl/~swier004/publications/2008-jfp.pdf) lets us compose different algebras in the context of `Free`. -Let's see a trivial example of unrelated ADT's getting composed as a `Coproduct` that can form a more complex program. +Let's see a trivial example of unrelated ADT's getting composed as a `EitherK` that can form a more complex program. ```tut:silent -import cats.data.Coproduct +import cats.data.EitherK import cats.free.Free import cats.{Id, Inject, ~>} import scala.collection.mutable.ListBuffer @@ -322,10 +322,10 @@ case class AddCat(a: String) extends DataOp[Unit] case class GetAllCats() extends DataOp[List[String]] ``` -Once the ADTs are defined we can formally state that a `Free` program is the Coproduct of it's Algebras. +Once the ADTs are defined we can formally state that a `Free` program is the EitherK of it's Algebras. ```tut:silent -type CatsApp[A] = Coproduct[DataOp, Interact, A] +type CatsApp[A] = EitherK[DataOp, Interact, A] ``` In order to take advantage of monadic composition we use smart constructors to lift our Algebra to the `Free` context. @@ -366,7 +366,7 @@ def program(implicit I : Interacts[CatsApp], D : DataSource[CatsApp]): Free[Cats } ``` -Finally we write one interpreter per ADT and combine them with a `FunctionK` to `Coproduct` so they can be +Finally we write one interpreter per ADT and combine them with a `FunctionK` to `EitherK` so they can be compiled and applied to our `Free` program. ```tut:invisible diff --git a/free/src/main/scala/cats/free/Free.scala b/free/src/main/scala/cats/free/Free.scala index e4e9a8e124..3459bb5e41 100644 --- a/free/src/main/scala/cats/free/Free.scala +++ b/free/src/main/scala/cats/free/Free.scala @@ -140,11 +140,11 @@ sealed abstract class Free[S[_], A] extends Product with Serializable { }(Free.catsFreeMonadForFree) /** - * Lift into `G` (typically a `Coproduct`) given `Inject`. Analogous + * Lift into `G` (typically a `EitherK`) given `Inject`. Analogous * to `Free.inject` but lifts programs rather than constructors. * *{{{ - *scala> type Lo[A] = cats.data.Coproduct[List, Option, A] + *scala> type Lo[A] = cats.data.EitherK[List, Option, A] *defined type alias Lo * *scala> val fo = Free.liftF(Option("foo")) diff --git a/free/src/test/scala/cats/free/FreeTests.scala b/free/src/test/scala/cats/free/FreeTests.scala index 4054805cca..ba34e7f39c 100644 --- a/free/src/test/scala/cats/free/FreeTests.scala +++ b/free/src/test/scala/cats/free/FreeTests.scala @@ -2,7 +2,7 @@ package cats package free import cats.arrow.FunctionK -import cats.data.Coproduct +import cats.data.EitherK import cats.laws.discipline.{CartesianTests, MonadTests, SerializableTests} import cats.laws.discipline.arbitrary.catsLawsArbitraryForFn0 import cats.tests.CatsSuite @@ -141,7 +141,7 @@ class FreeTests extends CatsSuite { Arbitrary(for {s <- seqArb.arbitrary; f <- intAArb.arbitrary} yield Test2(s, f)) } - type T[A] = Coproduct[Test1Algebra, Test2Algebra, A] + type T[A] = EitherK[Test1Algebra, Test2Algebra, A] object Test1Interpreter extends FunctionK[Test1Algebra,Id] { override def apply[A](fa: Test1Algebra[A]): Id[A] = fa match { @@ -155,7 +155,7 @@ class FreeTests extends CatsSuite { } } - val coProductInterpreter: FunctionK[T,Id] = Test1Interpreter or Test2Interpreter + val eitherKInterpreter: FunctionK[T,Id] = Test1Interpreter or Test2Interpreter test(".inject") { forAll { (x: Int, y: Int) => @@ -167,7 +167,7 @@ class FreeTests extends CatsSuite { b <- Free.inject[Test2Algebra, F](Test2(y, identity)) } yield a + b } - (res[T] foldMap coProductInterpreter) == (x + y) should ===(true) + (res[T] foldMap eitherKInterpreter) == (x + y) should ===(true) } } diff --git a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala index 039a76fc35..88bbba8167 100644 --- a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala +++ b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala @@ -103,8 +103,8 @@ object arbitrary extends ArbitraryInstances0 { implicit def catsLawsCogenForEval[A: Cogen]: Cogen[Eval[A]] = Cogen[A].contramap(_.value) - implicit def catsLawsArbitraryForProd[F[_], G[_], A](implicit F: Arbitrary[F[A]], G: Arbitrary[G[A]]): Arbitrary[Prod[F, G, A]] = - Arbitrary(F.arbitrary.flatMap(fa => G.arbitrary.map(ga => Prod[F, G, A](fa, ga)))) + implicit def catsLawsArbitraryForTuple2K[F[_], G[_], A](implicit F: Arbitrary[F[A]], G: Arbitrary[G[A]]): Arbitrary[Tuple2K[F, G, A]] = + Arbitrary(F.arbitrary.flatMap(fa => G.arbitrary.map(ga => Tuple2K[F, G, A](fa, ga)))) implicit def catsLawsArbitraryForFunc[F[_], A, B](implicit F: Arbitrary[F[B]]): Arbitrary[Func[F, A, B]] = Arbitrary(F.arbitrary.map(fb => Func.func[F, A, B](_ => fb))) @@ -122,15 +122,15 @@ object arbitrary extends ArbitraryInstances0 { implicit def catsLawsArbitraryForPartialFunction[A, B](implicit F: Arbitrary[A => Option[B]]): Arbitrary[PartialFunction[A, B]] = Arbitrary(F.arbitrary.map(Function.unlift)) - implicit def catsLawsArbitraryForCoproduct[F[_], G[_], A](implicit F: Arbitrary[F[A]], G: Arbitrary[G[A]]): Arbitrary[Coproduct[F, G, A]] = + implicit def catsLawsArbitraryForEitherK[F[_], G[_], A](implicit F: Arbitrary[F[A]], G: Arbitrary[G[A]]): Arbitrary[EitherK[F, G, A]] = Arbitrary(Gen.oneOf( - F.arbitrary.map(Coproduct.leftc[F, G, A]), - G.arbitrary.map(Coproduct.rightc[F, G, A]))) + F.arbitrary.map(EitherK.leftc[F, G, A]), + G.arbitrary.map(EitherK.rightc[F, G, A]))) - implicit def catsLawsCogenForCoproduct[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[Coproduct[F, G, A]] = + implicit def catsLawsCogenForEitherK[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[EitherK[F, G, A]] = Cogen((seed, x) => x.run.fold(F.perturb(seed, _), G.perturb(seed, _))) - implicit def catLawsCogenForProd[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[Prod[F, G, A]] = + implicit def catLawsCogenForTuple2K[F[_], G[_], A](implicit F: Cogen[F[A]], G: Cogen[G[A]]): Cogen[Tuple2K[F, G, A]] = Cogen((seed, t) => F.perturb(G.perturb(seed, t.second), t.first)) implicit def catsLawsArbitraryForShow[A: Arbitrary]: Arbitrary[Show[A]] = diff --git a/tests/src/test/scala/cats/tests/CoproductTests.scala b/tests/src/test/scala/cats/tests/CoproductTests.scala deleted file mode 100644 index 059c687343..0000000000 --- a/tests/src/test/scala/cats/tests/CoproductTests.scala +++ /dev/null @@ -1,61 +0,0 @@ -package cats.tests - -import cats._ -import cats.kernel.laws.OrderLaws -import cats.data.Coproduct -import cats.functor.Contravariant -import cats.laws.discipline._ -import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.eq._ - -class CoproductTests extends CatsSuite { - - checkAll("Coproduct[Option, Option, ?]", TraverseTests[Coproduct[Option, Option, ?]].traverse[Int, Int, Int, Int, Option, Option]) - checkAll("Traverse[Coproduct[Option, Option, ?]]", SerializableTests.serializable(Traverse[Coproduct[Option, Option, ?]])) - - { - implicit val foldable = Coproduct.catsDataFoldableForCoproduct[Option, Option] - checkAll("Coproduct[Option, Option, ?]", FoldableTests[Coproduct[Option, Option, ?]].foldable[Int, Int]) - checkAll("Foldable[Coproduct[Option, Option, ?]]", SerializableTests.serializable(Foldable[Coproduct[Option, Option, ?]])) - } - - checkAll("Coproduct[Eval, Eval, ?]", ComonadTests[Coproduct[Eval, Eval, ?]].comonad[Int, Int, Int]) - checkAll("Comonad[Coproduct[Eval, Eval, ?]]", SerializableTests.serializable(Comonad[Coproduct[Eval, Eval, ?]])) - - { - implicit val coflatMap = Coproduct.catsDataCoflatMapForCoproduct[Eval, Eval] - checkAll("Coproduct[Eval, Eval, ?]", CoflatMapTests[Coproduct[Eval, Eval, ?]].coflatMap[Int, Int, Int]) - checkAll("CoflatMap[Coproduct[Eval, Eval, ?]]", SerializableTests.serializable(CoflatMap[Coproduct[Eval, Eval, ?]])) - } - - checkAll("Coproduct[Option, Option, Int]", OrderLaws[Coproduct[Option, Option, Int]].eqv) - checkAll("Eq[Coproduct[Option, Option, Int]]", SerializableTests.serializable(Eq[Coproduct[Option, Option, Int]])) - - checkAll("Coproduct[Show, Show, ?]", ContravariantTests[Coproduct[Show, Show, ?]].contravariant[Int, Int, Int]) - checkAll("Contravariant[Coproduct[Show, Show, ?]]", SerializableTests.serializable(Contravariant[Coproduct[Show, Show, ?]])) - - test("double swap is identity") { - forAll { (x: Coproduct[Option, Option, Int]) => - x.swap.swap should ===(x) - } - } - - test("swap negates isLeft/isRight") { - forAll { (x: Coproduct[Option, Option, Int]) => - x.isLeft should !== (x.swap.isLeft) - x.isRight should !== (x.swap.isRight) - } - } - - test("isLeft consistent with isRight") { - forAll { (x: Coproduct[Option, Option, Int]) => - x.isLeft should !== (x.isRight) - } - } - - test("toValidated + toEither is identity") { - forAll { (x: Coproduct[Option, List, Int]) => - x.toValidated.toEither should === (x.run) - } - } -} diff --git a/tests/src/test/scala/cats/tests/EitherKTests.scala b/tests/src/test/scala/cats/tests/EitherKTests.scala new file mode 100644 index 0000000000..c7b2998adb --- /dev/null +++ b/tests/src/test/scala/cats/tests/EitherKTests.scala @@ -0,0 +1,61 @@ +package cats.tests + +import cats._ +import cats.kernel.laws.OrderLaws +import cats.data.EitherK +import cats.functor.Contravariant +import cats.laws.discipline._ +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq._ + +class EitherKTests extends CatsSuite { + + checkAll("EitherK[Option, Option, ?]", TraverseTests[EitherK[Option, Option, ?]].traverse[Int, Int, Int, Int, Option, Option]) + checkAll("Traverse[EitherK[Option, Option, ?]]", SerializableTests.serializable(Traverse[EitherK[Option, Option, ?]])) + + { + implicit val foldable = EitherK.catsDataFoldableForEitherK[Option, Option] + checkAll("EitherK[Option, Option, ?]", FoldableTests[EitherK[Option, Option, ?]].foldable[Int, Int]) + checkAll("Foldable[EitherK[Option, Option, ?]]", SerializableTests.serializable(Foldable[EitherK[Option, Option, ?]])) + } + + checkAll("EitherK[Eval, Eval, ?]", ComonadTests[EitherK[Eval, Eval, ?]].comonad[Int, Int, Int]) + checkAll("Comonad[EitherK[Eval, Eval, ?]]", SerializableTests.serializable(Comonad[EitherK[Eval, Eval, ?]])) + + { + implicit val coflatMap = EitherK.catsDataCoflatMapForEitherK[Eval, Eval] + checkAll("EitherK[Eval, Eval, ?]", CoflatMapTests[EitherK[Eval, Eval, ?]].coflatMap[Int, Int, Int]) + checkAll("CoflatMap[EitherK[Eval, Eval, ?]]", SerializableTests.serializable(CoflatMap[EitherK[Eval, Eval, ?]])) + } + + checkAll("EitherK[Option, Option, Int]", OrderLaws[EitherK[Option, Option, Int]].eqv) + checkAll("Eq[EitherK[Option, Option, Int]]", SerializableTests.serializable(Eq[EitherK[Option, Option, Int]])) + + checkAll("EitherK[Show, Show, ?]", ContravariantTests[EitherK[Show, Show, ?]].contravariant[Int, Int, Int]) + checkAll("Contravariant[EitherK[Show, Show, ?]]", SerializableTests.serializable(Contravariant[EitherK[Show, Show, ?]])) + + test("double swap is identity") { + forAll { (x: EitherK[Option, Option, Int]) => + x.swap.swap should ===(x) + } + } + + test("swap negates isLeft/isRight") { + forAll { (x: EitherK[Option, Option, Int]) => + x.isLeft should !== (x.swap.isLeft) + x.isRight should !== (x.swap.isRight) + } + } + + test("isLeft consistent with isRight") { + forAll { (x: EitherK[Option, Option, Int]) => + x.isLeft should !== (x.isRight) + } + } + + test("toValidated + toEither is identity") { + forAll { (x: EitherK[Option, List, Int]) => + x.toValidated.toEither should === (x.run) + } + } +} diff --git a/tests/src/test/scala/cats/tests/FunctionKTests.scala b/tests/src/test/scala/cats/tests/FunctionKTests.scala index 1d47fb9d6a..513bdfbb40 100644 --- a/tests/src/test/scala/cats/tests/FunctionKTests.scala +++ b/tests/src/test/scala/cats/tests/FunctionKTests.scala @@ -2,7 +2,7 @@ package cats package tests import cats.arrow.FunctionK -import cats.data.Coproduct +import cats.data.EitherK import cats.data.NonEmptyList import cats.laws.discipline.arbitrary._ @@ -50,8 +50,8 @@ class FunctionKTests extends CatsSuite { test("or") { val combinedInterpreter = Test1FK or Test2FK forAll { (a : Int, b : Int) => - combinedInterpreter(Coproduct.left(Test1(a))) should === (a) - combinedInterpreter(Coproduct.right(Test2(b))) should === (b) + combinedInterpreter(EitherK.left(Test1(a))) should === (a) + combinedInterpreter(EitherK.right(Test2(b))) should === (b) } } diff --git a/tests/src/test/scala/cats/tests/InjectTests.scala b/tests/src/test/scala/cats/tests/InjectTests.scala index 943634283e..692d08d99d 100644 --- a/tests/src/test/scala/cats/tests/InjectTests.scala +++ b/tests/src/test/scala/cats/tests/InjectTests.scala @@ -1,6 +1,6 @@ package cats -import cats.data.Coproduct +import cats.data.EitherK import cats.tests.CatsSuite import org.scalacheck._ @@ -38,7 +38,7 @@ class InjectTests extends CatsSuite { Arbitrary(for {s <- seqArb.arbitrary; f <- intAArb.arbitrary} yield Test2(s, f)) } - type T[A] = Coproduct[Test1Algebra, Test2Algebra, A] + type T[A] = EitherK[Test1Algebra, Test2Algebra, A] test("inj & prj") { def distr[F[_], A](f1: F[A], f2: F[A]) @@ -80,13 +80,13 @@ class InjectTests extends CatsSuite { test("apply in left") { forAll { (y: Test1Algebra[Int]) => - Inject[Test1Algebra, T].inj(y) == Coproduct(Left(y)) should ===(true) + Inject[Test1Algebra, T].inj(y) == EitherK(Left(y)) should ===(true) } } test("apply in right") { forAll { (y: Test2Algebra[Int]) => - Inject[Test2Algebra, T].inj(y) == Coproduct(Right(y)) should ===(true) + Inject[Test2Algebra, T].inj(y) == EitherK(Right(y)) should ===(true) } } diff --git a/tests/src/test/scala/cats/tests/ProdTests.scala b/tests/src/test/scala/cats/tests/ProdTests.scala deleted file mode 100644 index 751a3d184a..0000000000 --- a/tests/src/test/scala/cats/tests/ProdTests.scala +++ /dev/null @@ -1,93 +0,0 @@ -package cats -package tests - -import cats.data.Prod -import cats.functor.Contravariant -import cats.laws.discipline._ -import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.eq._ -import cats.kernel.laws.OrderLaws - -class ProdTests extends CatsSuite { - implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[Option, List, ?]] - checkAll("Prod[Option, List, Int]", CartesianTests[λ[α => Prod[Option, List, α]]].cartesian[Int, Int, Int]) - checkAll("Cartesian[Prod[Option, List, Int]]", SerializableTests.serializable(Cartesian[λ[α => Prod[Option, List, α]]])) - - checkAll("Prod[Option, List, Int]", AlternativeTests[λ[α => Prod[Option, List, α]]].alternative[Int, Int, Int]) - checkAll("Alternative[Prod[Option, List, Int]]", SerializableTests.serializable(Alternative[λ[α => Prod[Option, List, α]]])) - - checkAll("Prod[Show, Order, Int]", ContravariantTests[λ[α => Prod[Show, Order, α]]].contravariant[Int, Int, Int]) - checkAll("Contravariant[Prod[Show, Order, Int]]", SerializableTests.serializable(Contravariant[λ[α => Prod[Show, Order, α]]])) - - checkAll("Show[Prod[Option, Option, Int]]", SerializableTests.serializable(Show[Prod[Option, Option, Int]])) - - { - implicit val monoidK = ListWrapper.monoidK - checkAll("Prod[ListWrapper, ListWrapper, ?]", MonoidKTests[Prod[ListWrapper, ListWrapper, ?]].monoidK[Int]) - checkAll("MonoidK[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonoidK[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val semigroupK = ListWrapper.semigroupK - checkAll("Prod[ListWrapper, ListWrapper, ?]", SemigroupKTests[Prod[ListWrapper, ListWrapper, ?]].semigroupK[Int]) - checkAll("SemigroupK[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(SemigroupK[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val apply = ListWrapper.applyInstance - implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[ListWrapper, ListWrapper, ?]] - checkAll("Prod[ListWrapper, ListWrapper, ?]", ApplyTests[Prod[ListWrapper, ListWrapper, ?]].apply[Int, Int, Int]) - checkAll("Apply[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Apply[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val functor = ListWrapper.functor - checkAll("Prod[ListWrapper, ListWrapper, ?]", FunctorTests[Prod[ListWrapper, ListWrapper, ?]].functor[Int, Int, Int]) - checkAll("Functor[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Functor[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val monad = ListWrapper.monad - implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[ListWrapper, ListWrapper, ?]] - checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadTests[Prod[ListWrapper, ListWrapper, ?]].monad[Int, Int, Int]) - checkAll("Monad[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Monad[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val foldable = ListWrapper.foldable - checkAll("Prod[ListWrapper, ListWrapper, ?]", FoldableTests[Prod[ListWrapper, ListWrapper, ?]].foldable[Int, Int]) - checkAll("Foldable[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Foldable[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val traverse = ListWrapper.traverse - checkAll("Prod[ListWrapper, ListWrapper, ?]", TraverseTests[Prod[ListWrapper, ListWrapper, ?]].traverse[Int, Int, Int, Int, Option, Option]) - checkAll("Traverse[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Traverse[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val monadCombine = ListWrapper.monadCombine - implicit val iso = CartesianTests.Isomorphisms.invariant[Prod[ListWrapper, ListWrapper, ?]] - checkAll("Prod[ListWrapper, ListWrapper, ?]", MonadCombineTests[Prod[ListWrapper, ListWrapper, ?]].monadCombine[Int, Int, Int]) - checkAll("MonadCombine[Prod[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonadCombine[Prod[ListWrapper, ListWrapper, ?]])) - } - - { - implicit val E = ListWrapper.eqv[Int] - implicit val O = ListWrapper.order[Int] - implicit val P = ListWrapper.partialOrder[Int] - - checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].eqv) - checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].order) - checkAll("Prod[ListWrapper, ListWrapper, Int]", OrderLaws[Prod[ListWrapper, ListWrapper, Int]].partialOrder) - } - - test("show") { - forAll { (l1: Option[Int], l2: Option[Int]) => - val prod = Prod(l1, l2) - - Show[Prod[Option, Option, Int]].show(prod) should === (s"Prod(${Show[Option[Int]].show(l1)}, ${Show[Option[Int]].show(l2)})") - } - } - -} diff --git a/tests/src/test/scala/cats/tests/Tuple2KTests.scala b/tests/src/test/scala/cats/tests/Tuple2KTests.scala new file mode 100644 index 0000000000..9b7c993e39 --- /dev/null +++ b/tests/src/test/scala/cats/tests/Tuple2KTests.scala @@ -0,0 +1,93 @@ +package cats +package tests + +import cats.data.Tuple2K +import cats.functor.Contravariant +import cats.laws.discipline._ +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq._ +import cats.kernel.laws.OrderLaws + +class Tuple2KTests extends CatsSuite { + implicit val iso = CartesianTests.Isomorphisms.invariant[Tuple2K[Option, List, ?]] + checkAll("Tuple2K[Option, List, Int]", CartesianTests[λ[α => Tuple2K[Option, List, α]]].cartesian[Int, Int, Int]) + checkAll("Cartesian[Tuple2K[Option, List, Int]]", SerializableTests.serializable(Cartesian[λ[α => Tuple2K[Option, List, α]]])) + + checkAll("Tuple2K[Option, List, Int]", AlternativeTests[λ[α => Tuple2K[Option, List, α]]].alternative[Int, Int, Int]) + checkAll("Alternative[Tuple2K[Option, List, Int]]", SerializableTests.serializable(Alternative[λ[α => Tuple2K[Option, List, α]]])) + + checkAll("Tuple2K[Show, Order, Int]", ContravariantTests[λ[α => Tuple2K[Show, Order, α]]].contravariant[Int, Int, Int]) + checkAll("Contravariant[Tuple2K[Show, Order, Int]]", SerializableTests.serializable(Contravariant[λ[α => Tuple2K[Show, Order, α]]])) + + checkAll("Show[Tuple2K[Option, Option, Int]]", SerializableTests.serializable(Show[Tuple2K[Option, Option, Int]])) + + { + implicit val monoidK = ListWrapper.monoidK + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", MonoidKTests[Tuple2K[ListWrapper, ListWrapper, ?]].monoidK[Int]) + checkAll("MonoidK[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonoidK[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val semigroupK = ListWrapper.semigroupK + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", SemigroupKTests[Tuple2K[ListWrapper, ListWrapper, ?]].semigroupK[Int]) + checkAll("SemigroupK[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(SemigroupK[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val apply = ListWrapper.applyInstance + implicit val iso = CartesianTests.Isomorphisms.invariant[Tuple2K[ListWrapper, ListWrapper, ?]] + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", ApplyTests[Tuple2K[ListWrapper, ListWrapper, ?]].apply[Int, Int, Int]) + checkAll("Apply[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Apply[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val functor = ListWrapper.functor + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", FunctorTests[Tuple2K[ListWrapper, ListWrapper, ?]].functor[Int, Int, Int]) + checkAll("Functor[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Functor[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val monad = ListWrapper.monad + implicit val iso = CartesianTests.Isomorphisms.invariant[Tuple2K[ListWrapper, ListWrapper, ?]] + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", MonadTests[Tuple2K[ListWrapper, ListWrapper, ?]].monad[Int, Int, Int]) + checkAll("Monad[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Monad[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val foldable = ListWrapper.foldable + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", FoldableTests[Tuple2K[ListWrapper, ListWrapper, ?]].foldable[Int, Int]) + checkAll("Foldable[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Foldable[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val traverse = ListWrapper.traverse + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", TraverseTests[Tuple2K[ListWrapper, ListWrapper, ?]].traverse[Int, Int, Int, Int, Option, Option]) + checkAll("Traverse[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Traverse[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val monadCombine = ListWrapper.monadCombine + implicit val iso = CartesianTests.Isomorphisms.invariant[Tuple2K[ListWrapper, ListWrapper, ?]] + checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", MonadCombineTests[Tuple2K[ListWrapper, ListWrapper, ?]].monadCombine[Int, Int, Int]) + checkAll("MonadCombine[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(MonadCombine[Tuple2K[ListWrapper, ListWrapper, ?]])) + } + + { + implicit val E = ListWrapper.eqv[Int] + implicit val O = ListWrapper.order[Int] + implicit val P = ListWrapper.partialOrder[Int] + + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].eqv) + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].order) + checkAll("Tuple2K[ListWrapper, ListWrapper, Int]", OrderLaws[Tuple2K[ListWrapper, ListWrapper, Int]].partialOrder) + } + + test("show") { + forAll { (l1: Option[Int], l2: Option[Int]) => + val tuple = Tuple2K(l1, l2) + + Show[Tuple2K[Option, Option, Int]].show(tuple) should === (s"Tuple2K(${Show[Option[Int]].show(l1)}, ${Show[Option[Int]].show(l2)})") + } + } + +}