Skip to content

Commit

Permalink
Merge pull request #1049 from zainab-ali/master
Browse files Browse the repository at this point in the history
Adding CoflatMap and tests to WriterT and fixed laws for CoflatMap
  • Loading branch information
adelbertc committed May 23, 2016
2 parents eb3caf8 + 82443c9 commit 8fefdff
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
26 changes: 17 additions & 9 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,6 @@ 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]

implicit def writerTIdFlatMap[L:Semigroup]: FlatMap[WriterT[Id, L, ?]] =
writerTFlatMap[Id, L]

Expand All @@ -111,7 +108,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] {
Expand All @@ -131,6 +132,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 {
Expand Down Expand Up @@ -160,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
Expand All @@ -168,8 +171,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] {
implicit val F0: Functor[F] = F

implicit def writerTCoflatMap[F[_], L](implicit F: Functor[F]): CoflatMap[WriterT[F, L, ?]] =
new WriterTCoflatMap[F, L] {
implicit val F0: Functor[F] = F
}
}

Expand Down Expand Up @@ -259,12 +264,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)))
Expand All @@ -281,6 +292,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)
}



15 changes: 11 additions & 4 deletions laws/src/main/scala/cats/laws/discipline/CoflatMapTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] _)
)
}
}

Expand Down
16 changes: 15 additions & 1 deletion tests/src/test/scala/cats/tests/WriterTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -268,4 +268,18 @@ class WriterTTests extends CatsSuite {

Semigroup[WriterT[Id, Int, Int]]
}

{
// 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, ?]]
}
}

0 comments on commit 8fefdff

Please sign in to comment.