Ich habe eine Menge Posts gelesen, die erklären, was Monaden sind, wie unit
und wie sie bind
funktionieren. Einige davon tauchen direkt in die Kategorietheorie ein, die (zumindest für mich) so abstrakt ist, dass die Augen bluten, andere ignorieren diese und berühren seltsame Analogien von Burritos, Kisten und was nicht.
Nach ein paar Wochen des Studiums und vielen frittierten Neuronen verstehe ich, wie Monaden funktionieren. Aber es gibt noch eine Sache, die sich meinem Verständnis entzieht, etwas, das nur wenige Beiträge tatsächlich betreffen (außer IO und State):
WARUM?
Warum sind Monaden wichtig? Warum sind sie so wichtig? Welche Probleme lösen sie? Können diese Probleme nur mit Monaden gelöst werden oder gibt es andere Möglichkeiten?
functional-programming
problem-solving
monad
Dummy ich
quelle
quelle
Antworten:
Sie müssen nicht brauchen Monaden etwas zu lösen. Sie machen nur bestimmte Dinge einfacher. Viele Leute gehen viel zu abstrakt und theoretisch vor, wenn sie Monaden erklären. Meist sind Monaden ein Muster, das beim Programmieren immer wieder auftaucht. Indem wir dieses Muster erkennen, können wir unseren Code vereinfachen und vermeiden, dass bestimmte Funktionen erneut implementiert werden.
Für Haskell ist aus konkreter Sicht die Do-Notation das sichtbarste, was Monaden ermöglichen . Listenverständnisse in Haskell und anderen Sprachen machen sich Monaden ebenfalls zunutze. Sie können auch Bibliotheken wie Control.Monad erstellen .
Dies alles bietet nützliche Vereinfachungen und sobald Sie es für eine Monade implementiert haben, erhalten Sie es automatisch für alle Monaden. Dies ist einer der Hauptgründe, warum die Wiederverwendung von Code für die funktionale Programmierung so viel einfacher ist als andere Paradigmen.
quelle
IO
ist Haskells bekannteste Monade , aber ich habe keine Beispiele für einzelne Monaden aufgeführt. Ich habe Beispiele für die übergreifenden Abstraktionen aufgelistet, die sie ermöglichen. Ich habe versucht herauszufinden, warum zum Beispiel der erste, der an eine Monade für E / A denkt, der Meinung ist, dass dies im Allgemeinen eine gute Idee ist.Es ist einfacher zu verstehen, wenn Sie sich die einzelnen Monaden ansehen und sehen, welche Probleme sie lösen. Zum Beispiel in Haskell:
E / A: Ermöglicht die Darstellung von E / A im Typensystem, sodass Sie reine Funktionen klar von Funktionen trennen können, die E / A ausführen.
Liste: Hier können Sie Listenverständnisse und nodeterministische Berechnungen durchführen.
Vielleicht: Eine bessere Alternative zu Nullen und Unterstützung für etwas, das mit dem Null-Koaleszenz-Operator von C # vergleichbar ist.
Parsec: Ein praktisches DSL zum Schreiben von Parsern.
Es ist also leicht (ich hoffe), die Gründe für die einzelnen Monaden zu erkennen, da sie alle ziemlich nützlich sind. Aber die Probleme, die sie lösen, sind auch ganz anders und auf den ersten Blick scheinen sie nicht viel gemeinsam zu haben, außer dass sie alle mit einer Logik für Verkettungsoperationen zusammenhängen. Monaden sind nützlich, weil Sie so viele verschiedene Tools erstellen können.
Könnten die obigen Beispiele ohne Monaden implementiert werden? Sicherlich könnten sie ad-hoc implementiert werden, aber wenn Monaden in die Sprache integriert sind, können Sie direkte Sprachunterstützung wie die
do
-Notation verwenden, die für alle Monaden gilt.quelle
Eine Sache, die es verwirrend macht, ist, dass die "populären" Funktionen wie
bind
und<*>
praxisorientiert sind. Um die Konzepte zu verstehen, ist es jedoch einfacher, zuerst andere Funktionen zu betrachten. Es ist auch erwähnenswert, dass Monaden hervorstechen, weil sie im Vergleich zu anderen verbundenen Konzepten etwas überzeichnet sind. Also werde ich stattdessen mit Funktoren beginnen.Funktoren bieten eine Funktion (in Haskell-Notation)
fmap :: (Functor f) => (a -> b) -> f a -> f b
. Mit anderen Worten, Sie haben einen Kontextf
, in den Sie eine Funktion heben können. Wie Sie sich vorstellen können, ist fast alles ein Funktor. Listen, Vielleicht, Entweder, Funktionen, I / O, Tupel, Parser ... Jedes repräsentiert einen Kontext, in dem ein Wert erscheinen kann. So können Sie äußerst vielseitige Funktionen schreiben, die in nahezu jedem Kontext mitfmap
oder in der Inline-Variante funktionieren<$>
.Was möchten Sie sonst noch mit Kontexten machen? Möglicherweise möchten Sie zwei Kontexte kombinieren. Vielleicht möchten Sie eine Verallgemeinerung von
zip :: [a] -> [b] -> [(a,b)]
zum Beispiel wie folgt aus :pair :: (Monoidal f) => f a -> f b -> f (a,b)
.Aber weil es in der Praxis noch nützlicher ist, bieten die Haskell-Bibliotheken stattdessen
Applicative
eine Kombination ausFunctor
undMonoidal
undUnit
, die nur hinzufügt, dass Sie tatsächlich Werte "in" Ihren Kontext einfügen könnenunit
.Sie können äußerst allgemeine Funktionen schreiben, indem Sie nur diese drei Dinge über den Kontext angeben, in dem Sie arbeiten.
Monad
ist nur eine andere Sache, die Sie dazu sagen können. Was ich vorher nicht erwähnt habe, ist, dass Sie bereits zwei Möglichkeiten haben, zwei Kontexte zu kombinieren: Sie können nicht nurpair
sie, sondern Sie können sie auch stapeln, z. B. Sie können eine Liste von Listen haben. Im E / A-Kontext wäre ein Beispiel eine E / A-Aktion, die andere E / A-Aktionen aus einer Datei lesen kann, sodass Sie einen Typ hättenFilePath -> IO (IO a)
. Wie können wir dieses Stapeln loswerden, um eine ausführbare Funktion zu erhaltenIO a
? Hier kommtMonad
s insjoin
Spiel, es ermöglicht uns, zwei gestapelte Kontexte desselben Typs zu kombinieren. Das gleiche gilt für Parser, Vielleicht usw. Undbind
ist nur eine praktischere Art der Verwendungjoin
Ein monadischer Kontext muss also nur vier Dinge bieten und kann mit fast allen Maschinen verwendet werden, die für E / A, für Parser, für Ausfälle usw. entwickelt wurden.
quelle
Mit Monaden können Sie verschiedene nicht reine Berechnungen ausführen und den Code vereinfachen
Und vor allem, ohne Kompromisse mit den reinen Sprachkonstrukten einzugehen und eine sauberere Sprache daraus zu machen
quelle
Maybe
haben nichts mit Äußerem zu tun.