Haskell · Konzepte · Monaden
Monaden in Haskell, ohne Fachjargon erklärt
„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
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 beiNothingkurz ab, sodass Sie Nachschlagevorgänge verketten, ohne verschachtelte Null-Prüfungen.Either— der Kontext ist „kann mit einem Fehler scheitern“. WieMaybe, 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.