From 3efe27fe252b420f2ff25c5780f9fccd9cdf6a92 Mon Sep 17 00:00:00 2001 From: Zainab Ali Date: Fri, 20 May 2016 20:12:11 +0100 Subject: [PATCH 1/4] Adding CoflatMap and tests to WriterT --- core/src/main/scala/cats/data/WriterT.scala | 24 +++++++++++++------ .../cats/laws/discipline/CoflatMapTests.scala | 15 ++++++++---- .../test/scala/cats/tests/WriterTTests.scala | 11 +++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 2ee07cc5cd..1f7db51055 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -87,8 +87,7 @@ private[data] sealed abstract class WriterTInstances0 extends WriterTInstances1 implicit val L0: Monoid[L] = L } - implicit def writerTIdFunctor[L]: Functor[WriterT[Id, L, ?]] = - writerTFunctor[Id, L] + def writerTIdFunctor[L]: Functor[WriterT[Id, L, ?]] = writerTIdCoflatMap implicit def writerTIdFlatMap[L:Semigroup]: FlatMap[WriterT[Id, L, ?]] = writerTFlatMap[Id, L] @@ -111,7 +110,11 @@ private[data] sealed abstract class WriterTInstances1 extends WriterTInstances2 new WriterTMonoid[F, L, V] { implicit val F0: Monoid[F[(L, V)]] = W } + + implicit def writerTIdCoflatMap[L]: CoflatMap[WriterT[Id, L, ?]] = + writerTCoflatMap[Id, L] } + private[data] sealed abstract class WriterTInstances2 extends WriterTInstances3 { implicit def writerTMonadWriter[F[_], L](implicit F: Monad[F], L: Monoid[L]): MonadWriter[WriterT[F, L, ?], L] = new WriterTMonadWriter[F, L] { @@ -131,6 +134,7 @@ private[data] sealed abstract class WriterTInstances3 extends WriterTInstances4 implicit val F0: Alternative[F] = F implicit val L0: Monoid[L] = L } + } private[data] sealed abstract class WriterTInstances4 extends WriterTInstances5 { @@ -168,7 +172,10 @@ private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 } private[data] sealed abstract class WriterTInstances7 { - implicit def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = new WriterTFunctor[F, L] { + + def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = writerTCoflatMap + + implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): WriterTCoflatMap[F, L] = new WriterTCoflatMap[F, L] { implicit val F0: Functor[F] = F } } @@ -259,12 +266,18 @@ private[data] sealed trait WriterTSemigroup[F[_], L, A] extends Semigroup[Writer WriterT(F0.combine(x.run, y.run)) } -private[data] sealed trait WriterTMonoid[F[_], L, A] extends Monoid[WriterT[F, L, A]] with WriterTSemigroup[F, L, A]{ +private[data] sealed trait WriterTMonoid[F[_], L, A] extends Monoid[WriterT[F, L, A]] with WriterTSemigroup[F, L, A] { override implicit def F0: Monoid[F[(L, A)]] def empty: WriterT[F, L, A] = WriterT(F0.empty) } +private[data] sealed trait WriterTCoflatMap[F[_], L] extends CoflatMap[WriterT[F, L, ?]] with WriterTFunctor[F, L] { + + def coflatMap[A, B](fa: WriterT[F, L, A])(f: WriterT[F, L, A] => B): WriterT[F, L, B] = fa.map(_ => f(fa)) +} + + trait WriterTFunctions { def putT[F[_], L, V](vf: F[V])(l: L)(implicit functorF: Functor[F]): WriterT[F, L, V] = WriterT(functorF.map(vf)(v => (l, v))) @@ -281,6 +294,3 @@ trait WriterTFunctions { def valueT[F[_], L, V](vf: F[V])(implicit functorF: Functor[F], monoidL: Monoid[L]): WriterT[F, L, V] = WriterT.putT[F, L, V](vf)(monoidL.empty) } - - - diff --git a/laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala b/laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala index 0abeff6ad9..887a2cb9d1 100644 --- a/laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala @@ -7,18 +7,25 @@ import org.scalacheck.Prop import Prop._ import org.typelevel.discipline.Laws -trait CoflatMapTests[F[_]] extends Laws { +trait CoflatMapTests[F[_]] extends Laws with FunctorTests[F] { def laws: CoflatMapLaws[F] def coflatMap[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit ArbFA: Arbitrary[F[A]], EqFA: Eq[F[A]], - EqFC: Eq[F[C]] + EqFC: Eq[F[C]], + EqFFA: Eq[F[F[A]]], + EqFB: Eq[F[B]], + EqFFFA: Eq[F[F[F[A]]]] ): RuleSet = { new DefaultRuleSet( name = "coflatMap", - parent = None, - "coflatMap associativity" -> forAll(laws.coflatMapAssociativity[A, B, C] _)) + parent = Some(functor[A, B, C]), + "coflatMap associativity" -> forAll(laws.coflatMapAssociativity[A, B, C] _), + "coflatMap identity" -> forAll(laws.coflatMapIdentity[A, B] _), + "coflatten coherence" -> forAll(laws.coflattenCoherence[A, B] _), + "coflatten throughMap" -> forAll(laws.coflattenThroughMap[A] _) + ) } } diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index f6223e879f..d1bb73caa1 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -268,4 +268,15 @@ class WriterTTests extends CatsSuite { Semigroup[WriterT[Id, Int, Int]] } + + { + // F has a functor + implicit val F: Functor[ListWrapper] = ListWrapper.functor + + CoflatMap[WriterT[ListWrapper, Int, ?]] + checkAll("WriterT[Listwrapper, Int, ?]", CoflatMapTests[WriterT[ListWrapper, Int, ?]].coflatMap[Int, Int, Int]) + + // Id has a Functor + CoflatMap[WriterT[Id, Int, ?]] + } } From 6ab573c528843379b6f4a0c5b29a26b6e14c978d Mon Sep 17 00:00:00 2001 From: Zainab Ali Date: Fri, 20 May 2016 21:35:32 +0100 Subject: [PATCH 2/4] Added Serializable test to WriterT CoflatMap --- tests/src/test/scala/cats/tests/WriterTTests.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index d1bb73caa1..8ca9f789aa 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -270,11 +270,12 @@ class WriterTTests extends CatsSuite { } { - // F has a functor + // F has a Functor implicit val F: Functor[ListWrapper] = ListWrapper.functor 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, ?]])) // Id has a Functor CoflatMap[WriterT[Id, Int, ?]] From 128c49478fd1e486d7b5ab6941e0ba238318bfb8 Mon Sep 17 00:00:00 2001 From: Zainab Ali Date: Sat, 21 May 2016 00:11:01 +0100 Subject: [PATCH 3/4] Removing WriterT Functor instance in place of CoflatMap instance --- core/src/main/scala/cats/data/WriterT.scala | 10 ++++------ tests/src/test/scala/cats/tests/WriterTTests.scala | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 1f7db51055..81ee317e22 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -87,8 +87,6 @@ private[data] sealed abstract class WriterTInstances0 extends WriterTInstances1 implicit val L0: Monoid[L] = L } - def writerTIdFunctor[L]: Functor[WriterT[Id, L, ?]] = writerTIdCoflatMap - implicit def writerTIdFlatMap[L:Semigroup]: FlatMap[WriterT[Id, L, ?]] = writerTFlatMap[Id, L] @@ -111,7 +109,7 @@ private[data] sealed abstract class WriterTInstances1 extends WriterTInstances2 implicit val F0: Monoid[F[(L, V)]] = W } - implicit def writerTIdCoflatMap[L]: CoflatMap[WriterT[Id, L, ?]] = + implicit def writerTIdCoflatMap[L]: CoflatMap[WriterT[Id, L, ?]] = writerTCoflatMap[Id, L] } @@ -164,6 +162,7 @@ private[data] sealed abstract class WriterTInstances5 extends WriterTInstances6 } private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 { + implicit def writerTApply[F[_], L](implicit F: Apply[F], L: Semigroup[L]): Apply[WriterT[F, L, ?]] = new WriterTApply[F, L] { implicit val F0: Apply[F] = F @@ -173,9 +172,8 @@ private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 private[data] sealed abstract class WriterTInstances7 { - def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = writerTCoflatMap - - implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): WriterTCoflatMap[F, L] = new WriterTCoflatMap[F, L] { + implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): WriterTCoflatMap[F, L] = + new WriterTCoflatMap[F, L] { implicit val F0: Functor[F] = F } } diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index 8ca9f789aa..58dc04505d 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -101,7 +101,7 @@ class WriterTTests extends CatsSuite { checkAll("Bifunctor[WriterT[ListWrapper, ?, ?]]", SerializableTests.serializable(Bifunctor[WriterT[ListWrapper, ?, ?]])) } - implicit val iso = CartesianTests.Isomorphisms.invariant[WriterT[ListWrapper, ListWrapper[Int], ?]](WriterT.writerTFunctor(ListWrapper.functor)) + implicit val iso = CartesianTests.Isomorphisms.invariant[WriterT[ListWrapper, ListWrapper[Int], ?]](WriterT.writerTCoflatMap(ListWrapper.functor)) // We have varying instances available depending on `F` and `L`. // We also battle some inference issues with `Id`. From 82443c9f68f54c53a9836c89d3cb16e99d208946 Mon Sep 17 00:00:00 2001 From: Zainab Ali Date: Sat, 21 May 2016 15:53:52 +0100 Subject: [PATCH 4/4] Adding check for Functor in WriterT CoflatMap tests --- core/src/main/scala/cats/data/WriterT.scala | 4 ++-- tests/src/test/scala/cats/tests/WriterTTests.scala | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 81ee317e22..2c89f43dba 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -172,9 +172,9 @@ private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 private[data] sealed abstract class WriterTInstances7 { - implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): WriterTCoflatMap[F, L] = + implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): CoflatMap[WriterT[F, L, ?]] = new WriterTCoflatMap[F, L] { - implicit val F0: Functor[F] = F + implicit val F0: Functor[F] = F } } diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index 58dc04505d..55bff93d00 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -273,11 +273,13 @@ class WriterTTests extends CatsSuite { // F has a Functor implicit val F: Functor[ListWrapper] = ListWrapper.functor + 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, ?]])) // Id has a Functor + Functor[WriterT[Id, Int, ?]] CoflatMap[WriterT[Id, Int, ?]] } }