Skip to content

Commit

Permalink
2228-add MonadError instance for optionT where F is a Monad (#2299)
Browse files Browse the repository at this point in the history
* added MonadError instance for OptionT where F is a Monad

* test added

* removed duplicate code using OptionTMonad[F]
  • Loading branch information
heyrutvik authored and kailuowang committed Jun 19, 2018
1 parent 1a51beb commit b0f871b
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 0 deletions.
15 changes: 15 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ private[data] sealed abstract class OptionTInstances1 extends OptionTInstances2

implicit def catsDataEqForOptionT[F[_], A](implicit F0: Eq[F[Option[A]]]): Eq[OptionT[F, A]] =
new OptionTEq[F, A] { implicit val F = F0 }

implicit def catsDataMonadErrorMonadForOptionT[F[_]](implicit F0: Monad[F]): MonadError[OptionT[F, ?], Unit] =
new OptionTMonadErrorMonad[F] { implicit val F = F0 }
}

private[data] sealed abstract class OptionTInstances2 extends OptionTInstances3 {
Expand Down Expand Up @@ -287,6 +290,18 @@ private[data] trait OptionTMonad[F[_]] extends Monad[OptionT[F, ?]] {
)))
}

private[data] trait OptionTMonadErrorMonad[F[_]] extends MonadError[OptionT[F, ?], Unit] with OptionTMonad[F] {
implicit def F: Monad[F]

override def raiseError[A](e: Unit): OptionT[F, A] = OptionT.none

override def handleErrorWith[A](fa: OptionT[F, A])(f: Unit => OptionT[F, A]): OptionT[F, A] =
OptionT(F.flatMap(fa.value) {
case s @ Some(_) => F.pure(s)
case None => f(()).value
})
}

private trait OptionTMonadError[F[_], E] extends MonadError[OptionT[F, ?], E] with OptionTMonad[F] {
override def F: MonadError[F, E]

Expand Down
7 changes: 7 additions & 0 deletions tests/src/test/scala/cats/tests/OptionTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ class OptionTSuite extends CatsSuite {
checkAll("Semigroup[OptionT[ListWrapper, Int]]", SerializableTests.serializable(Semigroup[OptionT[ListWrapper, Int]]))
}

{
// MonadError instance where F has a Monad
implicit val F = ListWrapper.monad
checkAll("OptionT[ListWrapper, Int]", MonadErrorTests[OptionT[ListWrapper, ?], Unit].monadError[Int, Int, Int])
checkAll("MonadError[OptionT[List, ?]]", SerializableTests.serializable(MonadError[OptionT[ListWrapper, ?], Unit]))
}

test("fold and cata consistent") {
forAll { (o: OptionT[List, Int], s: String, f: Int => String) =>
o.fold(s)(f) should === (o.cata(s, f))
Expand Down

0 comments on commit b0f871b

Please sign in to comment.