Skip to content

Commit

Permalink
Kleisli MonadError instance
Browse files Browse the repository at this point in the history
  • Loading branch information
adelbertc committed Jul 30, 2015
1 parent e8dc3f1 commit 7d1b0c4
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
26 changes: 22 additions & 4 deletions core/src/main/scala/scalaz/Kleisli.scala
Expand Up @@ -85,14 +85,15 @@ final case class Kleisli[M[_], A, B](run: A => M[B]) { self =>
//
// Prioritized Implicits for type class instances
//
sealed abstract class KleisliInstances8 {

sealed abstract class KleisliInstances9 {
implicit def kleisliFunctor[F[_], R](implicit F0: Functor[F]): Functor[Kleisli[F, R, ?]] =
new KleisliFunctor[F, R] {
implicit def F: Functor[F] = F0
}
}

sealed abstract class KleisliInstances7 extends KleisliInstances8 {
sealed abstract class KleisliInstances8 extends KleisliInstances9 {

implicit def kleisliApply[F[_], R](implicit F0: Apply[F]): Apply[Kleisli[F, R, ?]] =
new KleisliApply[F, R] {
Expand All @@ -105,7 +106,7 @@ sealed abstract class KleisliInstances7 extends KleisliInstances8 {
}
}

sealed abstract class KleisliInstances6 extends KleisliInstances7 {
sealed abstract class KleisliInstances7 extends KleisliInstances8 {
implicit def kleisliApplicative[F[_], R](implicit F0: Applicative[F]): Applicative[Kleisli[F, R, ?]] =
new KleisliApplicative[F, R] {
implicit def F: Applicative[F] = F0
Expand All @@ -117,7 +118,7 @@ sealed abstract class KleisliInstances6 extends KleisliInstances7 {
}
}

sealed abstract class KleisliInstances5 extends KleisliInstances6 {
sealed abstract class KleisliInstances6 extends KleisliInstances7 {
implicit def kleisliApplicativePlus[F[_], R](implicit F0: ApplicativePlus[F]): ApplicativePlus[Kleisli[F, R, ?]] =
new ApplicativePlus[Kleisli[F, R, ?]] with KleisliApplicative[F, R] with KleisliPlusEmpty[F, R] {
implicit def F: ApplicativePlus[F] = F0
Expand All @@ -129,6 +130,13 @@ sealed abstract class KleisliInstances5 extends KleisliInstances6 {
}
}

sealed abstract class KleisliInstances5 extends KleisliInstances6 {
implicit def kleisliMonadError[F[_, _], E, R](implicit F0: MonadError[F, E]): MonadError[Lambda[(E0, A) => Kleisli[F[E0, ?], R, A]], E] =
new KleisliMonadError[F, E, R] {
implicit def F = F0
}
}

sealed abstract class KleisliInstances4 extends KleisliInstances5 {
implicit def kleisliMonadPlus[F[_], A](implicit F0: MonadPlus[F]): MonadPlus[Kleisli[F, A, ?]] =
new KleisliMonadPlus[F, A] {
Expand Down Expand Up @@ -309,6 +317,16 @@ private trait KleisliMonadPlus[F[_], R] extends MonadPlus[Kleisli[F, R, ?]] with
implicit def F: MonadPlus[F]
}

private trait KleisliMonadError[F[_, _], E, R] extends MonadError[Lambda[(E0, A) => Kleisli[F[E0, ?], R, A]], E] with KleisliMonad[F[E, ?], R] {
implicit def F: MonadError[F, E]

def handleError[A](fa: Kleisli[F[E, ?], R, A])(f: E => Kleisli[F[E, ?], R, A]): Kleisli[F[E, ?], R, A] =
Kleisli.kleisli[F[E, ?], R, A](r => F.handleError(fa.run(r))(e => f(e).run(r)))

def raiseError[A](e: E): Kleisli[F[E, ?], R, A] =
Kleisli.kleisli[F[E, ?], R, A](_ => F.raiseError(e))
}

private trait KleisliContravariant[F[_], X] extends Contravariant[Kleisli[F, ?, X]] {
def contramap[A, B](fa: Kleisli[F, A, X])(f: B => A) = fa local f
}
Expand Down
11 changes: 9 additions & 2 deletions tests/src/test/scala/scalaz/KleisliTest.scala
Expand Up @@ -4,6 +4,7 @@ import std.AllInstances._
import scalaz.scalacheck.ScalazProperties._
import scalaz.scalacheck.ScalazArbitrary._
import org.scalacheck.{Prop, Gen, Arbitrary}
import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.Prop.forAll

object KleisliTest extends SpecLite {
Expand All @@ -25,14 +26,20 @@ object KleisliTest extends SpecLite {
M.equal(mb1, mb2)
}
}


// Needed because scalac inference has trouble with \/
implicit def KleisliDisjunctionArbitrary[E : Arbitrary, R : Arbitrary, A : Arbitrary]: Arbitrary[Kleisli[\/[E, ?], R, A]] = KleisliArbitrary[\/[E, +?], R, A]

implicit def KleisliDisjunctionEqual[E : Equal] = KleisliEqual[\/[E, ?]]

"mapK" ! forAll {
(f: Int => Option[Int], a: Int) =>
(f: Int => Option[Int], a: Int) =>
Kleisli(f).mapK(_.toList.map(_.toString)).run(a) must_===(f(a).toList.map(_.toString))
}

checkAll(monoid.laws[KleisliOptInt[Int]])
checkAll(monadPlus.strongLaws[KleisliOptInt])
checkAll(monadError.laws[Lambda[(E0, A) => Kleisli[\/[E0, ?], Int, A]], Int])
checkAll(category.laws[KleisliOpt])

object instances {
Expand Down

0 comments on commit 7d1b0c4

Please sign in to comment.