Skip to content

Commit

Permalink
Override some methods in Kleisli instances (#1618)
Browse files Browse the repository at this point in the history
* Override some methods in Kleisli instances

- Switch the order of the traits so that some methods are overridden by
  the implementation in other type class instances in its hierarchy.
- Add a `MonadReader` test for `Reader`

* Use more consistent implicit parameters
  • Loading branch information
peterneyens authored and kailuowang committed Apr 21, 2017
1 parent 50741da commit c1dcd40
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 107 deletions.
189 changes: 82 additions & 107 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ private[data] sealed trait KleisliFunctions {

private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {

implicit def catsDataMonoidForKleisli[F[_], A, B](implicit M: Monoid[F[B]]): Monoid[Kleisli[F, A, B]] =
new KleisliMonoid[F, A, B] { def FB: Monoid[F[B]] = M }
implicit def catsDataMonoidForKleisli[F[_], A, B](implicit FB0: Monoid[F[B]]): Monoid[Kleisli[F, A, B]] =
new KleisliMonoid[F, A, B] { def FB: Monoid[F[B]] = FB0 }

implicit def catsDataMonoidKForKleisli[F[_]](implicit M: Monad[F]): MonoidK[λ[α => Kleisli[F, α, α]]] =
Category[Kleisli[F, ?, ?]].algebraK

implicit val catsDataMonoidKForKleisliId: MonoidK[λ[α => Kleisli[Id, α, α]]] =
catsDataMonoidKForKleisli[Id]

implicit def catsDataArrowForKleisli[F[_]](implicit ev: Monad[F]): Arrow[Kleisli[F, ?, ?]] =
new KleisliArrow[F] { def F: Monad[F] = ev }
implicit def catsDataArrowForKleisli[F[_]](implicit M: Monad[F]): Arrow[Kleisli[F, ?, ?]] =
new KleisliArrow[F] { def F: Monad[F] = M }

implicit val catsDataArrowForKleisliId: Arrow[Kleisli[Id, ?, ?]] =
catsDataArrowForKleisli[Id]
Expand All @@ -102,7 +102,7 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {

implicit def catsDataContravariantForKleisli[F[_], C]: Contravariant[Kleisli[F, ?, C]] =
new Contravariant[Kleisli[F, ?, C]] {
override def contramap[A, B](fa: Kleisli[F, A, C])(f: (B) => A): Kleisli[F, B, C] =
override def contramap[A, B](fa: Kleisli[F, A, C])(f: B => A): Kleisli[F, B, C] =
fa.local(f)
}

Expand All @@ -113,114 +113,70 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
def liftT[M[_], B](ma: M[B])(implicit ev: Trivial): Kleisli[M, A, B] = Kleisli.lift(ma)
}

implicit def catsDataApplicativeErrorForKleisli[F[_], A, E](implicit AE: ApplicativeError[F, E]): ApplicativeError[Kleisli[F, A, ?], E]
= new KleisliApplicativeError[F, A, E] { implicit def AF: ApplicativeError[F, E] = AE }
implicit def catsDataApplicativeErrorForKleisli[F[_], A, E](implicit AE: ApplicativeError[F, E]): ApplicativeError[Kleisli[F, A, ?], E] =
new KleisliApplicativeError[F, A, E] { def F: ApplicativeError[F, E] = AE }
}

private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 {

implicit def catsDataMonadErrorForKleisli[F[_], A, E](
implicit me: MonadError[F, E]
): MonadError[Kleisli[F, A, ?], E] with MonadReader[Kleisli[F, A, ?], A] = {
new KleisliApplicativeError[F, A, E]
with KleisliMonadReader[F, A]
with MonadError[Kleisli[F, A, ?], E] {
override def M: Monad[F] = me
override def AF: ApplicativeError[F, E] = me
}
}
implicit def catsDataMonadErrorForKleisli[F[_], A, E](implicit ME: MonadError[F, E]): MonadError[Kleisli[F, A, ?], E] =
new KleisliMonadError[F, A, E] { def F: MonadError[F, E] = ME }
}

private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 {

implicit def catsDataMonadReaderForKleisli[F[_]: Monad, A](implicit m: Monad[F]): MonadReader[Kleisli[F, A, ?], A] = {
new KleisliMonadReader[F, A] {
override def M: Monad[F] = m
}
}
implicit def catsDataMonadReaderForKleisli[F[_], A](implicit M: Monad[F]): MonadReader[Kleisli[F, A, ?], A] =
new KleisliMonadReader[F, A] { def F: Monad[F] = M }
}

private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 {
implicit def catsDataChoiceForKleisli[F[_]](implicit ev: Monad[F]): Choice[Kleisli[F, ?, ?]] =
new Choice[Kleisli[F, ?, ?]] {
def id[A]: Kleisli[F, A, A] = Kleisli(ev.pure)

def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Either[A, B], C] =
Kleisli(_.fold(f.run, g.run))

def compose[A, B, C](f: Kleisli[F, B, C], g: Kleisli[F, A, B]): Kleisli[F, A, C] =
f.compose(g)
}
implicit def catsDataChoiceForKleisli[F[_]](implicit M: Monad[F]): Choice[Kleisli[F, ?, ?]] =
new KleisliChoice[F] { def F: Monad[F] = M }

implicit val catsDataChoiceForKleisliId: Choice[Kleisli[Id, ?, ?]] =
catsDataChoiceForKleisli[Id]

implicit def catsDataSplitForKleisli[F[_]](implicit ev: FlatMap[F]): Split[Kleisli[F, ?, ?]] =
new KleisliSplit[F] { def F: FlatMap[F] = ev }
implicit def catsDataSplitForKleisli[F[_]](implicit FM: FlatMap[F]): Split[Kleisli[F, ?, ?]] =
new KleisliSplit[F] { def F: FlatMap[F] = FM }

implicit def catsDataStrongForKleisli[F[_]](implicit ev: Functor[F]): Strong[Kleisli[F, ?, ?]] =
new KleisliStrong[F] { def F: Functor[F] = ev }
implicit def catsDataStrongForKleisli[F[_]](implicit F0: Functor[F]): Strong[Kleisli[F, ?, ?]] =
new KleisliStrong[F] { def F: Functor[F] = F0 }

implicit def catsDataFlatMapForKleisli[F[_], A](implicit ev: FlatMap[F]): FlatMap[Kleisli[F, A, ?]] =
new KleisliFlatMap[F, A] { def FM: FlatMap[F] = ev }
implicit def catsDataFlatMapForKleisli[F[_], A](implicit FM: FlatMap[F]): FlatMap[Kleisli[F, A, ?]] =
new KleisliFlatMap[F, A] { def F: FlatMap[F] = FM }

implicit def catsDataSemigroupForKleisli[F[_], A, B](implicit M: Semigroup[F[B]]): Semigroup[Kleisli[F, A, B]] =
new KleisliSemigroup[F, A, B] { def FB: Semigroup[F[B]] = M }
implicit def catsDataSemigroupForKleisli[F[_], A, B](implicit FB0: Semigroup[F[B]]): Semigroup[Kleisli[F, A, B]] =
new KleisliSemigroup[F, A, B] { def FB: Semigroup[F[B]] = FB0 }

implicit def catsDataSemigroupKForKleisli[F[_]](implicit ev: FlatMap[F]): SemigroupK[λ[α => Kleisli[F, α, α]]] =
implicit def catsDataSemigroupKForKleisli[F[_]](implicit FM: FlatMap[F]): SemigroupK[λ[α => Kleisli[F, α, α]]] =
Compose[Kleisli[F, ?, ?]].algebraK
}

private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 {
implicit def catsDataApplicativeForKleisli[F[_], A](implicit A : Applicative[F]): Applicative[Kleisli[F, A, ?]] = new KleisliApplicative[F, A] {
implicit def F: Applicative[F] = A
}
implicit def catsDataApplicativeForKleisli[F[_], A](implicit A: Applicative[F]): Applicative[Kleisli[F, A, ?]] =
new KleisliApplicative[F, A] { def F: Applicative[F] = A }
}

private[data] sealed abstract class KleisliInstances4 extends KleisliInstances5 {
implicit def catsDataApplyForKleisli[F[_]: Apply, A]: Apply[Kleisli[F, A, ?]] = new Apply[Kleisli[F, A, ?]] {
def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
fa.ap(f)

override def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
Kleisli(a => Apply[F].product(fb.run(a), fc.run(a)))

def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fa.map(f)
}
implicit def catsDataApplyForKleisli[F[_], A](implicit A: Apply[F]): Apply[Kleisli[F, A, ?]] =
new KleisliApply[F, A] { def F: Apply[F] = A }
}

private[data] sealed abstract class KleisliInstances5 {
implicit def catsDataFunctorForKleisli[F[_]: Functor, A]: Functor[Kleisli[F, A, ?]] = new Functor[Kleisli[F, A, ?]] {
def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fa.map(f)
}
implicit def catsDataFunctorForKleisli[F[_], A](implicit F0: Functor[F]): Functor[Kleisli[F, A, ?]] =
new KleisliFunctor[F, A] { def F: Functor[F] = F0 }
}

private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSplit[F] with KleisliStrong[F] {
private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSplit[F] with KleisliStrong[F] with KleisliCategory[F] {
implicit def F: Monad[F]

def lift[A, B](f: A => B): Kleisli[F, A, B] =
Kleisli(a => F.pure(f(a)))

def id[A]: Kleisli[F, A, A] =
Kleisli(a => F.pure(a))

override def second[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (C, A), (C, B)] =
super[KleisliStrong].second(fa)

override def split[A, B, C, D](f: Kleisli[F, A, B], g: Kleisli[F, C, D]): Kleisli[F, (A, C), (B, D)] =
super[KleisliSplit].split(f, g)
}

private trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] {
private trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] with KleisliCompose[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)] =
override def split[A, B, C, D](f: Kleisli[F, A, B], g: Kleisli[F, C, D]): Kleisli[F, (A, C), (B, D)] =
Kleisli{ case (a, c) => F.flatMap(f.run(a))(b => F.map(g.run(c))(d => (b, d))) }

