Skip to content
Dinko Srkoč edited this page Aug 7, 2011 · 2 revisions

Sometimes it is desirable for a computation to generate output in addition to the computed values. The most common examples would be logging and tracing where we want to retain the data generated during computation, even though that is not the primary result of the computation.

Explicitly managing the logging data may clutter up the code. The Writer monad provides a cleaner way to manage the output. It may be seen as a write-only part of the State monad (where read-only part would be the role of the Reader monad).

A simple logging example is in order:

import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.Writer.write

def logNumber = { x -> write x, ["Got number: $x"]}

def res = foreach {
    a = takeFrom { logNumber 5 }
    b = takeFrom { logNumber 6 }
    yield { a * b }
}

assert res.value == 30
assert res.aggregate == ["Got number: 5", "Got number: 6"]

So, the writer works with a tuple (value, log) where log is a List. But writer is not limited to use just lists.

A simple logging example, take 2:

import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.Writer.write

def res = foreach {
    a = takeFrom { write 5, "Started with 5." }
    b = takeFrom { write a * 2, " Multiplied by 2." }
    yield { a + b }
}

assert res.value == 15
assert res.aggregate == "Started with 5. Multiplied by 2."

Writer can work with Strings too. In fact, writer can work with everything that is a monoid. This means that everything that has an identity element and a single associative binary operation can be used by our worker.

For Strings, identity is an empty string (""), the operation is concatenation (+). Lists have empty list ([]) and append (+ again).

Monadologie converts some types, such as collections, maps, and strings into monoids automatically. More information about monoids in Monadologie can be found here.

Now, how can we add a bunch of numbers? Why, by using the writer monad, thank you very much.
Example, the third:

import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.Writer.write

def res = foreach {
    a = takeFrom { write 5, 0 }
    b = takeFrom { write 2, a }
    c = takeFrom { write 7, b }
    d = takeFrom { write 0, c }
    yield { 0 }
}

assert res.aggregate == 5 + 2 + 7

Wait, what did I just do here? It must be those damn monoids again!

Clone this wiki locally