Skip to content

Commit

Permalink
Make endo SemigroupK / MonoidK instances explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
peterneyens committed Oct 11, 2017
1 parent 1234535 commit 598e677
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 67 deletions.
75 changes: 18 additions & 57 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,42 +89,13 @@ private[data] sealed trait KleisliFunctions {
}

private[data] sealed trait KleisliExplicitInstances {
/**
* Create a `SemigroupK` instance for `Kleisli` using a `SemigroupK[F]`.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> implicit val sgk = Kleisli.semigroupKF[Option, Int]
* scala> def divBy(divisor: Int): Kleisli[Option, Int, String] =
* | Kleisli(n => if (n % divisor == 0) Some("divisible by " + divisor) else None)
* scala> val div2or3: Kleisli[Option, Int, String] = divBy(2) <+> divBy(3)
* scala> div2or3(2)
* res0: Option[String] = Some(divisible by 2)
* scala> div2or3(3)
* res1: Option[String] = Some(divisible by 3)
* scala> div2or3(5)
* res2: Option[String] = None
* scala> div2or3(6)
* res3: Option[String] = Some(divisible by 2)
* }}}
*/
def semigroupKF[F[_], A](implicit S: SemigroupK[F]): SemigroupK[Kleisli[F, A, ?]] =
new KleisliABSemigroupK[F, A] { def F: SemigroupK[F] = S }

/**
* Create a `MonoidK` instance for `Kleisli` using a `MonoidK[F]`.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val kl: Kleisli[List, Int, String] = Kleisli.monoidKF[List, Int].empty[String]
* scala> kl(1)
* res0: List[String] = List()
* }}}
*/
def monoidKF[F[_], A](implicit M: MonoidK[F]): MonoidK[Kleisli[F, A, ?]] =
new KleisliABMonoidK[F, A] { def F: MonoidK[F] = M }

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


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

private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
Expand Down Expand Up @@ -161,7 +132,6 @@ private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1
override def contramap[A, B](fa: Kleisli[F, A, C])(f: B => A): Kleisli[F, B, C] =
fa.local(f)
}

}

private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 {
Expand All @@ -175,11 +145,8 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3
}

private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 {
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 catsDataMonoidKForKleisli[F[_], A](implicit F0: MonoidK[F]): MonoidK[Kleisli[F, A, ?]] =
new KleisliMonoidK[F, A] { def F: MonoidK[F] = F0 }

implicit def catsDataFlatMapForKleisli[F[_], A](implicit FM: FlatMap[F]): FlatMap[Kleisli[F, A, ?]] =
new KleisliFlatMap[F, A] { def F: FlatMap[F] = FM }
Expand All @@ -201,8 +168,8 @@ private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4
}

private[data] sealed abstract class KleisliInstances4 extends KleisliInstances5 {
implicit def catsDataSemigroupKForKleisli[F[_]](implicit FM: FlatMap[F]): SemigroupK[λ[α => Kleisli[F, α, α]]] =
Compose[Kleisli[F, ?, ?]].algebraK
implicit def catsDataSemigroupKForKleisli[F[_], A](implicit F0: SemigroupK[F]): SemigroupK[Kleisli[F, A, ?]] =
new KleisliSemigroupK[F, A] { def F: SemigroupK[F] = F0 }

implicit def catsDataApplicativeErrorForKleisli[F[_], E, A](implicit F0: ApplicativeError[F, E]): ApplicativeError[Kleisli[F, A, ?], E] =
new KleisliApplicativeError[F, A, E] { def F: ApplicativeError[F, E] = F0 }
Expand Down Expand Up @@ -287,17 +254,21 @@ private[data] trait KleisliMonoid[F[_], A, B] extends Monoid[Kleisli[F, A, B]] w
override def empty: Kleisli[F, A, B] = Kleisli[F, A, B](_ => FB.empty)
}

