scalaz/scalaz — pull request #128 by YoEight (2012-08-08 18:51:07+00:00)
Title: MonadWriter typeclass (Previously #94)

Partially a port from Haskell MonadWriter.

It pemits to use Writer Monad Transformer computation without type annotations nightmare

This comes with two implementations: WriterT and ValidationT

There is also a special syntax which currently includes:

:++> like WriterT
:++>> like WriterT
written like WriterT
listen : (MonadWriter F, Monoid W) => F[W, (A, W)]

Here is an (updated) example

```scala
package scalaz

import scalaz.std.string._
import scalaz.syntax.listenableMonadWriter._

object MonadWriterExample extends App {
implicit val monadWriter = EitherT.listenableMonadWriter[Writer, String, String]

case class Person(firstName: String, age: Int)

def notEmpty(s: String) = Option(s).filter(x => !x.isEmpty && !x.forall(_.isWhitespace)) match {
case Some(r) => monadWriter.right[String](r)
case None => monadWriter.left[String]("Empty String")
}

def majority(age: Int) =
if(age >= 18) monadWriter.right[Int](age)
else monadWriter.left[Int]("This person is not an adult")

def validateData(firstName: String, age: Int) = for {
n <- notEmpty(firstName) :++>> (x => "The first name is => " + x + "\n")
a <- majority(age) :++>> (x => "She is an adult => " + x + "\n")
} yield Person(n, a)

def showMe(v: (Person, String)) {
println("Log produced during computation -------")
println(v._2)
println("Computation result --------------------")
println(v._1)
}

println(validateData("", 17).listen.map(showMe).run.run) // showMe will not be called, no log accumulated
println()
println()
println(validateData("Nath", 5).listen.map(showMe).run.run) // showMe will not be called: log value is "Firstname name is => Nath"
println()
println()
validateData("Mimie", 20).listen.map(showMe)
}