Skip to content

Commit

Permalink
Add listen for Writer and WriterT (#2916)
Browse files Browse the repository at this point in the history
  • Loading branch information
jooohn authored and kailuowang committed Jun 27, 2019
1 parent 48a16cc commit 4df64bd
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
13 changes: 12 additions & 1 deletion core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {
def value(implicit functorF: Functor[F]): F[V] =
functorF.map(run)(_._2)

def listen(implicit F: Functor[F]): WriterT[F, L, (V, L)] =
WriterT(F.map(run) {
case (l, v) => (l, (v, l))
})

def ap[Z](f: WriterT[F, L, V => Z])(implicit F: Apply[F], L: Semigroup[L]): WriterT[F, L, Z] =
WriterT(F.map2(f.run, run) {
case ((l1, fvz), (l2, v)) => (L.combine(l1, l2), fvz(v))
Expand Down Expand Up @@ -84,7 +89,7 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {
)(WriterT.apply)
}

object WriterT extends WriterTInstances with WriterTFunctions {
object WriterT extends WriterTInstances with WriterTFunctions with WriterTFunctions0 {

def liftF[F[_], L, V](fv: F[V])(implicit monoidL: Monoid[L], F: Applicative[F]): WriterT[F, L, V] =
WriterT(F.map(fv)(v => (monoidL.empty, v)))
Expand Down Expand Up @@ -527,6 +532,12 @@ sealed private[data] trait WriterTComonad[F[_], L] extends Comonad[WriterT[F, L,
def extract[A](fa: WriterT[F, L, A]): A = F0.extract(F0.map(fa.run)(_._2))
}

// new trait for binary compatibility
private[data] trait WriterTFunctions0 {
def listen[F[_], L, V](writerTFLV: WriterT[F, L, V])(implicit functorF: Functor[F]): WriterT[F, L, (V, L)] =
writerTFLV.listen
}

private[data] 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 Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/data/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ package object data {
def value[L: Monoid, V](v: V): Writer[L, V] = WriterT.value(v)

def tell[L](l: L): Writer[L, Unit] = WriterT.tell(l)

def listen[L, V](writer: Writer[L, V]): Writer[L, (V, L)] =
WriterT.listen(writer)
}

type IndexedState[S1, S2, A] = IndexedStateT[Eval, S1, S2, A]
Expand Down
17 changes: 17 additions & 0 deletions tests/src/test/scala/cats/tests/WriterTSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ class WriterTSuite extends CatsSuite {
}
}

test("value + listen + map(_._1) + value is identity") {
forAll { (i: Int) =>
WriterT.value[Id, Int, Int](i).listen.map(_._1).value should ===(i)
}
}

test("tell + listen + map(_._2) + value is identity") {
forAll { (i: Int) =>
WriterT.tell[Id, Int](i).listen.map(_._2).value should ===(i)
}
}

test("Writer.pure and WriterT.liftF are consistent") {
forAll { (i: Int) =>
val writer: Writer[String, Int] = Writer.value(i)
Expand All @@ -91,6 +103,11 @@ class WriterTSuite extends CatsSuite {
Writer.tell("foo").written should ===("foo")
}

test("listen returns a tuple of value and log") {
val w: Writer[String, Int] = Writer("foo", 3)
w.listen should ===(Writer("foo", (3, "foo")))
}

test("mapK consistent with f(value)+pure") {
val f: List ~> Option = λ[List ~> Option](_.headOption)
forAll { (writert: WriterT[List, String, Int]) =>
Expand Down

0 comments on commit 4df64bd

Please sign in to comment.