private[data] sealed trait KleisliABSemigroupK[F[_], A] extends SemigroupK[Kleisli[F, A, ?]] {
private[data] sealed trait KleisliSemigroupK[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] {
private[data] sealed trait KleisliMonoidK[F[_], A] extends MonoidK[Kleisli[F, A, ?]] with KleisliSemigroupK[F, A] {
implicit def F: MonoidK[F]

override def empty[B]: Kleisli[F, A, B] = Kleisli(_ => F.empty[B])
override def empty[B]: Kleisli[F, A, B] = Kleisli.lift(F.empty[B])
}

private[data] trait KleisliAlternative[F[_], A] extends Alternative[Kleisli[F, A, ?]] with KleisliApplicative[F, A] with KleisliMonoidK[F, A] {
implicit def F: Alternative[F]
}

private[data] trait KleisliMonadError[F[_], A, E] extends MonadError[Kleisli[F, A, ?], E] with KleisliApplicativeError[F, A, E] with KleisliMonad[F, A] {
Expand Down Expand Up @@ -337,16 +308,6 @@ private[data] trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A
Kleisli.pure[F, A, B](x)
}

private[data] trait KleisliAlternative[F[_], A] extends Alternative[Kleisli[F, A, ?]] with KleisliApplicative[F, A] {
implicit def F: Alternative[F]

def empty[X]: Kleisli[F, A, X] =
Kleisli.lift(F.empty[X])

def combineK[X](x: ReaderT[F, A, X], y: ReaderT[F, A, X]): ReaderT[F, A, X] =
ReaderT[F, A, X](a => F.combineK(x(a), y(a)))
}

private[data] trait KleisliApply[F[_], A] extends Apply[Kleisli[F, A, ?]] with KleisliFunctor[F, A] {
implicit def F: Apply[F]

Expand Down
17 changes: 7 additions & 10 deletions tests/src/test/scala/cats/tests/KleisliTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,25 +118,25 @@ class KleisliTests extends CatsSuite {
}

{
implicit val catsDataMonoidKForKleisli = Kleisli.catsDataMonoidKForKleisli[Option]
implicit val catsDataMonoidKForKleisli = Kleisli.endoMonoidK[Option]
checkAll("Kleisli[Option, Int, Int]", MonoidKTests[λ[α => Kleisli[Option, α, α]]].monoidK[Int])
checkAll("MonoidK[λ[α => Kleisli[Option, α, α]]]", SerializableTests.serializable(catsDataMonoidKForKleisli))
}

{
implicit val catsDataSemigroupKForKleisli = Kleisli.catsDataSemigroupKForKleisli[Option]
implicit val catsDataSemigroupKForKleisli = Kleisli.endoSemigroupK[Option]
checkAll("Kleisli[Option, Int, Int]", SemigroupKTests[λ[α => Kleisli[Option, α, α]]].semigroupK[Int])
checkAll("SemigroupK[λ[α => Kleisli[Option, α, α]]]", SerializableTests.serializable(catsDataSemigroupKForKleisli))
}

{
implicit val semigroupk = Kleisli.semigroupKF[Option, String]
implicit val semigroupk = Kleisli.catsDataSemigroupKForKleisli[Option, String]
checkAll("Kleisli[Option, String, Int]", SemigroupKTests[Kleisli[Option, String, ?]].semigroupK[Int])
checkAll("SemigroupK[Kleisli[Option, String, ?]]", SerializableTests.serializable(semigroupk))
}

{
implicit val monoidk = Kleisli.monoidKF[Option, String]
implicit val monoidk = Kleisli.catsDataMonoidKForKleisli[Option, String]
checkAll("Kleisli[Option, String, Int]", MonoidKTests[Kleisli[Option, String, ?]].monoidK[Int])
checkAll("MonoidK[Kleisli[Option, String, ?]]", SerializableTests.serializable(monoidk))
}
Expand Down Expand Up @@ -234,45 +234,42 @@ class KleisliTests extends CatsSuite {
Functor[Kleisli[List, Int, ?]]
Apply[Kleisli[List, Int, ?]]
Applicative[Kleisli[List, Int, ?]]
Alternative[Kleisli[List, Int, ?]]
Monad[Kleisli[List, Int, ?]]
Monoid[Kleisli[List, Int, String]]
MonoidK[λ[α => Kleisli[List, α, α]]]
MonoidK[Kleisli[List, Int, ?]]
Arrow[Kleisli[List, ?, ?]]
Choice[Kleisli[List, ?, ?]]
Strong[Kleisli[List, ?, ?]]
FlatMap[Kleisli[List, Int, ?]]
Semigroup[Kleisli[List, Int, String]]
SemigroupK[λ[α => Kleisli[List, α, α]]]
SemigroupK[Kleisli[List, Int, ?]]

// F is Id
Functor[Kleisli[Id, Int, ?]]
Apply[Kleisli[Id, Int, ?]]
Applicative[Kleisli[Id, Int, ?]]
Monad[Kleisli[Id, Int, ?]]
Monoid[Kleisli[Id, Int, String]]
MonoidK[λ[α => Kleisli[Id, α, α]]]
Arrow[Kleisli[Id, ?, ?]]
CommutativeArrow[Kleisli[Id, ?, ?]]
Choice[Kleisli[Id, ?, ?]]
Strong[Kleisli[Id, ?, ?]]
FlatMap[Kleisli[Id, Int, ?]]
Semigroup[Kleisli[Id, Int, String]]
SemigroupK[λ[α => Kleisli[Id, α, α]]]

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

// using IntReader alias instead of Kleisli with Id as F and A as Int
type IntReader[A] = Reader[Int, A]
Expand Down

0 comments on commit 598e677

Please sign in to comment.