1

I wish to fold a list of Writer Monad from cats to one big writer without running them. for example:

import cats.data.Writer
import cats.instances.vector._
import cats.instances.list._
import cats.instances.tuple._
import cats.Foldable

val result = for {
  i <- Writer(Vector("hello"), Vector(1))
  j <- Writer(Vector("bye"), Vector(2))
} yield j

val result2 = for {
  x <- Writer(Vector("hi"), Vector(33))
  y <- Writer(Vector("ciao"), Vector(55))
} yield y

val l = List(result, result2)

val result3 = for {
  t <- result
  z <- result2
} yield z // Success !!!

val l = List(result, result2)

// Logically:
// val result3 = for {
//   r <- l
//   o <- r
// } yield o
// But will not compile without Monad Transformer


// With run
val l1: List[(Vector[String], Vector[Int])] = l.map(_.run)

val result5 = Foldable[List].combineAll(l1)

I believe there must be a functional construct for such combination without running the Writers

4

2 回答 2

1

您可以直接跳到result5使用Vector,因此您拥有相同的容器类型,然后使用l.sequence.map(_.flatten) Check out the Traverse typeclass,因为俗话说“它总是遍历”。

import cats.data.{Writer, WriterT}
import cats.instances.vector._
import cats.instances.list._
import cats.instances.tuple._
import cats.{Foldable, Id}
import cats.implicits._

val result = for {
  i <- Writer(Vector("hello"), Vector(1))
  j <- Writer(Vector("bye"), Vector(2))
} yield j

val result2 = for {
  x <- Writer(Vector("hi"), Vector(33))
  y <- Writer(Vector("ciao"), Vector(55))
} yield y

val l = Vector(result, result2)

val result3 = for {
  t <- result
  z <- result2
} yield z // Success !!!

// val l = List(result, result2) -- this is a duplicate

val result5: WriterT[Id, Vector[String], Vector[Int]] = l.sequence.map(_.flatten)

result5将具有值:

WriterT((Vector(hello, bye, hi, ciao),Vector(2, 55)))
于 2020-09-23T01:17:41.177 回答
1

感谢@NigelBeans 的回答。我将在这里发布工作解决方案,因为我使用答案中的确切导入存在一些隐含冲突:

import cats.data.Writer
import cats.instances.vector._
import cats.instances.list._
import cats.instances.tuple._
import cats.Foldable
import cats.syntax.traverse._

val result1 = for {
  i <- Writer(Vector("hello"), Vector(1))
  j <- Writer(Vector("bye"), Vector(2))
} yield j

val result2 = for {
  x <- Writer(Vector("hi"), Vector(33))
  y <- Writer(Vector("ciao"), Vector(55))
} yield y

val l = Vector(result1, result2)

val result3 = l.flatSequence

println(result3.run) // (Vector(hello, bye, hi, ciao),Vector(2, 55))
于 2020-09-23T06:45:51.750 回答