From b0f871b5a65054b9cfc130a88d3b966a33893275 Mon Sep 17 00:00:00 2001 From: Rutvik Patel Date: Wed, 20 Jun 2018 01:50:56 +0530 Subject: [PATCH] 2228-add MonadError instance for optionT where F is a Monad (#2299) * added MonadError instance for OptionT where F is a Monad * test added * removed duplicate code using OptionTMonad[F] --- core/src/main/scala/cats/data/OptionT.scala | 15 +++++++++++++++ .../src/test/scala/cats/tests/OptionTSuite.scala | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 74fb633fb5..30976b1a59 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -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 { @@ -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] diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index 32e3458fda..8ba0935b61 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -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))