Writer-Monade — eine Monade, die neben dem eigentlichen Ergebnis einen zusätzlichen Ausgabewert akkumuliert, ohne Seiteneffekte zu erzeugen. Sie eignet sich für Protokollierung, Audit-Trails oder das Sammeln von Warnungen, wenn der Log selbst ein Wert der Berechnung ist.

Die Idee: Ergebnis plus Log

Eine Berechnung in der Writer-Monade liefert ein Paar: den eigentlichen Wert a und ein angesammeltes Protokoll w. Das Protokoll wird mit der Operation mappend eines Monoids kombiniert — einer mathematischen Struktur mit einer assoziativen Verknüpfung und einem neutralen Element (für Listen ist das die Verkettung mit der leeren Liste als neutralem Element). Dadurch bleibt die gesamte Akkumulation rein: nichts wird global verändert, jede Stufe der Kette reicht den bisherigen Log an die nächste weiter.

newtype Writer w a = Writer { runWriter :: (a, w) }

Der Kern ist damit fast derselbe wie bei der State-Monade — nur dass der weitergereichte Wert nicht verändert, sondern nur angehängt wird.

tell und Freunde

Die zentrale Funktion ist tell :: Monoid w => w -> Writer w (): Sie hängt einen Eintrag an das Protokoll an. Der Wert des Ergebnisses ist (), die Bedeutung steckt im Log. Beim Ausführen wählt man, was man braucht:

  • runWriter — liefert Paar (Wert, Log)
  • execWriter — nur der Log (häufigster Fall)
  • evalWriter — nur der Wert
  • listen — Zugriff auf den Zwischenstand des Logs innerhalb der Berechnung
  • pass — den Log einer Teilberechnung nachträglich verändern

Als Monoid eignen sich Listen (eine Liste von Log-Zeilen), Strings, Mengen oder selbstgebaute Summenwerte — etwa Zähler, die durch die Verknüpfung addiert werden. Damit lassen sich ohne eine einzige mutable Variable Kennzahlen wie „wie viele Validierungen liefen fehlerhaft“ sammeln.

Wo die Writer-Monade passt — und wo nicht

Stärken: Sie macht Logs typsicher und referenziell transparent, ist leicht testbar und trägt keine globale Logging-Instanz. Sie ist die pure Alternative, wenn man in einer reinen Funktion nebenbei protokollieren will.

Grenzen: Bei sehr großen Protokollen hält die Writer-Monade die gesamte Ausgabe im Speicher (sie kann den Log nicht vorzeitig leeren) und die Listen-Verkettung kann schlecht assoziieren. Für echte Laufzeit-Logs in Produktivsystemen nutzt man deshalb einen dedizierten Logger; die Writer-Monade ist das Werkzeug für kompakte, rein funktionale Ausgaben — etwa als WriterT-Schicht im Transformer-Stack, siehe Monadentransformer.

Verwandte Grundlagen: Monade, Funktionale Programmierung, Funktionskomposition, IO-Monade, Haskell-Befehle.