From fc54f363f5397c62278afa2c1b7b6d50e3132691 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Wed, 13 Jul 2016 22:24:36 -0400 Subject: [PATCH 1/4] Separate Bitraverse hierarchy default implementations This is a first-step for #992. I've started with the Bitraverse type hierarchy because it's not a very deep one. The idea is that we would continue this effort for other type class hierarchies. --- core/src/main/scala/cats/Bifoldable.scala | 11 +++++++++-- core/src/main/scala/cats/Bitraverse.scala | 15 +++++++++++---- core/src/main/scala/cats/data/Const.scala | 2 +- core/src/main/scala/cats/data/Ior.scala | 4 ++-- core/src/main/scala/cats/data/Validated.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 4 ++-- core/src/main/scala/cats/data/Xor.scala | 2 +- core/src/main/scala/cats/data/XorT.scala | 8 ++++---- .../main/scala/cats/functor/Bifunctor.scala | 18 +++++++++++++----- .../src/main/scala/cats/instances/either.scala | 2 +- core/src/main/scala/cats/instances/tuple.scala | 2 +- 11 files changed, 46 insertions(+), 24 deletions(-) diff --git a/core/src/main/scala/cats/Bifoldable.scala b/core/src/main/scala/cats/Bifoldable.scala index 5d7721c06c..cde0f4baf4 100644 --- a/core/src/main/scala/cats/Bifoldable.scala +++ b/core/src/main/scala/cats/Bifoldable.scala @@ -3,7 +3,7 @@ package cats /** * A type class abstracting over types that give rise to two independent [[cats.Foldable]]s. */ -trait Bifoldable[F[_, _]] extends Any with Serializable { self => +trait Bifoldable[F[_, _]] extends Any with Serializable { /** Collapse the structure with a left-associative function */ def bifoldLeft[A, B, C](fab: F[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C @@ -11,6 +11,13 @@ trait Bifoldable[F[_, _]] extends Any with Serializable { self => def bifoldRight[A, B, C](fab: F[A, B], c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C] /** Collapse the structure by mapping each element to an element of a type that has a [[cats.Monoid]] */ + def bifoldMap[A, B, C](fab: F[A, B])(f: A => C, g: B => C)(implicit C: Monoid[C]): C + + def compose[G[_, _]](implicit ev: Bifoldable[G]): Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] +} + +trait DefaultBifoldable[F[_, _]] extends Bifoldable[F] { self => + def bifoldMap[A, B, C](fab: F[A, B])(f: A => C, g: B => C)(implicit C: Monoid[C]): C = bifoldLeft(fab, C.empty)( (c: C, a: A) => C.combine(c, f(a)), @@ -28,7 +35,7 @@ object Bifoldable { def apply[F[_, _]](implicit F: Bifoldable[F]): Bifoldable[F] = F } -private[cats] trait ComposedBifoldable[F[_, _], G[_, _]] extends Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] { +private[cats] trait ComposedBifoldable[F[_, _], G[_, _]] extends DefaultBifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] { implicit def F: Bifoldable[F] implicit def G: Bifoldable[G] diff --git a/core/src/main/scala/cats/Bitraverse.scala b/core/src/main/scala/cats/Bitraverse.scala index 042e8b1e43..2408fd0ce9 100644 --- a/core/src/main/scala/cats/Bitraverse.scala +++ b/core/src/main/scala/cats/Bitraverse.scala @@ -1,19 +1,26 @@ package cats -import cats.functor.{Bifunctor, ComposedBifunctor} +import cats.functor.{Bifunctor, ComposedBifunctor, DefaultBifunctor} /** * A type class abstracting over types that give rise to two independent [[cats.Traverse]]s. */ -trait Bitraverse[F[_, _]] extends Bifoldable[F] with Bifunctor[F] { self => +trait Bitraverse[F[_, _]] extends Bifoldable[F] with Bifunctor[F] { /** Traverse each side of the structure with the given functions */ def bitraverse[G[_]: Applicative, A, B, C, D](fab: F[A, B])(f: A => G[C], g: B => G[D]): G[F[C, D]] /** Sequence each side of the structure with the given functions */ + def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] + + /** If F and G are both [[cats.Bitraverse]] then so is their composition F[G[_, _], G[_, _]] */ + def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] +} + +trait DefaultBitraverse[F[_, _]] extends Bitraverse[F] with DefaultBifoldable[F] with DefaultBifunctor[F] { self => + def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] = bitraverse(fab)(identity, identity) - /** If F and G are both [[cats.Bitraverse]] then so is their composition F[G[_, _], G[_, _]] */ def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] = new ComposedBitraverse[F, G] { val F = self @@ -29,7 +36,7 @@ object Bitraverse { } private[cats] trait ComposedBitraverse[F[_, _], G[_, _]] - extends Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] + extends DefaultBitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] with ComposedBifoldable[F, G] with ComposedBifunctor[F, G] { def F: Bitraverse[F] diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 154c696aa7..3a91ce1a70 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -71,7 +71,7 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 { } implicit val catsDataBifoldableForConst: Bifoldable[Const] = - new Bifoldable[Const] { + new DefaultBifoldable[Const] { def bifoldLeft[A, B, C](fab: Const[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = f(c, fab.getConst) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 25cdc77474..634cd9ca72 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -1,7 +1,7 @@ package cats package data -import cats.functor.Bifunctor +import cats.functor.{Bifunctor, DefaultBifunctor} /** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`. * @@ -146,7 +146,7 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { } implicit def catsDataBifunctorForIor: Bifunctor[Ior] = - new Bifunctor[Ior] { + new DefaultBifunctor[Ior] { override def bimap[A, B, C, D](fab: A Ior B)(f: A => C, g: B => D): C Ior D = fab.bimap(f, g) } } diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index 3ff68f8b5c..d866df3857 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -259,7 +259,7 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } implicit val catsDataBitraverseForValidated: Bitraverse[Validated] = - new Bitraverse[Validated] { + new DefaultBitraverse[Validated] { def bitraverse[G[_], A, B, C, D](fab: Validated[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Validated[C, D]] = fab match { case Invalid(a) => G.map(f(a))(Validated.invalid) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index e1edf6e620..6f8db87b9f 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -2,7 +2,7 @@ package cats package data import cats.kernel.instances.tuple._ -import cats.functor.{Bifunctor, Contravariant} +import cats.functor.{Bifunctor, Contravariant, DefaultBifunctor} final case class WriterT[F[_], L, V](run: F[(L, V)]) { def written(implicit functorF: Functor[F]): F[L] = @@ -64,7 +64,7 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 { catsDataEqForWriterT[Id, L, V] implicit def catsDataBifunctorForWriterT[F[_]:Functor]: Bifunctor[WriterT[F, ?, ?]] = - new Bifunctor[WriterT[F, ?, ?]] { + new DefaultBifunctor[WriterT[F, ?, ?]] { def bimap[A, B, C, D](fab: WriterT[F, A, B])(f: A => C, g: B => D): WriterT[F, C, D] = fab.bimap(f, g) } diff --git a/core/src/main/scala/cats/data/Xor.scala b/core/src/main/scala/cats/data/Xor.scala index b7e599063d..490a7bab82 100644 --- a/core/src/main/scala/cats/data/Xor.scala +++ b/core/src/main/scala/cats/data/Xor.scala @@ -235,7 +235,7 @@ private[data] sealed abstract class XorInstances extends XorInstances1 { } implicit val catsDataBitraverseForXor: Bitraverse[Xor] = - new Bitraverse[Xor] { + new DefaultBitraverse[Xor] { def bitraverse[G[_], A, B, C, D](fab: Xor[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Xor[C, D]] = fab match { case Xor.Left(a) => G.map(f(a))(Xor.left) diff --git a/core/src/main/scala/cats/data/XorT.scala b/core/src/main/scala/cats/data/XorT.scala index 4ec93aa120..6d152529ce 100644 --- a/core/src/main/scala/cats/data/XorT.scala +++ b/core/src/main/scala/cats/data/XorT.scala @@ -1,7 +1,7 @@ package cats package data -import cats.functor.Bifunctor +import cats.functor.{Bifunctor, DefaultBifunctor} /** * Transformer for `Xor`, allowing the effect of an arbitrary type constructor `F` to be combined with the @@ -238,7 +238,7 @@ private[data] abstract class XorTInstances extends XorTInstances1 { functor.Contravariant[Show].contramap(sh)(_.value) implicit def catsDataBifunctorForXorT[F[_]](implicit F: Functor[F]): Bifunctor[XorT[F, ?, ?]] = - new Bifunctor[XorT[F, ?, ?]] { + new DefaultBifunctor[XorT[F, ?, ?]] { override def bimap[A, B, C, D](fab: XorT[F, A, B])(f: A => C, g: B => D): XorT[F, C, D] = fab.bimap(f, g) } @@ -401,7 +401,7 @@ private[data] sealed trait XorTTraverse[F[_], L] extends Traverse[XorT[F, L, ?]] fa traverse f } -private[data] sealed trait XorTBifoldable[F[_]] extends Bifoldable[XorT[F, ?, ?]] { +private[data] sealed trait XorTBifoldable[F[_]] extends DefaultBifoldable[XorT[F, ?, ?]] { implicit def F0: Foldable[F] def bifoldLeft[A, B, C](fab: XorT[F, A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = @@ -411,7 +411,7 @@ private[data] sealed trait XorTBifoldable[F[_]] extends Bifoldable[XorT[F, ?, ?] F0.foldRight(fab.value, c)( (axb, acc) => Bifoldable[Xor].bifoldRight(axb, acc)(f, g)) } -private[data] sealed trait XorTBitraverse[F[_]] extends Bitraverse[XorT[F, ?, ?]] with XorTBifoldable[F] { +private[data] sealed trait XorTBitraverse[F[_]] extends DefaultBitraverse[XorT[F, ?, ?]] with XorTBifoldable[F] { override implicit def F0: Traverse[F] override def bitraverse[G[_], A, B, C, D](fab: XorT[F, A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[XorT[F, C, D]] = diff --git a/core/src/main/scala/cats/functor/Bifunctor.scala b/core/src/main/scala/cats/functor/Bifunctor.scala index 143505db84..f202fbfec6 100644 --- a/core/src/main/scala/cats/functor/Bifunctor.scala +++ b/core/src/main/scala/cats/functor/Bifunctor.scala @@ -5,7 +5,7 @@ package functor * A type class of types which give rise to two independent, covariant * functors. */ -trait Bifunctor[F[_, _]] extends Any with Serializable { self => +trait Bifunctor[F[_, _]] extends Any with Serializable { /** * The quintessential method of the Bifunctor trait, it applies a @@ -13,18 +13,26 @@ trait Bifunctor[F[_, _]] extends Any with Serializable { self => */ def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] - // derived methods /** * apply a function to the "left" functor */ - def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity) + def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] /** * apply a function ro the "right" functor */ - def rightMap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] = bimap(fab)(identity, f) + def rightMap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] /** The composition of two Bifunctors is itself a Bifunctor */ + def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] +} + +trait DefaultBifunctor[F[_, _]] extends Bifunctor[F] { self => + + def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity) + + def rightMap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] = bimap(fab)(identity, f) + def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] = new ComposedBifunctor[F, G] { val F = self @@ -37,7 +45,7 @@ object Bifunctor { } private[cats] trait ComposedBifunctor[F[_, _], G[_, _]] - extends Bifunctor[λ[(A, B) => F[G[A, B], G[A, B]]]] { + extends DefaultBifunctor[λ[(A, B) => F[G[A, B], G[A, B]]]] { def F: Bifunctor[F] def G: Bifunctor[G] diff --git a/core/src/main/scala/cats/instances/either.scala b/core/src/main/scala/cats/instances/either.scala index 8bdb39dd64..464f7689c2 100644 --- a/core/src/main/scala/cats/instances/either.scala +++ b/core/src/main/scala/cats/instances/either.scala @@ -6,7 +6,7 @@ import cats.data.Xor trait EitherInstances extends EitherInstances1 { implicit val catsStdBitraverseForEither: Bitraverse[Either] = - new Bitraverse[Either] { + new DefaultBitraverse[Either] { def bitraverse[G[_], A, B, C, D](fab: Either[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Either[C, D]] = fab match { case Left(a) => G.map(f(a))(Left(_)) diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index 13a1b32edb..864ca70ff7 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -5,7 +5,7 @@ trait TupleInstances extends Tuple2Instances with cats.kernel.instances.TupleIns sealed trait Tuple2Instances { implicit val catsStdBitraverseForTuple2: Bitraverse[Tuple2] = - new Bitraverse[Tuple2] { + new DefaultBitraverse[Tuple2] { def bitraverse[G[_]: Applicative, A, B, C, D](fab: (A, B))(f: A => G[C], g: B => G[D]): G[(C, D)] = Applicative[G].tuple2(f(fab._1), g(fab._2)) From 9daaa828ed3784ff4fc2789c34d070b645e8227e Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Thu, 14 Jul 2016 09:11:26 -0400 Subject: [PATCH 2/4] Namespace default type class traits --- core/src/main/scala/cats/Bifoldable.scala | 30 +++++++++---------- core/src/main/scala/cats/Bitraverse.scala | 30 +++++++++---------- core/src/main/scala/cats/data/Const.scala | 2 +- core/src/main/scala/cats/data/Ior.scala | 4 +-- core/src/main/scala/cats/data/Validated.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 4 +-- core/src/main/scala/cats/data/Xor.scala | 2 +- core/src/main/scala/cats/data/XorT.scala | 8 ++--- .../main/scala/cats/functor/Bifunctor.scala | 24 +++++++-------- .../main/scala/cats/instances/either.scala | 2 +- .../src/main/scala/cats/instances/tuple.scala | 2 +- 11 files changed, 55 insertions(+), 55 deletions(-) diff --git a/core/src/main/scala/cats/Bifoldable.scala b/core/src/main/scala/cats/Bifoldable.scala index cde0f4baf4..3cb537a21c 100644 --- a/core/src/main/scala/cats/Bifoldable.scala +++ b/core/src/main/scala/cats/Bifoldable.scala @@ -16,26 +16,26 @@ trait Bifoldable[F[_, _]] extends Any with Serializable { def compose[G[_, _]](implicit ev: Bifoldable[G]): Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] } -trait DefaultBifoldable[F[_, _]] extends Bifoldable[F] { self => +object Bifoldable { + def apply[F[_, _]](implicit F: Bifoldable[F]): Bifoldable[F] = F - def bifoldMap[A, B, C](fab: F[A, B])(f: A => C, g: B => C)(implicit C: Monoid[C]): C = - bifoldLeft(fab, C.empty)( - (c: C, a: A) => C.combine(c, f(a)), - (c: C, b: B) => C.combine(c, g(b)) - ) + trait Default[F[_, _]] extends Bifoldable[F] { self => - def compose[G[_, _]](implicit ev: Bifoldable[G]): Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] = - new ComposedBifoldable[F, G] { - val F = self - val G = ev - } -} + def bifoldMap[A, B, C](fab: F[A, B])(f: A => C, g: B => C)(implicit C: Monoid[C]): C = + bifoldLeft(fab, C.empty)( + (c: C, a: A) => C.combine(c, f(a)), + (c: C, b: B) => C.combine(c, g(b)) + ) -object Bifoldable { - def apply[F[_, _]](implicit F: Bifoldable[F]): Bifoldable[F] = F + def compose[G[_, _]](implicit ev: Bifoldable[G]): Bifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] = + new ComposedBifoldable[F, G] { + val F = self + val G = ev + } + } } -private[cats] trait ComposedBifoldable[F[_, _], G[_, _]] extends DefaultBifoldable[λ[(α, β) => F[G[α, β], G[α, β]]]] { +private[cats] trait ComposedBifoldable[F[_, _], G[_, _]] extends Bifoldable.Default[λ[(α, β) => F[G[α, β], G[α, β]]]] { implicit def F: Bifoldable[F] implicit def G: Bifoldable[G] diff --git a/core/src/main/scala/cats/Bitraverse.scala b/core/src/main/scala/cats/Bitraverse.scala index 2408fd0ce9..0e9f6b1fb3 100644 --- a/core/src/main/scala/cats/Bitraverse.scala +++ b/core/src/main/scala/cats/Bitraverse.scala @@ -1,6 +1,6 @@ package cats -import cats.functor.{Bifunctor, ComposedBifunctor, DefaultBifunctor} +import cats.functor.{Bifunctor, ComposedBifunctor} /** * A type class abstracting over types that give rise to two independent [[cats.Traverse]]s. @@ -16,27 +16,27 @@ trait Bitraverse[F[_, _]] extends Bifoldable[F] with Bifunctor[F] { def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] } -trait DefaultBitraverse[F[_, _]] extends Bitraverse[F] with DefaultBifoldable[F] with DefaultBifunctor[F] { self => +object Bitraverse { + def apply[F[_, _]](implicit F: Bitraverse[F]): Bitraverse[F] = F - def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] = - bitraverse(fab)(identity, identity) + trait Default[F[_, _]] extends Bitraverse[F] with Bifoldable.Default[F] with Bifunctor.Default[F] { self => - def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] = - new ComposedBitraverse[F, G] { - val F = self - val G = ev - } + def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] = + bitraverse(fab)(identity, identity) - override def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] = - bitraverse[Id, A, B, C, D](fab)(f, g) -} + def compose[G[_, _]](implicit ev: Bitraverse[G]): Bitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] = + new ComposedBitraverse[F, G] { + val F = self + val G = ev + } -object Bitraverse { - def apply[F[_, _]](implicit F: Bitraverse[F]): Bitraverse[F] = F + override def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] = + bitraverse[Id, A, B, C, D](fab)(f, g) + } } private[cats] trait ComposedBitraverse[F[_, _], G[_, _]] - extends DefaultBitraverse[λ[(α, β) => F[G[α, β], G[α, β]]]] + extends Bitraverse.Default[λ[(α, β) => F[G[α, β], G[α, β]]]] with ComposedBifoldable[F, G] with ComposedBifunctor[F, G] { def F: Bitraverse[F] diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 3a91ce1a70..928d1b4dd6 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -71,7 +71,7 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 { } implicit val catsDataBifoldableForConst: Bifoldable[Const] = - new DefaultBifoldable[Const] { + new Bifoldable.Default[Const] { def bifoldLeft[A, B, C](fab: Const[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = f(c, fab.getConst) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 634cd9ca72..6828d5867e 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -1,7 +1,7 @@ package cats package data -import cats.functor.{Bifunctor, DefaultBifunctor} +import cats.functor.Bifunctor /** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`. * @@ -146,7 +146,7 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { } implicit def catsDataBifunctorForIor: Bifunctor[Ior] = - new DefaultBifunctor[Ior] { + new Bifunctor.Default[Ior] { override def bimap[A, B, C, D](fab: A Ior B)(f: A => C, g: B => D): C Ior D = fab.bimap(f, g) } } diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index d866df3857..a3305a352b 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -259,7 +259,7 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } implicit val catsDataBitraverseForValidated: Bitraverse[Validated] = - new DefaultBitraverse[Validated] { + new Bitraverse.Default[Validated] { def bitraverse[G[_], A, B, C, D](fab: Validated[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Validated[C, D]] = fab match { case Invalid(a) => G.map(f(a))(Validated.invalid) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 6f8db87b9f..e8dce8f6ce 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -2,7 +2,7 @@ package cats package data import cats.kernel.instances.tuple._ -import cats.functor.{Bifunctor, Contravariant, DefaultBifunctor} +import cats.functor.{Bifunctor, Contravariant} final case class WriterT[F[_], L, V](run: F[(L, V)]) { def written(implicit functorF: Functor[F]): F[L] = @@ -64,7 +64,7 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 { catsDataEqForWriterT[Id, L, V] implicit def catsDataBifunctorForWriterT[F[_]:Functor]: Bifunctor[WriterT[F, ?, ?]] = - new DefaultBifunctor[WriterT[F, ?, ?]] { + new Bifunctor.Default[WriterT[F, ?, ?]] { def bimap[A, B, C, D](fab: WriterT[F, A, B])(f: A => C, g: B => D): WriterT[F, C, D] = fab.bimap(f, g) } diff --git a/core/src/main/scala/cats/data/Xor.scala b/core/src/main/scala/cats/data/Xor.scala index 490a7bab82..178fc5290d 100644 --- a/core/src/main/scala/cats/data/Xor.scala +++ b/core/src/main/scala/cats/data/Xor.scala @@ -235,7 +235,7 @@ private[data] sealed abstract class XorInstances extends XorInstances1 { } implicit val catsDataBitraverseForXor: Bitraverse[Xor] = - new DefaultBitraverse[Xor] { + new Bitraverse.Default[Xor] { def bitraverse[G[_], A, B, C, D](fab: Xor[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Xor[C, D]] = fab match { case Xor.Left(a) => G.map(f(a))(Xor.left) diff --git a/core/src/main/scala/cats/data/XorT.scala b/core/src/main/scala/cats/data/XorT.scala index 6d152529ce..d31f476b88 100644 --- a/core/src/main/scala/cats/data/XorT.scala +++ b/core/src/main/scala/cats/data/XorT.scala @@ -1,7 +1,7 @@ package cats package data -import cats.functor.{Bifunctor, DefaultBifunctor} +import cats.functor.Bifunctor /** * Transformer for `Xor`, allowing the effect of an arbitrary type constructor `F` to be combined with the @@ -238,7 +238,7 @@ private[data] abstract class XorTInstances extends XorTInstances1 { functor.Contravariant[Show].contramap(sh)(_.value) implicit def catsDataBifunctorForXorT[F[_]](implicit F: Functor[F]): Bifunctor[XorT[F, ?, ?]] = - new DefaultBifunctor[XorT[F, ?, ?]] { + new Bifunctor.Default[XorT[F, ?, ?]] { override def bimap[A, B, C, D](fab: XorT[F, A, B])(f: A => C, g: B => D): XorT[F, C, D] = fab.bimap(f, g) } @@ -401,7 +401,7 @@ private[data] sealed trait XorTTraverse[F[_], L] extends Traverse[XorT[F, L, ?]] fa traverse f } -private[data] sealed trait XorTBifoldable[F[_]] extends DefaultBifoldable[XorT[F, ?, ?]] { +private[data] sealed trait XorTBifoldable[F[_]] extends Bifoldable.Default[XorT[F, ?, ?]] { implicit def F0: Foldable[F] def bifoldLeft[A, B, C](fab: XorT[F, A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = @@ -411,7 +411,7 @@ private[data] sealed trait XorTBifoldable[F[_]] extends DefaultBifoldable[XorT[F F0.foldRight(fab.value, c)( (axb, acc) => Bifoldable[Xor].bifoldRight(axb, acc)(f, g)) } -private[data] sealed trait XorTBitraverse[F[_]] extends DefaultBitraverse[XorT[F, ?, ?]] with XorTBifoldable[F] { +private[data] sealed trait XorTBitraverse[F[_]] extends Bitraverse.Default[XorT[F, ?, ?]] with XorTBifoldable[F] { override implicit def F0: Traverse[F] override def bitraverse[G[_], A, B, C, D](fab: XorT[F, A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[XorT[F, C, D]] = diff --git a/core/src/main/scala/cats/functor/Bifunctor.scala b/core/src/main/scala/cats/functor/Bifunctor.scala index f202fbfec6..6a8bee5322 100644 --- a/core/src/main/scala/cats/functor/Bifunctor.scala +++ b/core/src/main/scala/cats/functor/Bifunctor.scala @@ -27,25 +27,25 @@ trait Bifunctor[F[_, _]] extends Any with Serializable { def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] } -trait DefaultBifunctor[F[_, _]] extends Bifunctor[F] { self => +object Bifunctor { + def apply[F[_, _]](implicit ev: Bifunctor[F]): Bifunctor[F] = ev - def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity) + trait Default[F[_, _]] extends Bifunctor[F] { self => - def rightMap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] = bimap(fab)(identity, f) + def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity) - def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] = - new ComposedBifunctor[F, G] { - val F = self - val G = G0 - } -} + def rightMap[A, B, C](fab: F[A, B])(f: B => C): F[A, C] = bimap(fab)(identity, f) -object Bifunctor { - def apply[F[_, _]](implicit ev: Bifunctor[F]): Bifunctor[F] = ev + def compose[G[_, _]](implicit G0: Bifunctor[G]): Bifunctor[λ[(α, β) => F[G[α, β], G[α, β]]]] = + new ComposedBifunctor[F, G] { + val F = self + val G = G0 + } + } } private[cats] trait ComposedBifunctor[F[_, _], G[_, _]] - extends DefaultBifunctor[λ[(A, B) => F[G[A, B], G[A, B]]]] { + extends Bifunctor.Default[λ[(A, B) => F[G[A, B], G[A, B]]]] { def F: Bifunctor[F] def G: Bifunctor[G] diff --git a/core/src/main/scala/cats/instances/either.scala b/core/src/main/scala/cats/instances/either.scala index 464f7689c2..46968734d6 100644 --- a/core/src/main/scala/cats/instances/either.scala +++ b/core/src/main/scala/cats/instances/either.scala @@ -6,7 +6,7 @@ import cats.data.Xor trait EitherInstances extends EitherInstances1 { implicit val catsStdBitraverseForEither: Bitraverse[Either] = - new DefaultBitraverse[Either] { + new Bitraverse.Default[Either] { def bitraverse[G[_], A, B, C, D](fab: Either[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Either[C, D]] = fab match { case Left(a) => G.map(f(a))(Left(_)) diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index 864ca70ff7..7a7d973890 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -5,7 +5,7 @@ trait TupleInstances extends Tuple2Instances with cats.kernel.instances.TupleIns sealed trait Tuple2Instances { implicit val catsStdBitraverseForTuple2: Bitraverse[Tuple2] = - new DefaultBitraverse[Tuple2] { + new Bitraverse.Default[Tuple2] { def bitraverse[G[_]: Applicative, A, B, C, D](fab: (A, B))(f: A => G[C], g: B => G[D]): G[(C, D)] = Applicative[G].tuple2(f(fab._1), g(fab._2)) From f0536445e5c4392fc6d342f0893159a6dce214e1 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Fri, 15 Jul 2016 07:11:29 -0400 Subject: [PATCH 3/4] Add bisequence and bimap examples This is an attempt to not have net negative code coverage on #1194. --- core/src/main/scala/cats/Bitraverse.scala | 26 ++++++++++++++++++- .../main/scala/cats/functor/Bifunctor.scala | 9 +++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Bitraverse.scala b/core/src/main/scala/cats/Bitraverse.scala index 0e9f6b1fb3..143287eb6b 100644 --- a/core/src/main/scala/cats/Bitraverse.scala +++ b/core/src/main/scala/cats/Bitraverse.scala @@ -9,7 +9,31 @@ trait Bitraverse[F[_, _]] extends Bifoldable[F] with Bifunctor[F] { /** Traverse each side of the structure with the given functions */ def bitraverse[G[_]: Applicative, A, B, C, D](fab: F[A, B])(f: A => G[C], g: B => G[D]): G[F[C, D]] - /** Sequence each side of the structure with the given functions */ + /** + * Sequence each side of the structure with the given functions. + * + * Example: + * {{{ + * scala> import cats.data.Xor + * scala> import cats.implicits._ + * + * scala> val rightSome: Option[String] Xor Option[Int] = Xor.right(Some(3)) + * scala> rightSome.bisequence + * res0: Option[String Xor Int] = Some(Right(3)) + * + * scala> val rightNone: Option[String] Xor Option[Int] = Xor.right(None) + * scala> rightNone.bisequence + * res0: Option[String Xor Int] = None + * + * scala> val leftSome: Option[String] Xor Option[Int] = Xor.left(Some("foo")) + * scala> leftSome.bisequence + * res0: Option[String Xor Int] = Some(Left(foo)) + * + * scala> val leftNone: Option[String] Xor Option[Int] = Xor.left(None) + * scala> leftNone.bisequence + * res0: Option[String Xor Int] = None + * }}} + */ def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] /** If F and G are both [[cats.Bitraverse]] then so is their composition F[G[_, _], G[_, _]] */ diff --git a/core/src/main/scala/cats/functor/Bifunctor.scala b/core/src/main/scala/cats/functor/Bifunctor.scala index 6a8bee5322..9f06e6e7f7 100644 --- a/core/src/main/scala/cats/functor/Bifunctor.scala +++ b/core/src/main/scala/cats/functor/Bifunctor.scala @@ -10,6 +10,15 @@ trait Bifunctor[F[_, _]] extends Any with Serializable { /** * The quintessential method of the Bifunctor trait, it applies a * function to each "side" of the bifunctor. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * + * scala> val x: (List[String], Int) = (List("foo", "bar"), 3) + * scala> x.bimap(_.headOption, _.toLong + 1) + * res0: (Option[String], Long) = (Some(foo),4) + * }}} */ def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] From 4bc34cce03168173c4f92d52dc69badf71df73ef Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Fri, 15 Jul 2016 08:09:49 -0400 Subject: [PATCH 4/4] Use fancy characters for ComposedBifunctor type parameters --- core/src/main/scala/cats/functor/Bifunctor.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/functor/Bifunctor.scala b/core/src/main/scala/cats/functor/Bifunctor.scala index 9f06e6e7f7..3feefb9fda 100644 --- a/core/src/main/scala/cats/functor/Bifunctor.scala +++ b/core/src/main/scala/cats/functor/Bifunctor.scala @@ -54,7 +54,7 @@ object Bifunctor { } private[cats] trait ComposedBifunctor[F[_, _], G[_, _]] - extends Bifunctor.Default[λ[(A, B) => F[G[A, B], G[A, B]]]] { + extends Bifunctor.Default[λ[(α, β) => F[G[α, β], G[α, β]]]] { def F: Bifunctor[F] def G: Bifunctor[G]