El log en un Writer se conserva cuando hacemos map or flatMap sobre él. flatMap agrega los logs del Writer de origen y el resultado de la función de secuenciación del usuario. Por esta razón, es una buena práctica utilizar un tipo de registro que tenga operaciones de adición y concatenación eficientes, como un Vector:
val writer1 = for {
a <- 10.pure[Logged]
_ <- Vector("a", "b", "c").tell
b <- 32.writer(Vector("x", "y", "z"))
} yield a + b
// writer1: cats.data.WriterT[cats.package.Id, Vector[String], Int] =WriterT(
//(Vector("a", "b", "c", "x", "y", "z"), 42)
// )
writer1.run
// res3: (Vector[String], Int) = (Vector("a", "b", "c", "x", "y", "z") , 42)
Además de transformar el resultado con map y flatMap, podemos transformar el log en un Writer con el método mapWritten:
val writer2 = writer1.mapWritten(_.map(_.toUpperCase))
// writer2: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(
// (Vector("A", "B", "C", "X", "Y", "Z"), 42)
// )
writer2.run
// res4: (Vector[String], Int) = (Vector("A", "B", "C", "X", "Y", "Z") , 42)
Podemos transformar tanto el log como el resultado simultáneamente usando bimap o mapBoth. bimap toma dos parámetros de función, uno para el registro y otro para el resultado. mapBoth toma una sola función que acepta dos parámetros:
val writer3 = writer1.bimap(
log => log.map(_.toUpperCase),
res => res * 100
)
// writer3: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(
//(Vector("A", "B", "C", "X", "Y", "Z"), 4200)
// )
writer3.run
// res5: (Vector[String], Int) = (Vector("A", "B", "C", "X", "Y", "Z"), 4200)
val writer4 = writer1.mapBoth { (log, res) =>
val log2 = log.map(_ + "!")
val res2 = res * 1000
(log2, res2)
}
// writer4: cats.data.WriterT[cats.package.Id, Vector[String], Int] =WriterT(
//(Vector("a!", "b!", "c!", "x!", "y!", "z!"), 42000)
// )
writer4.run
// res6: (Vector[String], Int) = (
//Vector("a!", "b!", "c!", "x!", "y!", "z!"),
//42000
// )
Finalmente, podemos borrar el registro con el método de reinicio e intercambiar el registro y el resultado con el método de intercambio:
val writer5 = writer1.reset
// writer5: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(
//(Vector(), 42)
// )
writer5.run
// res7: (Vector[String], Int) = (Vector(), 42)
val writer6 = writer1.swap
// writer6: cats.data.WriterT[cats.package.Id, Int, Vector[String]] = WriterT(
//(42, Vector("a", "b", "c", "x", "y", "z"))
// )
writer6.run
// res8: (Int, Vector[String]) = (42, Vector("a", "b", "c", "x", "y","z"))