def compose[A, B, C](f: Kleisli[F, B, C], g: Kleisli[F, A, B]): Kleisli[F, A, C] =
f.compose(g)
}

private trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] {
Expand All @@ -238,10 +194,28 @@ private trait KleisliStrong[F[_]] extends Strong[Kleisli[F, ?, ?]] {
def first[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (A, C), (B, C)] =
fa.first[C]

def second[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (C, A), (C, B)] =
override def second[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (C, A), (C, B)] =
fa.second[C]
}

private trait KleisliChoice[F[_]] extends Choice[Kleisli[F, ?, ?]] with KleisliCategory[F] {
def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Either[A, B], C] =
Kleisli(_.fold(f.run, g.run))
}

private trait KleisliCategory[F[_]] extends Category[Kleisli[F, ?, ?]] with KleisliCompose[F] {
implicit def F: Monad[F]

def id[A]: Kleisli[F, A, A] = Kleisli.ask[F, A]
}

private trait KleisliCompose[F[_]] extends Compose[Kleisli[F, ?, ?]] {
implicit def F: FlatMap[F]

def compose[A, B, C](f: Kleisli[F, B, C], g: Kleisli[F, A, B]): Kleisli[F, A, C] =
f.compose(g)
}

private trait KleisliSemigroup[F[_], A, B] extends Semigroup[Kleisli[F, A, B]] {
implicit def FB: Semigroup[F[B]]

Expand All @@ -255,63 +229,64 @@ private trait KleisliMonoid[F[_], A, B] extends Monoid[Kleisli[F, A, B]] with Kl
override def empty: Kleisli[F, A, B] = Kleisli[F, A, B](a => FB.empty)
}

