diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index e1edf6e620..635f83a52f 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -175,8 +175,7 @@ private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 } } -private[data] sealed abstract class WriterTInstances7 { - +private[data] sealed abstract class WriterTInstances7 extends WriterTInstances8 { implicit def catsDataCoflatMapForWriterT[F[_], L](implicit F: Functor[F]): CoflatMap[WriterT[F, L, ?]] = new WriterTCoflatMap[F, L] { implicit val F0: Functor[F] = F @@ -187,6 +186,22 @@ private[data] sealed abstract class WriterTInstances7 { } } +private[data] sealed abstract class WriterTInstances8 extends WriterTInstances9 { + implicit def catsDataMonadErrorForWriterT[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 catsDataApplicativeErrorForWriterT[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] @@ -235,6 +250,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) diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index b3f7630403..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} +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 @@ -95,6 +96,9 @@ class WriterTTests extends CatsSuite { checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", FunctorTests[WriterT[ListWrapper, ListWrapper[Int], ?]].functor[Int, Int, Int]) checkAll("Functor[WriterT[ListWrapper, ListWrapper[Int], ?]]", SerializableTests.serializable(Functor[WriterT[ListWrapper, ListWrapper[Int], ?]])) + checkAll("WriterT[Listwrapper, Int, ?]", CoflatMapTests[WriterT[ListWrapper, Int, ?]].coflatMap[Int, Int, Int]) + checkAll("WriterT[ListWrapper, Int, ?]", SerializableTests.serializable(CoflatMap[WriterT[ListWrapper, Int, ?]])) + // just making sure this resolves; it's tested above Functor[WriterT[Id, ListWrapper[Int], ?]] @@ -123,12 +127,15 @@ class WriterTTests extends CatsSuite { Functor[WriterT[Id, ListWrapper[Int], ?]] Apply[WriterT[Id, ListWrapper[Int], ?]] + CoflatMap[WriterT[Id, ListWrapper[Int], ?]] Functor[Writer[ListWrapper[Int], ?]] Apply[Writer[ListWrapper[Int], ?]] + CoflatMap[Writer[ListWrapper[Int], ?]] Functor[Logged] Apply[Logged] + CoflatMap[Logged] } { @@ -138,20 +145,24 @@ class WriterTTests extends CatsSuite { Functor[WriterT[ListWrapper, ListWrapper[Int], ?]] Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", FlatMapTests[WriterT[ListWrapper, ListWrapper[Int], ?]].flatMap[Int, Int, Int]) checkAll("FlatMap[WriterT[ListWrapper, ListWrapper[Int], ?]]", SerializableTests.serializable(FlatMap[WriterT[ListWrapper, ListWrapper[Int], ?]])) Functor[WriterT[Id, ListWrapper[Int], ?]] Apply[WriterT[Id, ListWrapper[Int], ?]] FlatMap[WriterT[Id, ListWrapper[Int], ?]] + CoflatMap[WriterT[Id, ListWrapper[Int], ?]] Functor[Writer[ListWrapper[Int], ?]] Apply[Writer[ListWrapper[Int], ?]] FlatMap[Writer[ListWrapper[Int], ?]] + CoflatMap[Writer[ListWrapper[Int], ?]] Functor[Logged] Apply[Logged] FlatMap[Logged] + CoflatMap[Logged] } { @@ -161,20 +172,24 @@ class WriterTTests extends CatsSuite { Functor[WriterT[ListWrapper, ListWrapper[Int], ?]] Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", ApplicativeTests[WriterT[ListWrapper, ListWrapper[Int], ?]].applicative[Int, Int, Int]) checkAll("Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]]", SerializableTests.serializable(Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]])) Functor[WriterT[Id, ListWrapper[Int], ?]] Apply[WriterT[Id, ListWrapper[Int], ?]] Applicative[WriterT[Id, ListWrapper[Int], ?]] + CoflatMap[WriterT[Id, ListWrapper[Int], ?]] Functor[Writer[ListWrapper[Int], ?]] Apply[Writer[ListWrapper[Int], ?]] Applicative[Writer[ListWrapper[Int], ?]] + CoflatMap[Writer[ListWrapper[Int], ?]] Functor[Logged] Apply[Logged] Applicative[Logged] + CoflatMap[Logged] } { @@ -186,6 +201,7 @@ class WriterTTests extends CatsSuite { Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]] FlatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", MonadWriterTests[WriterT[ListWrapper, ListWrapper[Int], ?], ListWrapper[Int]].monadWriter[Int, Int, Int]) checkAll("MonadWriter[WriterT[ListWrapper, ListWrapper[Int], ?], List[String]]", SerializableTests.serializable(MonadWriter[WriterT[ListWrapper, ListWrapper[Int], ?], ListWrapper[Int]])) @@ -193,18 +209,21 @@ class WriterTTests extends CatsSuite { Apply[WriterT[Id, ListWrapper[Int], ?]] Applicative[WriterT[Id, ListWrapper[Int], ?]] FlatMap[WriterT[Id, ListWrapper[Int], ?]] + CoflatMap[WriterT[Id, ListWrapper[Int], ?]] Monad[WriterT[Id, ListWrapper[Int], ?]] Functor[Writer[ListWrapper[Int], ?]] Apply[Writer[ListWrapper[Int], ?]] Applicative[Writer[ListWrapper[Int], ?]] FlatMap[Writer[ListWrapper[Int], ?]] + CoflatMap[Writer[ListWrapper[Int], ?]] Monad[Writer[ListWrapper[Int], ?]] Functor[Logged] Apply[Logged] Applicative[Logged] FlatMap[Logged] + CoflatMap[Logged] Monad[Logged] } @@ -216,6 +235,7 @@ class WriterTTests extends CatsSuite { Functor[WriterT[ListWrapper, ListWrapper[Int], ?]] Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", AlternativeTests[WriterT[ListWrapper, ListWrapper[Int], ?]].alternative[Int, Int, Int]) checkAll("Alternative[WriterT[ListWrapper, ListWrapper[Int], ?]]", SerializableTests.serializable(Alternative[WriterT[ListWrapper, ListWrapper[Int], ?]])) } @@ -229,6 +249,7 @@ class WriterTTests extends CatsSuite { Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]] FlatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] Monad[WriterT[ListWrapper, ListWrapper[Int], ?]] checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", MonadFilterTests[WriterT[ListWrapper, ListWrapper[Int], ?]].monadFilter[Int, Int, Int]) checkAll("MonadFilter[WriterT[ListWrapper, ListWrapper[Int], ?]]", SerializableTests.serializable(MonadFilter[WriterT[ListWrapper, ListWrapper[Int], ?]])) @@ -243,6 +264,7 @@ class WriterTTests extends CatsSuite { Apply[WriterT[ListWrapper, ListWrapper[Int], ?]] Applicative[WriterT[ListWrapper, ListWrapper[Int], ?]] FlatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] + CoflatMap[WriterT[ListWrapper, ListWrapper[Int], ?]] Monad[WriterT[ListWrapper, ListWrapper[Int], ?]] MonadFilter[WriterT[ListWrapper, ListWrapper[Int], ?]] Alternative[WriterT[ListWrapper, ListWrapper[Int], ?]] @@ -275,16 +297,42 @@ class WriterTTests extends CatsSuite { } { - // F has a Functor - implicit val F: Functor[ListWrapper] = ListWrapper.functor + // 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])) + } - Functor[WriterT[ListWrapper, Int, ?]] - CoflatMap[WriterT[ListWrapper, Int, ?]] - checkAll("WriterT[Listwrapper, Int, ?]", CoflatMapTests[WriterT[ListWrapper, Int, ?]].coflatMap[Int, Int, Int]) - checkAll("WriterT[ListWrapper, Int, ?]", SerializableTests.serializable(CoflatMap[WriterT[ListWrapper, Int, ?]])) + { + // F has a MonadError and L has a Monoid + implicit val L: Monoid[ListWrapper[Int]] = ListWrapper.monoid[Int] + implicit val iso = CartesianTests.Isomorphisms.invariant[WriterT[Option, ListWrapper[Int], ?]] + implicit val eq0: Eq[XorT[WriterT[Option, ListWrapper[Int], ?], Unit, Int]] = XorT.catsDataEqForXorT[WriterT[Option, ListWrapper[Int], ?], Unit, Int] + + + Functor[WriterT[Option, ListWrapper[Int], ?]] + Apply[WriterT[Option, ListWrapper[Int], ?]] + Applicative[WriterT[Option, ListWrapper[Int], ?]] + FlatMap[WriterT[Option, ListWrapper[Int], ?]] + CoflatMap[WriterT[Option, ListWrapper[Int], ?]] + Monad[WriterT[Option, ListWrapper[Int], ?]] + MonadWriter[WriterT[Option, ListWrapper[Int], ?], ListWrapper[Int]] + ApplicativeError[WriterT[Option, ListWrapper[Int], ?], Unit] - // Id has a Functor - Functor[WriterT[Id, Int, ?]] - CoflatMap[WriterT[Id, Int, ?]] + checkAll("WriterT[Option, ListWrapper[Int], ?]", MonadErrorTests[WriterT[Option, ListWrapper[Int], ?], Unit].monadError[Int, Int, Int]) + checkAll("MonadError[WriterT[Option, ListWrapper[Int], ?], Unit]", SerializableTests.serializable(MonadError[WriterT[Option, ListWrapper[Int], ?], Unit])) } }