Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -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
Expand All @@ -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]

Expand Down Expand Up @@ -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))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if you should append the L from fa.run and the L that results from f(e).run ?
In other words, if the Log that came from fa will be lost (maybe it's ok for it to be forgotten)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lukiano sorry I'm just seeing this. I don't think we can do what you have recommended. Let's consider Future as F (and thus Throwable as E). If the Future fails, then there is no log. We do have a log if the future succeeds, but in that case the function that we pass to handleErrorWith will never be called, because there is no error to handle.

Does that sound right?

@lukiano lukiano May 13, 2016 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are right. I was thinking of something like XorT -> WriterT -> Future, but in this case F is just Future so there's no monadError instance for it. XorT will provide the MonadError and will already do the right thing.

}

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 @@ -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], ?]]

Expand Down Expand Up @@ -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]
}

{
Expand All @@ -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]
}

{
Expand All @@ -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]
}

{
Expand All @@ -186,25 +201,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 @@ -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], ?]]))
}
Expand All @@ -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], ?]]))
Expand All @@ -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], ?]]
Expand Down Expand Up @@ -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]))
}
}