private trait KleisliApplicativeError[F[_], A, E] extends KleisliApplicative[F, A] with ApplicativeError[Kleisli[F, A, ?], E] {
type K[T] = Kleisli[F, A, T]
private trait KleisliMonadError[F[_], A, E] extends MonadError[Kleisli[F, A, ?], E] with KleisliApplicativeError[F, A, E] with KleisliMonadReader[F, A] {
def F: MonadError[F, E]
}

implicit def AF: ApplicativeError[F, E]
private trait KleisliApplicativeError[F[_], A, E] extends ApplicativeError[Kleisli[F, A, ?], E] with KleisliApplicative[F, A] {
type K[T] = Kleisli[F, A, T]

implicit def F: Applicative[F] = AF
implicit def F: ApplicativeError[F, E]

def raiseError[B](e: E): K[B] = Kleisli(_ => AF.raiseError(e))
def raiseError[B](e: E): K[B] = Kleisli(_ => F.raiseError(e))

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))
F.handleErrorWith(kb.run(a))((e: E) => f(e).run(a))
}

}

private trait KleisliMonadReader[F[_], A] extends KleisliFlatMap[F, A] with KleisliApplicative[F, A] with MonadReader[Kleisli[F, A, ?], A] {

def M: Monad[F]

override def F: Applicative[F] = M
override def FM: FlatMap[F] = M

val ask: Kleisli[F, A, A] = Kleisli(M.pure)
private trait KleisliMonadReader[F[_], A] extends MonadReader[Kleisli[F, A, ?], A] with KleisliMonad[F, A] {
implicit def F: Monad[F]

def local[B](f: A => A)(fa: Kleisli[F, A, B]): Kleisli[F, A, B] =
Kleisli(f.andThen(fa.run))
val ask: Kleisli[F, A, A] = Kleisli.ask[F, A]

override def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
super[KleisliApplicative].ap(f)(fa)
def local[B](f: A => A)(fa: Kleisli[F, A, B]): Kleisli[F, A, B] = Kleisli.local(f)(fa)
}

private trait KleisliFlatMap[F[_], A] extends FlatMap[Kleisli[F, A, ?]] {
private trait KleisliMonad[F[_], A] extends Monad[Kleisli[F, A, ?]] with KleisliFlatMap[F, A] with KleisliApplicative[F, A] {
implicit def F: Monad[F]
}

implicit def FM: FlatMap[F]
private trait KleisliFlatMap[F[_], A] extends FlatMap[Kleisli[F, A, ?]] with KleisliApply[F, A] {
implicit def F: FlatMap[F]

def flatMap[B, C](fa: Kleisli[F, A, B])(f: B => Kleisli[F, A, C]): Kleisli[F, A, C] =
fa.flatMap(f)

def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fa.map(f)

def tailRecM[B, C](b: B)(f: B => Kleisli[F, A, Either[B, C]]): Kleisli[F, A, C] =
Kleisli[F, A, C]({ a => FlatMap[F].tailRecM(b) { f(_).run(a) } })
Kleisli[F, A, C]({ a => F.tailRecM(b) { f(_).run(a) } })
}

private trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A, ?]] {
private trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A, ?]] with KleisliApply[F, A] {
implicit def F: Applicative[F]

def pure[B](x: B): Kleisli[F, A, B] =
Kleisli.pure[F, A, B](x)
}

