coldwa.st
Alle LeitfädenProgrammierungWebDatenWerkzeugeDatenbankenHaskellKonzepteCabal & BuildsToolchainCompilerPerformanceEditor & HLS

Haskell · Konzepte · Monaden

Monaden in Haskell, ohne Fachjargon erklärt

Von ColdwastAktualisiert am 14. Juni 20268 Min. Lesezeit#haskell#monads#concepts
Quellcode auf einem dunklen Bildschirm
Quellcode auf einem dunklen Bildschirm — Monaden sind ein Muster, das man direkt in Code wie diesem schreibt.

„Monade“ hat einen furchteinflößenden Ruf, den sie nicht verdient. Vom Fachjargon befreit, ist eine Monade in Haskell schlicht ein Typ, mit dem Sie Berechnungen sequenzieren können, die einen bestimmten Kontext mitführen — ein möglicher Fehlschlag, ein Seiteneffekt, mehrere Ergebnisse — ohne die Verdrahtung jedes Mal von Hand zu schreiben. Dieser Leitfaden erklärt, was eine Monade wirklich ist, die beiden Operationen, die sie definieren, die do-Notation und die alltäglichen Monaden, die Sie bereits verwenden.

Die Idee in einem Satz

Eine Monade ist ein Typ, der eine Möglichkeit besitzt, Schritte zu verketten, bei der jeder Schritt vom Ergebnis des vorherigen abhängt und bei der der „Kontext“ (Fehlschlag, Effekte, Nichtdeterminismus) automatisch weitergereicht wird. Das ist alles. Die berühmten Typen Maybe, Either, IO und Liste sind alle Monaden, weil jeder diese Verkettung für seine eigene Art von Kontext definiert.

Die beiden Operationen

Die Typklasse Monad wird durch zwei Funktionen definiert:

return :: a -> m a          -- wrap a plain value into the monad
(>>=)  :: m a -> (a -> m b) -> m b   -- "bind": feed the result into the next step

>>= (ausgesprochen „bind“) ist ihr Kern: Es nimmt einen Wert im Kontext und eine Funktion, die den nächsten Wert im Kontext erzeugt, und fügt sie zusammen — wobei es den Kontext für Sie verwaltet.

do-Notation: dasselbe, lesbar

Quellcode auf einem Computerbildschirm
Quellcode auf dem Bildschirm — die do-Notation ist syntaktischer Zucker über dem bind-Operator.

do-Blöcke sind nur Zucker über >>=. Diese sind gleichwertig:

-- with bind
getLine >>= \name -> putStrLn ("Hi " ++ name)

-- with do-notation
do name <- getLine
   putStrLn ("Hi " ++ name)

Die do-Notation lässt Sie kontexttragenden, sequenzierten Code schreiben, der sich wie imperative Schritte liest und dabei rein funktional bleibt.

Die Monaden, die Sie bereits verwenden

  • Maybe — der Kontext ist „kann fehlen“. Bind bricht bei Nothing kurz ab, sodass Sie Nachschlagevorgänge verketten, ohne verschachtelte Null-Prüfungen.
  • Either — der Kontext ist „kann mit einem Fehler scheitern“. Wie Maybe, trägt aber den Grund des Fehlschlags.
  • IO — der Kontext ist „führt Seiteneffekte aus“. Die IO-Monade ist die Art, wie Haskell Effekte sequenziert und dabei rein bleibt; main :: IO () ist der Einstiegspunkt.
  • Liste ([]) — der Kontext ist „mehrere Ergebnisse“. Bind durchläuft jede Kombination (Nichtdeterminismus).

Sie verwenden Monaden seit Ihrem allerersten main — IO ist eine davon.

Warum Monaden zählen

Sie lassen Sie die Verdrahtung der Fehlerbehandlung, der Effekte und der Sequenzierung zu einem wiederverwendbaren Muster abstrahieren, sodass derselbe Code im do-Stil über sehr verschiedene Kontexte hinweg funktioniert. Deshalb kann Haskell IO getrennt und explizit halten und dabei ergonomisch bleiben. Um das alles auszuführen, brauchen Sie die Toolchain — siehe Haskell mit GHCup installieren und den Leitfaden zum GHC-Compiler, und probieren Sie die Beispiele live in GHCi aus.

FAQ

Was ist eine Monade in einfachen Worten? Ein Typ, der Sie Berechnungen verketten lässt, die einen Kontext (Fehlschlag, Effekte, mehrere Ergebnisse) mitführen, und diesen Kontext automatisch über den bind-Operator weiterreicht.

Ist IO eine Monade? Ja — IO ist die Monade, die Haskell verwendet, um Seiteneffekte zu sequenzieren und dabei rein zu bleiben. Ihr main läuft darin.

Muss man Kategorientheorie verstehen? Nein. Sie können Monaden in Haskell produktiv verwenden, wenn Sie nur return, >>= und die do-Notation kennen; die Theorie ist optional.

Was ist der Unterschied zwischen Maybe und Either? Beide modellieren einen möglichen Fehlschlag; Maybe sagt nur „fehlt“ (Nothing), während Either einen Fehlerwert trägt, der den Fehlschlag erklärt.

Unabhängiger, von der Community gepflegter Leitfaden. coldwa.st ist eine Ressourcen-Website rund ums Programmieren; dieser Artikel ist ein neuer, eigenständiger Erklärtext zu Monaden in Haskell, ohne Verbindung zu irgendeinem Projekt und nicht von ihm verfasst. Der Code spiegelt das Standardverhalten von Haskell wider — prüfen Sie es anhand der aktuellen GHC-Dokumentation.