From e2e0e6b79814553d40c5216b56ad4665dd20bffa Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Sat, 21 Nov 2015 10:28:19 -0500 Subject: [PATCH 1/2] Add WriterT MonadError instance --- core/src/main/scala/cats/data/WriterT.scala | 31 ++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 1db757f28f..5c79d8e8dd 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -151,12 +151,28 @@ private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 } } -private[data] sealed abstract class WriterTInstances7 { +private[data] sealed abstract class WriterTInstances7 extends WriterTInstances8 { implicit def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = new WriterTFunctor[F, L] { implicit val F0: Functor[F] = F } } +private[data] sealed abstract class WriterTInstances8 extends WriterTInstances9 { + implicit def writerTMonadError[F[_], L, E](implicit F: MonadError[F, E], L: Monoid[L]): MonadError[WriterT[F, L, ?], E] = + new WriterTMonadError[F, L, E] { + implicit val F0: MonadError[F, E] = F + implicit val L0: Monoid[L] = L + } +} + +private[data] sealed abstract class WriterTInstances9 { + implicit def writerTApplicativeError[F[_], L, E](implicit F: ApplicativeError[F, E], L: Monoid[L]): ApplicativeError[WriterT[F, L, ?], E] = + new WriterTApplicativeError[F, L, E] { + implicit val F0: ApplicativeError[F, E] = F + implicit val L0: Monoid[L] = L + } +} + private[data] sealed trait WriterTFunctor[F[_], L] extends Functor[WriterT[F, L, ?]] { implicit def F0: Functor[F] @@ -198,6 +214,19 @@ private[data] sealed trait WriterTMonad[F[_], L] extends WriterTApplicative[F, L fa.flatMap(f) } +private[data] sealed trait WriterTApplicativeError[F[_], L, E] extends ApplicativeError[WriterT[F, L, ?], E] with WriterTApplicative[F, L] { + override implicit def F0: ApplicativeError[F, E] + + def raiseError[A](e: E): WriterT[F, L, A] = WriterT(F0.raiseError[(L, A)](e)) + + def handleErrorWith[A](fa: WriterT[F, L, A])(f: E => WriterT[F, L, A]): WriterT[F, L, A] = + WriterT(F0.handleErrorWith(fa.run)(e => f(e).run)) +} + +private[data] sealed trait WriterTMonadError[F[_], L, E] extends MonadError[WriterT[F, L, ?], E] with WriterTMonad[F, L] with WriterTApplicativeError[F, L, E]{ + override implicit def F0: MonadError[F, E] +} + private[data] sealed trait WriterTMonadWriter[F[_], L] extends MonadWriter[WriterT[F, L, ?], L] with WriterTMonad[F, L] { def writer[A](aw: (L, A)): WriterT[F, L, A] = WriterT.put(aw._2)(aw._1) From 172cf6214d9627febce40ab31c1bd0ba97a863fd Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Fri, 22 Jul 2016 09:39:22 -0400 Subject: [PATCH 2/2] Add WriterT ApplicativeError tests --- .../test/scala/cats/tests/WriterTTests.scala | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index eeb77c5e87..7c92b20d20 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -1,11 +1,12 @@ package cats package tests -import cats.data.{Writer, WriterT, XorT} +import cats.data.{Validated, Writer, WriterT, XorT} import cats.functor.{Bifunctor, Contravariant} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ +import org.scalacheck.Arbitrary import cats.kernel.laws.OrderLaws @@ -295,6 +296,26 @@ class WriterTTests extends CatsSuite { Semigroup[WriterT[Id, Int, Int]] } + { + // F has an ApplicativeError and L has a Monoid + implicit val L: Monoid[ListWrapper[Int]] = ListWrapper.monoid[Int] + implicit val appErr = WriterT.catsDataApplicativeErrorForWriterT[Validated[String, ?], ListWrapper[Int], String] + implicit val iso = CartesianTests.Isomorphisms.invariant[WriterT[Validated[String, ?], ListWrapper[Int], ?]] + implicit def eq1[A:Eq]: Eq[WriterT[Validated[String, ?], ListWrapper[Int], A]] = + WriterT.catsDataEqForWriterT[Validated[String, ?], ListWrapper[Int], A] + implicit val eq2: Eq[XorT[WriterT[Validated[String, ?], ListWrapper[Int], ?], String, Int]] = + XorT.catsDataEqForXorT[WriterT[Validated[String, ?], ListWrapper[Int], ?], String, Int] + implicit def arb0[A:Arbitrary]: Arbitrary[WriterT[Validated[String, ?], ListWrapper[Int], A]] = + arbitrary.catsLawsArbitraryForWriterT[Validated[String, ?], ListWrapper[Int], A] + + Functor[WriterT[Validated[String, ?], ListWrapper[Int], ?]] + Apply[WriterT[Validated[String, ?], ListWrapper[Int], ?]] + Applicative[WriterT[Validated[String, ?], ListWrapper[Int], ?]] + + checkAll("WriterT[Validated[String, ?], ListWrapper[Int], ?]", ApplicativeErrorTests[WriterT[Validated[String, ?], ListWrapper[Int], ?], String].applicativeError[Int, Int, Int]) + checkAll("ApplicativeError[WriterT[Validated[String, ?], ListWrapper[Int], ?], Unit]", SerializableTests.serializable(ApplicativeError[WriterT[Validated[String, ?], ListWrapper[Int], ?], String])) + } + { // F has a MonadError and L has a Monoid implicit val L: Monoid[ListWrapper[Int]] = ListWrapper.monoid[Int]