Skip to content

Commit

Permalink
Merge pull request #689 from ceedubs/writert-monaderror
Browse files Browse the repository at this point in the history
Add WriterT MonadError instance
  • Loading branch information
kailuowang authored Jul 22, 2016
2 parents ac38602 + 172cf62 commit b9e78f5
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 12 deletions.
32 changes: 30 additions & 2 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,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
Expand All @@ -191,6 +190,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]

Expand Down Expand Up @@ -239,6 +254,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)
Expand Down
68 changes: 58 additions & 10 deletions tests/src/test/scala/cats/tests/WriterTTests.scala
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -114,6 +115,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], ?]]

Expand Down Expand Up @@ -142,12 +146,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]
}

{
Expand All @@ -157,20 +164,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]
}

{
Expand All @@ -180,20 +191,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]
}

{
Expand All @@ -205,25 +220,29 @@ 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]]))

Functor[WriterT[Id, ListWrapper[Int], ?]]
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]
}

Expand All @@ -235,6 +254,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], ?]]))
}
Expand All @@ -248,6 +268,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], ?]]))
Expand All @@ -262,6 +283,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], ?]]
Expand Down Expand Up @@ -294,16 +316,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]))
}
}

0 comments on commit b9e78f5

Please sign in to comment.