def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
fa.ap(f)
private trait KleisliApply[F[_], A] extends Apply[Kleisli[F, A, ?]] with KleisliFunctor[F, A] {
implicit def F: Apply[F]

override def map[B, C](fb: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fb.map(f)
override def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
fa.ap(f)

override def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
Kleisli(a => Applicative[F].product(fb.run(a), fc.run(a)))
Kleisli(a => F.product(fb.run(a), fc.run(a)))
}

private trait KleisliFunctor[F[_], A] extends Functor[Kleisli[F, A, ?]] {
implicit def F: Functor[F]

override def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fa.map(f)
}
8 changes: 8 additions & 0 deletions tests/src/test/scala/cats/tests/KleisliTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class KleisliTests extends CatsSuite {
kleisliEq

implicit val eitherTEq = EitherT.catsDataEqForEitherT[Kleisli[Option, Int, ?], Unit, Int]
implicit val eitherTEq2 = EitherT.catsDataEqForEitherT[Reader[Int, ?], Unit, Int]

implicit val iso = CartesianTests.Isomorphisms.invariant[Kleisli[Option, Int, ?]]
implicit val iso2 = CartesianTests.Isomorphisms.invariant[Reader[Int, ?]]

checkAll("Kleisli[Option, Int, Int] with Unit", ApplicativeErrorTests[Kleisli[Option, Int, ?], Unit].applicativeError[Int, Int, Int])
checkAll("ApplicativeError[Kleisli[Option, Int, Int], Unit]", SerializableTests.serializable(ApplicativeError[Kleisli[Option, Int, ?], Unit]))
Expand Down Expand Up @@ -49,6 +51,12 @@ class KleisliTests extends CatsSuite {
checkAll("MonadReader[Kleisli[Option, ?, ?], Int]", SerializableTests.serializable(MonadReader[Kleisli[Option, Int, ?], Int]))
}

{
implicit val catsDataMonadReaderForReader = Kleisli.catsDataMonadReaderForKleisliId[Int]
checkAll("Reader[Int, Int]", MonadReaderTests[Reader[Int, ?], Int].monadReader[Int, Int, Int])
checkAll("MonadReader[Reader[?, ?], Int]", SerializableTests.serializable(MonadReader[Reader[Int, ?], Int]))
}

{
implicit val kleisliSplit = Kleisli.catsDataSplitForKleisli[Option]
checkAll("Kleisli[Option, Int, Int]", SplitTests[Kleisli[Option, ?, ?]].split[Int, Int, Int, Int, Int, Int])
Expand Down

0 comments on commit c1dcd40

Please sign in to comment.