Skip to content

Commit

Permalink
Merge pull request #621 from ceedubs/kleisli-id-instances
Browse files Browse the repository at this point in the history
Add explicit Id instances for Kleisli
  • Loading branch information
non committed Nov 12, 2015
2 parents d50e1d4 + 2992586 commit c4626ee
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 14 deletions.
41 changes: 28 additions & 13 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,15 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
implicit def kleisliMonoidK[F[_]](implicit M: Monad[F]): MonoidK[Lambda[A => Kleisli[F, A, A]]] =
new KleisliMonoidK[F] { def F: Monad[F] = M }

implicit val kleisliIdMonoidK: MonoidK[Lambda[A => Kleisli[Id, A, A]]] =
kleisliMonoidK[Id]

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

implicit val kleisliIdArrow: Arrow[Kleisli[Id, ?, ?]] =
kleisliArrow[Id]

implicit def kleisliChoice[F[_]](implicit ev: Monad[F]): Choice[Kleisli[F, ?, ?]] =
new Choice[Kleisli[F, ?, ?]] {
def id[A]: Kleisli[F, A, A] = Kleisli(ev.pure(_))
Expand All @@ -103,19 +109,11 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
f.compose(g)
}

implicit def kleisliMonadReader[F[_]: Monad, A]: MonadReader[Kleisli[F, A, ?], A] =
new MonadReader[Kleisli[F, A, ?], A] {
def pure[B](x: B): Kleisli[F, A, B] =
Kleisli.pure[F, A, B](x)
implicit val kleisliIdChoice: Choice[Kleisli[Id, ?, ?]] =
kleisliChoice[Id]

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

val ask: Kleisli[F, A, A] = Kleisli(Monad[F].pure)

def local[B](f: A => A)(fa: Kleisli[F, A, B]): Kleisli[F, A, B] =
Kleisli(f.andThen(fa.run))
}
implicit def kleisliIdMonadReader[A]: MonadReader[Kleisli[Id, A, ?], A] =
kleisliMonadReader[Id, A]

implicit def kleisliContravariant[F[_], C]: Contravariant[Kleisli[F, ?, C]] =
new Contravariant[Kleisli[F, ?, C]] {
Expand Down Expand Up @@ -166,13 +164,30 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3
}
}

private[data] sealed abstract class KleisliInstances3 {
private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 {
implicit def kleisliFunctor[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)
}
}

private[data] sealed abstract class KleisliInstances4 {

implicit def kleisliMonadReader[F[_]: Monad, A]: MonadReader[Kleisli[F, A, ?], A] =
new MonadReader[Kleisli[F, A, ?], A] {
def pure[B](x: B): Kleisli[F, A, B] =
Kleisli.pure[F, A, B](x)

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

val ask: Kleisli[F, A, A] = Kleisli(Monad[F].pure)

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

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

Expand Down
66 changes: 65 additions & 1 deletion tests/src/test/scala/cats/tests/KleisliTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats
package tests

import cats.arrow.{Arrow, Choice, Split}
import cats.data.Kleisli
import cats.data.{Kleisli, Reader}
import cats.functor.{Contravariant, Strong}
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
Expand Down Expand Up @@ -133,4 +133,68 @@ class KleisliTests extends CatsSuite {
val config = Config(0, "cats")
kconfig1.run(config) should === (kconfig2.run(config))
}

/**
* Testing that implicit resolution works. If it compiles, the "test" passes.
*/
object ImplicitResolution {
// F is List
Functor[Kleisli[List, Int, ?]]
Apply[Kleisli[List, Int, ?]]
Applicative[Kleisli[List, Int, ?]]
Monad[Kleisli[List, Int, ?]]
MonadReader[Kleisli[List, Int, ?], Int]
Monoid[Kleisli[List, Int, String]]
MonoidK[Lambda[A => Kleisli[List, A, A]]]
Arrow[Kleisli[List, ?, ?]]
Choice[Kleisli[List, ?, ?]]
Split[Kleisli[List, ?, ?]]
Strong[Kleisli[List, ?, ?]]
FlatMap[Kleisli[List, Int, ?]]
Semigroup[Kleisli[List, Int, String]]
SemigroupK[Lambda[A => Kleisli[List, A, A]]]

// F is Id
Functor[Kleisli[Id, Int, ?]]
Apply[Kleisli[Id, Int, ?]]
Applicative[Kleisli[Id, Int, ?]]
Monad[Kleisli[Id, Int, ?]]
MonadReader[Kleisli[Id, Int, ?], Int]
Monoid[Kleisli[Id, Int, String]]
MonoidK[Lambda[A => Kleisli[Id, A, A]]]
Arrow[Kleisli[Id, ?, ?]]
Choice[Kleisli[Id, ?, ?]]
Split[Kleisli[Id, ?, ?]]
Strong[Kleisli[Id, ?, ?]]
FlatMap[Kleisli[Id, Int, ?]]
Semigroup[Kleisli[Id, Int, String]]
SemigroupK[Lambda[A => Kleisli[Id, A, A]]]

// using Reader alias instead of Kleisli with Id as F
Functor[Reader[Int, ?]]
Apply[Reader[Int, ?]]
Applicative[Reader[Int, ?]]
Monad[Reader[Int, ?]]
MonadReader[Reader[Int, ?], Int]
Monoid[Reader[Int, String]]
MonoidK[Lambda[A => Reader[A, A]]]
Arrow[Reader[?, ?]]
Choice[Reader[?, ?]]
Split[Reader[?, ?]]
Strong[Reader[?, ?]]
FlatMap[Reader[Int, ?]]
Semigroup[Reader[Int, String]]
SemigroupK[Lambda[A => Reader[A, A]]]

// using IntReader alias instead of Kleisli with Id as F and A as Int
type IntReader[A] = Reader[Int, A]
Functor[IntReader]
Apply[IntReader]
Applicative[IntReader]
Monad[IntReader]
MonadReader[IntReader, Int]
Monoid[IntReader[String]]
FlatMap[IntReader]
Semigroup[IntReader[String]]
}
}

0 comments on commit c4626ee

Please sign in to comment.