diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 92e68495560..2eb6c5a1fff 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -91,6 +91,9 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { implicit val catsDataMonoidKForKleisliId: MonoidK[λ[α => Kleisli[Id, α, α]]] = catsDataMonoidKForKleisli[Id] + implicit def catsDataMonoidKForKleisliAB[F[_], A](implicit M: MonoidK[F]): MonoidK[Kleisli[F, A, ?]] = + new KleisliABMonoidK[F, A] { def F: MonoidK[F] = M } + implicit def catsDataArrowForKleisli[F[_]](implicit ev: Monad[F]): Arrow[Kleisli[F, ?, ?]] = new KleisliArrow[F] { def F: Monad[F] = ev } @@ -152,6 +155,8 @@ private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 implicit def catsDataSemigroupKForKleisli[F[_]](implicit ev: FlatMap[F]): SemigroupK[λ[α => Kleisli[F, α, α]]] = new KleisliSemigroupK[F] { def F: FlatMap[F] = ev } + implicit def catsDataSemigroupKForKleisliAB[F[_], A](implicit S: SemigroupK[F]): SemigroupK[Kleisli[F, A, ?]] = + new KleisliABSemigroupK[F, A] { def F: SemigroupK[F] = S } } private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 { @@ -181,7 +186,6 @@ private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 } private[data] sealed abstract class KleisliInstances4 { - implicit def catsDataMonadReaderForKleisli[F[_]: Monad, A]: MonadReader[Kleisli[F, A, ?], A] = new MonadReader[Kleisli[F, A, ?], A] { def pure[B](x: B): Kleisli[F, A, B] = @@ -197,7 +201,7 @@ private[data] sealed abstract class KleisliInstances4 { } } -private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSplit[F] with KleisliStrong[F] { +private[data] trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSplit[F] with KleisliStrong[F] { implicit def F: Monad[F] def lift[A, B](f: A => B): Kleisli[F, A, B] = @@ -213,7 +217,7 @@ private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSpl super[KleisliSplit].split(f, g) } -private trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] { +private[data] trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] { implicit def F: FlatMap[F] def split[A, B, C, D](f: Kleisli[F, A, B], g: Kleisli[F, C, D]): Kleisli[F, (A, C), (B, D)] = @@ -223,7 +227,7 @@ private trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] { f.compose(g) } -private trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] { +private[data] trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] { implicit def F: Functor[F] override def lmap[A, B, C](fab: Kleisli[F, A, B])(f: C => A): Kleisli[F, C, B] = @@ -242,33 +246,45 @@ private trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] { fa.second[C] } -private trait KleisliSemigroup[F[_], A, B] extends Semigroup[Kleisli[F, A, B]] { +private[data] trait KleisliSemigroup[F[_], A, B] extends Semigroup[Kleisli[F, A, B]] { implicit def FB: Semigroup[F[B]] override def combine(a: Kleisli[F, A, B], b: Kleisli[F, A, B]): Kleisli[F, A, B] = Kleisli[F, A, B](x => FB.combine(a.run(x), b.run(x))) } -private trait KleisliMonoid[F[_], A, B] extends Monoid[Kleisli[F, A, B]] with KleisliSemigroup[F, A, B] { +private[data] trait KleisliMonoid[F[_], A, B] extends Monoid[Kleisli[F, A, B]] with KleisliSemigroup[F, A, B] { implicit def FB: Monoid[F[B]] override def empty: Kleisli[F, A, B] = Kleisli[F, A, B](a => FB.empty) } -private trait KleisliSemigroupK[F[_]] extends SemigroupK[λ[α => Kleisli[F, α, α]]] { +private[data] trait KleisliSemigroupK[F[_]] extends SemigroupK[λ[α => Kleisli[F, α, α]]] { implicit def F: FlatMap[F] override def combineK[A](a: Kleisli[F, A, A], b: Kleisli[F, A, A]): Kleisli[F, A, A] = a compose b } -private trait KleisliMonoidK[F[_]] extends MonoidK[λ[α => Kleisli[F, α, α]]] with KleisliSemigroupK[F] { +private[data] trait KleisliMonoidK[F[_]] extends MonoidK[λ[α => Kleisli[F, α, α]]] with KleisliSemigroupK[F] { implicit def F: Monad[F] override def empty[A]: Kleisli[F, A, A] = Kleisli(F.pure[A]) } +private[data] sealed trait KleisliABSemigroupK[F[_], A] extends SemigroupK[Kleisli[F, A, ?]] { + implicit def F: SemigroupK[F] + + override def combineK[B](x: Kleisli[F, A, B], y: Kleisli[F, A, B]): Kleisli[F, A, B] = + Kleisli(a => F.combineK(x.run(a), y.run(a))) +} + +private[data] sealed trait KleisliABMonoidK[F[_], A] extends MonoidK[Kleisli[F, A, ?]] with KleisliABSemigroupK[F, A] { + implicit def F: MonoidK[F] -private trait KleisliApplicativeError[F[_], A, E] extends KleisliApplicative[F, A] with ApplicativeError[Kleisli[F, A, ?], E] { + override def empty[B]: Kleisli[F, A, B] = Kleisli(_ => F.empty[B]) +} + +private[data] trait KleisliApplicativeError[F[_], A, E] extends KleisliApplicative[F, A] with ApplicativeError[Kleisli[F, A, ?], E] { type K[T] = Kleisli[F, A, T] implicit def AF: ApplicativeError[F, E] @@ -280,11 +296,9 @@ private trait KleisliApplicativeError[F[_], A, E] extends KleisliApplicative[F, def handleErrorWith[B](kb: K[B])(f: E => K[B]): K[B] = Kleisli { a: A => AF.handleErrorWith(kb.run(a))((e: E) => f(e).run(a)) } - } - -private trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A, ?]] { +private[data] trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A, ?]] { implicit def F: Applicative[F] def pure[B](x: B): Kleisli[F, A, B] = diff --git a/core/src/main/scala/cats/std/function.scala b/core/src/main/scala/cats/std/function.scala index 486e12ad1ec..fdb89d687a5 100644 --- a/core/src/main/scala/cats/std/function.scala +++ b/core/src/main/scala/cats/std/function.scala @@ -71,7 +71,7 @@ private[std] sealed trait Function1Instances extends Function1Instances0 { def compose[A, B, C](f: B => C, g: A => B): A => C = f.compose(g) } - implicit def catsStdMonoidForFunction1[A,B](implicit M: Monoid[B]): Monoid[A => B] = + implicit def catsStdMonoidForFunction1[A, B](implicit M: Monoid[B]): Monoid[A => B] = new Function1Monoid[A, B] { def B: Monoid[B] = M } implicit val catsStdMonoidKForFunction1: MonoidK[λ[α => α => α]] = diff --git a/tests/src/test/scala/cats/tests/KleisliTests.scala b/tests/src/test/scala/cats/tests/KleisliTests.scala index 451a80685c8..f59bae44b84 100644 --- a/tests/src/test/scala/cats/tests/KleisliTests.scala +++ b/tests/src/test/scala/cats/tests/KleisliTests.scala @@ -103,6 +103,18 @@ class KleisliTests extends CatsSuite { checkAll("SemigroupK[λ[α => Kleisli[Option, α, α]]]", SerializableTests.serializable(catsDataSemigroupKForKleisli)) } + { + implicit val catsDataSemigroupKForKleisliAB = Kleisli.catsDataSemigroupKForKleisliAB[Option, String] + checkAll("Kleisli[Option, String, Int]", SemigroupKTests[Kleisli[Option, String, ?]].semigroupK[Int]) + checkAll("SemigroupK[Kleisli[Option, String, ?]]", SerializableTests.serializable(catsDataSemigroupKForKleisliAB)) + } + + { + implicit val catsDataMonoidKForKleisliAB = Kleisli.catsDataMonoidKForKleisliAB[Option, String] + checkAll("Kleisli[Option, String, Int]", MonoidKTests[Kleisli[Option, String, ?]].monoidK[Int]) + checkAll("MonoidK[Kleisli[Option, String, ?]]", SerializableTests.serializable(catsDataMonoidKForKleisliAB)) + } + checkAll("Kleisli[Option, ?, Int]", ContravariantTests[Kleisli[Option, ?, Int]].contravariant[Int, Int, Int]) checkAll("Contravariant[Kleisli[Option, ?, Int]]", SerializableTests.serializable(Contravariant[Kleisli[Option, ?, Int]]))