Was wäre eine kurze, prägnante und praktische Erklärung, was eine Monade im Wesentlichen ist , nachdem sie sich kürzlich kurz mit Haskell befasst hat?
Ich habe festgestellt, dass die meisten Erklärungen, auf die ich gestoßen bin, ziemlich unzugänglich sind und keine praktischen Details enthalten.
haskell
functional-programming
monads
terminology
Peter Mortensen
quelle
quelle
Antworten:
Erstens: Der Begriff Monade ist etwas leer, wenn Sie kein Mathematiker sind. Ein alternativer Begriff ist Computation Builder, der etwas aussagekräftiger ist, wofür sie tatsächlich nützlich sind.
Sie fragen nach praktischen Beispielen:
Beispiel 1: Listenverständnis :
Dieser Ausdruck gibt das Doppel aller ungeraden Zahlen im Bereich von 1 bis 10 zurück. Sehr nützlich!
Es stellt sich heraus, dass dies für einige Operationen innerhalb der List-Monade wirklich nur syntaktischer Zucker ist. Das gleiche Listenverständnis kann geschrieben werden als:
Oder auch:
Beispiel 2: Eingabe / Ausgabe :
Beide Beispiele verwenden Monaden, AKA-Berechnungsgeneratoren. Das gemeinsame Thema ist, dass die Monadenketten auf eine bestimmte, nützliche Weise operieren . Im Listenverständnis sind die Operationen so verkettet, dass, wenn eine Operation eine Liste zurückgibt, die folgenden Operationen für jedes Element in der Liste ausgeführt werden. Die E / A-Monade hingegen führt die Operationen nacheinander aus, gibt jedoch eine "versteckte Variable" weiter, die den "Zustand der Welt" darstellt, wodurch wir E / A-Code auf rein funktionale Weise schreiben können.
Es stellt sich heraus, dass das Muster der Verkettungsvorgänge sehr nützlich ist und für viele verschiedene Dinge in Haskell verwendet wird.
Ein weiteres Beispiel sind Ausnahmen: Bei Verwendung der
Error
Monade werden Operationen so verkettet, dass sie nacheinander ausgeführt werden, es sei denn, es wird ein Fehler ausgegeben. In diesem Fall wird der Rest der Kette abgebrochen.Sowohl die Syntax des Listenverständnisses als auch die Do-Notation sind syntaktischer Zucker für Verkettungsoperationen mit dem
>>=
Operator. Eine Monade ist im Grunde nur ein Typ, der den>>=
Operator unterstützt .Beispiel 3: Ein Parser
Dies ist ein sehr einfacher Parser, der entweder eine Zeichenfolge in Anführungszeichen oder eine Zahl analysiert:
Die Operationen
char
,digit
etc. sind ziemlich einfach. Sie stimmen entweder überein oder stimmen nicht überein. Die Magie ist die Monade, die den Kontrollfluss verwaltet: Die Operationen werden nacheinander ausgeführt, bis ein Match fehlschlägt. In diesem Fall wird die Monade auf die neueste zurückgesetzt<|>
und versucht die nächste Option. Wieder eine Möglichkeit, Operationen mit einer zusätzlichen, nützlichen Semantik zu verketten.Beispiel 4: Asynchrone Programmierung
Die obigen Beispiele sind in Haskell, aber es stellt sich heraus, dass F # auch Monaden unterstützt. Dieses Beispiel wurde Don Syme gestohlen :
Diese Methode ruft eine Webseite ab. Die Pointe wird verwendet von
GetResponseAsync
- sie wartet tatsächlich auf die Antwort in einem separaten Thread, während der Haupt-Thread von der Funktion zurückkehrt. Die letzten drei Zeilen werden auf dem erzeugten Thread ausgeführt, wenn die Antwort empfangen wurde.In den meisten anderen Sprachen müssten Sie explizit eine separate Funktion für die Zeilen erstellen, die die Antwort verarbeiten. Die
async
Monade ist in der Lage, den Block selbst zu "teilen" und die Ausführung der zweiten Hälfte zu verschieben. (Dieasync {}
Syntax gibt an, dass der Kontrollfluss im Block von derasync
Monade definiert wird .)Wie sie arbeiten
Wie kann eine Monade all diese ausgefallenen Kontrollfluss-Dinge tun? Was tatsächlich in einem do-Block (oder einem Berechnungsausdruck, wie sie in F # genannt werden) passiert , ist, dass jede Operation (im Grunde jede Zeile) in eine separate anonyme Funktion eingeschlossen ist. Diese Funktionen werden dann mit dem
bind
Operator (>>=
in Haskell geschrieben) kombiniert . Da diebind
Operation Funktionen kombiniert, kann sie sie nach Belieben ausführen: nacheinander mehrmals, in umgekehrter Reihenfolge, einige verwerfen, einige in einem separaten Thread ausführen, wenn es ihnen gefällt, und so weiter.Dies ist beispielsweise die erweiterte Version des E / A-Codes aus Beispiel 2:
Das ist hässlicher, aber es ist auch offensichtlicher, was tatsächlich vor sich geht. Der
>>=
Operator ist die magische Zutat: Er nimmt einen Wert (auf der linken Seite) und kombiniert ihn mit einer Funktion (auf der rechten Seite), um einen neuen Wert zu erzeugen. Dieser neue Wert wird dann vom nächsten>>=
Operator übernommen und erneut mit einer Funktion kombiniert, um einen neuen Wert zu erzeugen.>>=
kann als Mini-Evaluator angesehen werden.Beachten Sie, dass dies
>>=
für verschiedene Typen überladen ist, sodass jede Monade ihre eigene Implementierung von hat>>=
. (Alle Operationen in der Kette müssen jedoch vom Typ derselben Monade sein, sonst>>=
funktioniert der Bediener nicht.)Die einfachste mögliche Implementierung von
>>=
nimmt nur den Wert auf der linken Seite und wendet ihn auf die Funktion auf der rechten Seite an und gibt das Ergebnis zurück. Wie bereits erwähnt, ist das gesamte Muster nützlich, wenn in der Implementierung der Monade etwas Besonderes vor sich geht>>=
.Es gibt einige zusätzliche Klugheit bei der Übergabe der Werte von einer Operation zur nächsten, dies erfordert jedoch eine eingehendere Erläuterung des Haskell-Typsystems.
Zusammenfassen
In Haskell-Begriffen ist eine Monade ein parametrisierter Typ, der eine Instanz der Monad-Typklasse ist, die
>>=
zusammen mit einigen anderen Operatoren definiert wird. Für Laien ist eine Monade nur ein Typ, für den die>>=
Operation definiert ist.An sich
>>=
ist es nur eine umständliche Art, Funktionen zu verketten, aber mit der Do-Notation, die das "Sanitär" verbirgt, erweisen sich die monadischen Operationen als eine sehr schöne und nützliche Abstraktion, die an vielen Stellen in der Sprache nützlich und nützlich ist zum Erstellen eigener Mini-Sprachen in der Sprache.Warum sind Monaden schwer?
Für viele Haskell-Lernende sind Monaden ein Hindernis, das sie wie eine Mauer treffen. Es ist nicht so, dass Monaden selbst komplex sind, sondern dass die Implementierung auf vielen anderen erweiterten Haskell-Funktionen wie parametrisierten Typen, Typklassen usw. beruht. Das Problem ist, dass Haskell I / O auf Monaden basiert und I / O wahrscheinlich eines der ersten Dinge ist, die Sie beim Erlernen einer neuen Sprache verstehen möchten - schließlich macht es nicht viel Spaß, Programme zu erstellen, die keine produzieren Ausgabe. Ich habe keine unmittelbare Lösung für dieses Henne-Ei-Problem, außer die Behandlung von E / A wie "Magie passiert hier", bis Sie genug Erfahrung mit anderen Teilen der Sprache haben. Es tut uns leid.
Ausgezeichneter Blog über Monaden: http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
quelle
"Was ist eine Monade?" Zu erklären ist ein bisschen wie "Was ist eine Zahl?" Wir verwenden ständig Zahlen. Aber stellen Sie sich vor, Sie haben jemanden getroffen, der nichts über Zahlen wusste. Wie zum Teufel würden Sie erklären, was Zahlen sind? Und wie würden Sie überhaupt beschreiben, warum das nützlich sein könnte?
Was ist eine Monade? Die kurze Antwort: Es ist eine spezielle Art, Operationen miteinander zu verketten.
Im Wesentlichen schreiben Sie Ausführungsschritte und verknüpfen sie mit der "Bindefunktion". (In Haskell heißt es
>>=
.) Sie können die Aufrufe selbst an den Bind-Operator schreiben oder Syntaxzucker verwenden, wodurch der Compiler diese Funktionsaufrufe für Sie einfügt. In beiden Fällen wird jeder Schritt durch einen Aufruf dieser Bindefunktion getrennt.Die Bindungsfunktion ist also wie ein Semikolon. Es trennt die Schritte in einem Prozess. Die Aufgabe der Bindefunktion besteht darin, die Ausgabe aus dem vorherigen Schritt in den nächsten Schritt einzuspeisen.
Das klingt nicht zu schwer, oder? Aber es gibt mehr als eine Art von Monade. Warum? Wie?
Nun, die Bindefunktion kann nur das Ergebnis aus einem Schritt übernehmen und es dem nächsten Schritt zuführen. Aber wenn das "alles" ist, was die Monade tut ... ist das eigentlich nicht sehr nützlich. Und das ist wichtig , zu verstehen: Jede nützliche Monade tut etwas anderes zusätzlich nur eine Monade zu sein. Jede nützliche Monade hat eine "besondere Kraft", die sie einzigartig macht.
(Eine Monade, die nichts Besonderes tut , wird als "Identitätsmonade" bezeichnet. Ähnlich wie die Identitätsfunktion klingt dies wie eine völlig sinnlose Sache, stellt sich jedoch als nicht ... Aber das ist eine andere Geschichte ™.)
Grundsätzlich hat jede Monade ihre eigene Implementierung der Bindefunktion. Und Sie können eine Bindefunktion so schreiben, dass sie zwischen den Ausführungsschritten Fehler macht. Zum Beispiel:
Wenn jeder Schritt eine Erfolgs- / Fehleranzeige zurückgibt, können Sie den nächsten Schritt nur dann ausführen lassen, wenn der vorherige erfolgreich war. Auf diese Weise bricht ein fehlgeschlagener Schritt die gesamte Sequenz "automatisch" ab, ohne dass Sie einen bedingten Test durchführen müssen. (Die Fehlermonade .)
Wenn Sie diese Idee erweitern, können Sie "Ausnahmen" implementieren. (Die Fehlermonade oder Ausnahmemonade .) Da Sie sie selbst definieren und keine Sprachfunktion sind, können Sie definieren, wie sie funktionieren. (Vielleicht möchten Sie die ersten beiden Ausnahmen ignorieren und nur abbrechen, wenn eine dritte Ausnahme ausgelöst wird.)
Sie können dafür sorgen, dass jeder Schritt mehrere Ergebnisse zurückgibt und die Bindungsfunktionsschleife über ihnen liegt, wobei jedes für Sie in den nächsten Schritt eingespeist wird. Auf diese Weise müssen Sie nicht ständig Schleifen schreiben, wenn Sie mit mehreren Ergebnissen arbeiten. Die Bindefunktion "automatisch" erledigt das alles für Sie. (Die Listenmonade .)
Sie können nicht nur ein "Ergebnis" von einem Schritt zum anderen übergeben, sondern auch zusätzliche Daten an die Bindefunktion weitergeben . Diese Daten werden jetzt nicht in Ihrem Quellcode angezeigt, aber Sie können trotzdem von überall darauf zugreifen, ohne sie manuell an jede Funktion übergeben zu müssen. (Die Lesermonade .)
Sie können es so gestalten, dass die "zusätzlichen Daten" ersetzt werden können. Auf diese Weise können Sie destruktive Updates simulieren , ohne destruktive Updates durchzuführen. (Die Staatsmonade und ihr Cousin, die Schriftstellermonade .)
Da Sie nur destruktive Updates simulieren , können Sie trivial Dinge tun, die mit echten destruktiven Updates unmöglich wären . Sie können beispielsweise das letzte Update rückgängig machen oder zu einer älteren Version zurückkehren .
Sie können eine Monade erstellen , in der Berechnungen angehalten werden können , sodass Sie Ihr Programm anhalten, interne Statusdaten basteln und dann fortsetzen können.
Sie können "Fortsetzungen" als Monade implementieren. Dies ermöglicht es Ihnen, die Meinung der Menschen zu brechen!
All dies und mehr ist mit Monaden möglich. All dies ist natürlich auch ohne Monaden durchaus möglich . Mit Monaden ist es nur drastisch einfacher .
quelle
Entgegen dem allgemeinen Verständnis von Monaden haben sie eigentlich nichts mit Staat zu tun. Monaden sind einfach eine Möglichkeit, Dinge zu verpacken und Methoden bereitzustellen, um Operationen an den verpackten Sachen durchzuführen, ohne sie auszupacken.
Sie können beispielsweise in Haskell einen Typ erstellen, um einen anderen zu verpacken:
Um Dinge zu verpacken, die wir definieren
Um Vorgänge ohne Auspacken auszuführen, sagen wir, Sie haben eine Funktion
f :: a -> b
, dann können Sie dies tun, um zu heben Funktion , um auf umschlossene Werte zu reagieren:Das ist ungefähr alles, was es zu verstehen gibt. Es stellt sich jedoch heraus , dass es eine allgemeinere Funktion ist , dies zu tun Heben , das ist
bind
:bind
kann ein bisschen mehr alsfmap
, aber nicht umgekehrt. Eigentlichfmap
kann nur in Bezug aufbind
und definiert werdenreturn
. Wenn Sie also eine Monade definieren, geben Sie ihren Typ an (hier war esWrapped a
) und sagen dann, wie ihrereturn
undbind
Operationen funktionieren.Das Coole ist, dass sich herausstellt, dass dies ein so allgemeines Muster ist, dass es überall auftaucht. Der reine Einkapselungszustand ist nur eines davon.
Einen guten Artikel darüber, wie Monaden verwendet werden können, um funktionale Abhängigkeiten einzuführen und damit die Reihenfolge der Auswertung zu steuern, wie sie in Haskells IO-Monade verwendet wird, finden Sie unter IO Inside .
Machen Sie sich keine Sorgen, wenn Sie Monaden verstehen wollen. Lesen Sie über sie, was Sie interessant finden, und machen Sie sich keine Sorgen, wenn Sie nicht sofort verstehen. Dann ist es der richtige Weg, nur in einer Sprache wie Haskell zu tauchen. Monaden sind eines dieser Dinge, bei denen das Verstehen durch Übung in Ihr Gehirn eindringt. Eines Tages merkt man plötzlich, dass man sie versteht.
quelle
Aber du hättest Monaden erfinden können!
quelle
Eine Monade ist ein Datentyp, der zwei Operationen hat:
>>=
(akabind
) undreturn
(akaunit
).return
nimmt einen beliebigen Wert und erstellt damit eine Instanz der Monade.>>=
Nimmt eine Instanz der Monade und ordnet eine Funktion darüber zu. (Sie können bereits sehen, dass eine Monade ein seltsamer Datentyp ist, da Sie in den meisten Programmiersprachen keine Funktion schreiben konnten, die einen beliebigen Wert annimmt und daraus einen Typ erstellt. Monaden verwenden eine Art parametrischen Polymorphismus .)In der Haskell-Notation wird die Monadenschnittstelle geschrieben
Diese Operationen sollen bestimmten "Gesetzen" gehorchen, aber das ist nicht besonders wichtig: Die "Gesetze" kodifizieren nur das Verhalten vernünftiger Implementierungen der Operationen (im Grunde genommen das
>>=
undreturn
sollten sich darüber einig sein, wie Werte in Monadeninstanzen umgewandelt werden und Das>>=
ist assoziativ).Bei Monaden geht es nicht nur um Zustand und E / A: Sie abstrahieren ein gemeinsames Berechnungsmuster, das die Arbeit mit Zustand, E / A, Ausnahmen und Nichtdeterminismus umfasst. Die wahrscheinlich am einfachsten zu verstehenden Monaden sind Listen und Optionstypen:
wo
[]
und:
sind die Listenkonstruktoren,++
ist der Verkettungsoperator undJust
undNothing
sind dieMaybe
Konstruktoren. Beide Monaden kapseln gemeinsame und nützliche Berechnungsmuster für ihre jeweiligen Datentypen (beachten Sie, dass beides nichts mit Nebenwirkungen oder E / A zu tun hat).Sie müssen wirklich herumspielen, um einen nicht trivialen Haskell-Code zu schreiben, um zu verstehen, worum es bei Monaden geht und warum sie nützlich sind.
quelle
Sie sollten zuerst verstehen, was ein Funktor ist. Verstehe vorher Funktionen höherer Ordnung.
Eine Funktion höherer Ordnung ist einfach eine Funktion, die eine Funktion als Argument verwendet.
Ein Funktor ist eine beliebige Typkonstruktion,
T
für die es eine Funktion höherer Ordnungmap
gibt, die eine Funktion vom Typa -> b
(bei zwei beliebigen Typena
undb
) in eine Funktion umwandeltT a -> T b
. Diesemap
Funktion muss auch den Gesetzen der Identität und Zusammensetzung entsprechen, so dass die folgenden Ausdrücke für allep
undq
(Haskell-Notation) wahr sind :Ein aufgerufener
List
Typkonstruktor ist beispielsweise ein Funktor, wenn er mit einer Funktion vom Typ ausgestattet ist,(a -> b) -> List a -> List b
die den oben genannten Gesetzen entspricht. Die einzige praktische Umsetzung liegt auf der Hand. Die resultierendeList a -> List b
Funktion durchläuft die angegebene Liste, ruft die(a -> b)
Funktion für jedes Element auf und gibt die Liste der Ergebnisse zurück.Ein monadisch ist im wesentlichen nur ein Funktors
T
mit zwei zusätzlichen Methodenjoin
, vom TypT (T a) -> T a
undunit
(manchmal genanntreturn
,fork
oderpure
) vom Typa -> T a
. Für Listen in Haskell:Warum ist das nützlich? Weil Sie zum Beispiel
map
über eine Liste mit einer Funktion gehen könnten, die eine Liste zurückgibt.Join
Nimmt die resultierende Liste der Listen und verkettet sie.List
ist eine Monade, weil dies möglich ist.Sie können eine Funktion schreiben , die tut
map
, dannjoin
. Diese Funktion heißtbind
oderflatMap
oder(>>=)
oder oder(=<<)
. So wird normalerweise eine Monadeninstanz in Haskell angegeben.Eine Monade muss bestimmte Gesetze erfüllen, nämlich
join
assoziative. Dies bedeutet, wenn Sie einen Wertx
vom Typ haben,[[[a]]]
dannjoin (join x)
gleich sein solltejoin (map join x)
. Undpure
muss eine Identität für seinjoin
, dassjoin (pure x) == x
.quelle
[Haftungsausschluss: Ich versuche immer noch, Monaden vollständig zu groken. Das Folgende ist genau das, was ich bisher verstanden habe. Wenn es falsch ist, ruft mich hoffentlich jemand, der sich auskennt, auf dem Teppich an.]
Arnar schrieb:
Genau das ist es. Die Idee geht so:
Sie nehmen einen Wert und verpacken ihn mit zusätzlichen Informationen. So wie der Wert von einer bestimmten Art ist (z. B. eine Ganzzahl oder eine Zeichenfolge), so sind die zusätzlichen Informationen von einer bestimmten Art.
Zum Beispiel könnte diese zusätzliche Information eine
Maybe
oder eine seinIO
.Dann haben Sie einige Operatoren, mit denen Sie die umschlossenen Daten bearbeiten können, während Sie diese zusätzlichen Informationen mitnehmen. Diese Operatoren verwenden die zusätzlichen Informationen, um zu entscheiden, wie das Verhalten der Operation für den umschlossenen Wert geändert werden soll.
ZB
Maybe Int
kann a einJust Int
oder seinNothing
. Wenn Sie nun aMaybe Int
zu a hinzufügenMaybe Int
, prüft der Operator, ob beideJust Int
s enthalten sind, und wenn ja, packt er dasInt
s aus, übergibt ihm den Additionsoperator und verpackt das Ergebnis erneutInt
in ein neuesJust Int
(was gültig ist)Maybe Int
) und geben damit a zurückMaybe Int
. Wenn jedoch einer von ihnen einNothing
Inside war, kehrt dieser Operator sofort zurückNothing
, was wiederum gültig istMaybe Int
. Auf diese Weise können Sie so tun, als wären IhreMaybe Int
s nur normale Zahlen, und sie regelmäßig berechnen. Wenn Sie eine erhaltenNothing
, werden Ihre Gleichungen immer noch das richtige Ergebnis liefern - ohne dass SieNothing
überall Wurfprüfungen durchführen müssen .Aber das Beispiel ist genau das, wofür es passiert
Maybe
. Wenn die zusätzlichen Informationen eine wären, würde stattdessen derIO
fürIO
s definierte spezielle Operator aufgerufen, und er könnte vor dem Hinzufügen etwas völlig anderes tun. (OK, zweiIO Int
s zusammen zu addieren ist wahrscheinlich unsinnig - ich bin mir noch nicht sicher.) (Auch wenn Sie auf das geachtet habenMaybe
Beispiel beachtet haben, haben Sie auch festgestellt, dass das „Umschließen eines Werts mit zusätzlichen Dingen“ nicht immer korrekt ist. Aber es ist schwierig um genau, richtig und präzise zu sein, ohne unergründlich zu sein.)Grundsätzlich bedeutet "Monade" ungefähr "Muster" . Anstelle eines Buches mit informell erklärten und speziell benannten Mustern haben Sie jetzt ein Sprachkonstrukt - Syntax und alles -, mit dem Sie neue Muster als Dinge in Ihrem Programm deklarieren können . (Die Ungenauigkeit hier ist, dass alle Muster einer bestimmten Form folgen müssen, daher ist eine Monade nicht ganz so allgemein wie ein Muster. Aber ich denke, das ist der engste Begriff, den die meisten Menschen kennen und verstehen.)
Und deshalb finden die Leute Monaden so verwirrend: weil sie so ein generisches Konzept sind. Zu fragen, was etwas zu einer Monade macht, ist ähnlich vage wie zu fragen, was etwas zu einem Muster macht.
Denken Sie jedoch an die Auswirkungen einer syntaktischen Unterstützung in der Sprache für die Idee eines Musters: Anstatt das Buch der Viererbande lesen und sich die Konstruktion eines bestimmten Musters merken zu müssen, schreiben Sie einfach Code, der dieses Muster in einem Agnostiker implementiert. generischer Weg einmal und dann sind Sie fertig! Sie können dieses Muster dann wiederverwenden, z. B. Besucher oder Strategie oder Fassade oder was auch immer, indem Sie die Vorgänge in Ihrem Code damit dekorieren, ohne es immer wieder neu implementieren zu müssen!
Deshalb finden Leute, die Monaden verstehen , sie so nützlich : Es ist kein Elfenbeinturm-Konzept, auf das intellektuelle Snobs stolz sind (OK, das natürlich auch, Teehee), aber es macht den Code tatsächlich einfacher.
quelle
M (M a) -> M a
. Die Tatsache, dass Sie daraus einen TypM a -> (a -> M b) -> M b
machen können, macht sie nützlich.Nach langem Bemühen denke ich, dass ich die Monade endlich verstehe. Nachdem ich meine lange Kritik an der überwiegend am besten bewerteten Antwort noch einmal gelesen habe, werde ich diese Erklärung anbieten.
Es gibt drei Fragen, die beantwortet werden müssen, um Monaden zu verstehen:
Wie ich in meinen ursprünglichen Kommentaren festgestellt habe, sind zu viele Monadenerklärungen in Frage 3 enthalten, ohne und bevor Frage 2 oder Frage 1 wirklich angemessen behandelt wird.
Warum brauchst du eine Monade?
Reine Funktionssprachen wie Haskell unterscheiden sich von imperativen Sprachen wie C oder Java darin, dass ein reines Funktionsprogramm nicht unbedingt Schritt für Schritt in einer bestimmten Reihenfolge ausgeführt wird. Ein Haskell-Programm ähnelt eher einer mathematischen Funktion, bei der Sie die "Gleichung" in beliebig vielen möglichen Reihenfolgen lösen können. Dies bringt eine Reihe von Vorteilen mit sich, unter anderem, dass bestimmte Arten von Fehlern ausgeschlossen werden, insbesondere solche, die sich auf Dinge wie "Zustand" beziehen.
Es gibt jedoch bestimmte Probleme, die mit diesem Programmierstil nicht so einfach zu lösen sind. Einige Dinge, wie die Konsolenprogrammierung und die Datei-E / A, müssen in einer bestimmten Reihenfolge ausgeführt werden oder den Status beibehalten. Eine Möglichkeit, dieses Problem zu lösen, besteht darin, eine Art Objekt zu erstellen, das den Status einer Berechnung darstellt, sowie eine Reihe von Funktionen, die ein Statusobjekt als Eingabe verwenden und ein neues modifiziertes Statusobjekt zurückgeben.
Erstellen wir also einen hypothetischen "Status" -Wert, der den Status eines Konsolenbildschirms darstellt. Es ist nicht wichtig, wie genau dieser Wert aufgebaut ist. Angenommen, es handelt sich um ein Array von ASCII-Zeichen mit Bytelänge, das das darstellt, was derzeit auf dem Bildschirm angezeigt wird, und ein Array, das die letzte vom Benutzer eingegebene Eingabezeile im Pseudocode darstellt. Wir haben einige Funktionen definiert, die den Konsolenstatus annehmen, ändern und einen neuen Konsolenstatus zurückgeben.
Um die Konsolenprogrammierung durchzuführen, aber auf rein funktionale Weise, müssten Sie viele Funktionsaufrufe ineinander verschachteln.
Wenn Sie auf diese Weise programmieren, bleibt der "reine" Funktionsstil erhalten, während Änderungen an der Konsole in einer bestimmten Reihenfolge erzwungen werden. Aber wir werden wahrscheinlich mehr als nur ein paar Operationen gleichzeitig ausführen wollen, wie im obigen Beispiel. Verschachtelungsfunktionen auf diese Weise werden unansehnlich. Was wir wollen, ist Code, der im Wesentlichen dasselbe wie oben tut, aber ein bisschen mehr so geschrieben ist:
Dies wäre in der Tat eine bequemere Art, es zu schreiben. Wie machen wir das aber?
Was ist eine Monade?
Sobald Sie einen Typ (z. B.
consolestate
) haben, den Sie zusammen mit einer Reihe von Funktionen definieren, die speziell für diesen Typ entwickelt wurden, können Sie das gesamte Paket dieser Dinge in eine "Monade" verwandeln, indem Sie einen Operator wie:
(bind) definieren, der dies automatisch tut speist Rückgabewerte links in Funktionsparameter rechts ein und alift
Operator, der normale Funktionen in Funktionen umwandelt, die mit dieser bestimmten Art von Bindungsoperator arbeiten.Wie wird eine Monade implementiert?
Sehen Sie andere Antworten, die ziemlich frei zu sein scheinen, um in die Details davon zu springen.
quelle
Nachdem ich vor einigen Jahren eine Antwort auf diese Frage gegeben habe, glaube ich, dass ich diese Antwort verbessern und vereinfachen kann mit ...
Eine Monade ist eine Technik zur Funktionskomposition, die die Behandlung einiger Eingabeszenarien mithilfe einer Kompositionsfunktion externalisiert.
bind
, um Eingaben während der Komposition vorzuverarbeiten.In der normalen Komposition wird die Funktion
compose (>>)
verwendet, um die zusammengesetzte Funktion nacheinander auf das Ergebnis ihres Vorgängers anzuwenden. Wichtig ist, dass die zusammengesetzte Funktion alle Szenarien ihrer Eingabe verarbeiten muss.(x -> y) >> (y -> z)
Dieses Design kann verbessert werden, indem die Eingabe so umstrukturiert wird, dass relevante Zustände leichter abgefragt werden können. So kann
y
der Wert statt einfach nur so werden,Mb
wie zum Beispiel,(is_OK, b)
wenn ery
einen Gültigkeitsbegriff enthält.Wenn die Eingabe beispielsweise möglicherweise nur eine Zahl ist, können Sie den Typ so umstrukturieren,
bool
dass er das Vorhandensein einer gültigen Zahl und einer Zahl im Tupel anzeigt, zbool * float
. Die zusammengesetzten Funktionen müssten nun keine Eingabezeichenfolge mehr analysieren, um festzustellen, ob eine Zahl vorhanden ist, sondern könnten lediglich denbool
Teil eines Tupels untersuchen.(Ma -> Mb) >> (Mb -> Mc)
Auch hier erfolgt die Komposition auf natürliche Weise mit,
compose
sodass jede Funktion alle Szenarien ihrer Eingabe einzeln behandeln muss, obwohl dies jetzt viel einfacher ist.Was wäre jedoch, wenn wir den Aufwand für die Befragung in Zeiten auslagern könnten, in denen die Behandlung eines Szenarios Routine ist? Was ist zum Beispiel, wenn unser Programm nichts tut, wenn die Eingabe nicht in Ordnung ist, wie in wann
is_OK
?false
. Wenn dies getan würde, müssten zusammengesetzte Funktionen dieses Szenario nicht selbst behandeln, was ihren Code dramatisch vereinfacht und eine weitere Ebene der Wiederverwendung bewirkt.Um diese Externalisierung zu erreichen, könnten wir eine Funktion verwenden,
bind (>>=)
um dascomposition
anstelle von auszuführencompose
. Anstatt einfach Werte von der Ausgabe einer Funktion auf die Eingabe einer anderen zu übertragen,Bind
würde dies denM
Teil von untersuchenMa
und entscheiden, ob und wie die zusammengesetzte Funktion auf die angewendet werden solla
. Natürlichbind
würde die Funktion speziell für unsere spezielle definiertM
, um ihre Struktur überprüfen und jede Art von Anwendung ausführen zu können, die wir wollen. Nichtsdestotrotza
kann das alles sein, da esbind
lediglich den durchläufta
Uninspektionierte an die zusammengesetzte Funktion übergeben wird, wenn es die erforderliche Anwendung bestimmt. Außerdem müssen sich die zusammengesetzten Funktionen selbst nicht mehr mit dem befassenM
Teil der Eingabestruktur entweder, um sie zu vereinfachen. Daher...(a -> Mb) >>= (b -> Mc)
oder prägnanterMb >>= (b -> Mc)
Kurz gesagt, eine Monade externalisiert und liefert dadurch ein Standardverhalten bei der Behandlung bestimmter Eingabeszenarien, sobald die Eingabe so ausgelegt ist, dass sie ausreichend verfügbar ist. Dieses Design ist ein
shell and content
Modell, bei dem die Shell Daten enthält, die für die Anwendung der zusammengesetzten Funktion relevant sind, von der Funktion abgefragt wird und nur für diese verfügbar bleibtbind
.Daher ist eine Monade drei Dinge:
M
Hülle für monadenrelevante Informationen,bind
Funktion, die implementiert ist, um diese Shell-Informationen bei der Anwendung der zusammengesetzten Funktionen auf die in der Shell gefundenen Inhaltswerte zu verwenden, unda -> Mb
die Ergebnisse liefern, die monadische Verwaltungsdaten enthalten.Im Allgemeinen ist die Eingabe in eine Funktion weitaus restriktiver als ihre Ausgabe, die beispielsweise Fehlerbedingungen enthalten kann. Daher ist die
Mb
Ergebnisstruktur im Allgemeinen sehr nützlich. Beispielsweise gibt der Divisionsoperator keine Zahl zurück, wenn der Divisor ist0
.Zusätzlich kann
monad
s Wrap-Funktionen enthalten, die Wertea
in den monadischen TypMa
und allgemeine Funktionena -> b
in monadische Funktionen einschließena -> Mb
, indem ihre Ergebnisse nach der Anwendung umbrochen werden . Natürlichbind
sind solche Wrap-Funktionen spezifisch fürM
. Ein Beispiel:Das Design der
bind
Funktion setzt unveränderliche Datenstrukturen und reine Funktionen voraus, andere Dinge werden komplex und Garantien können nicht gegeben werden. Als solche gibt es monadische Gesetze:Gegeben...
Dann...
Associativity
bedeutet, dassbind
die Reihenfolge der Bewertung unabhängig vom Zeitpunkt derbind
Anwendung erhalten bleibt. Das heißt, in derAssociativity
obigen Definition erzwingt die frühzeitige Bewertung der Klammernbinding
vonf
undg
führt nur zu einer Funktion, die erwartet,Ma
um die zu vervollständigenbind
. Daher muss die Bewertung vonMa
bestimmt werden, bevor ihr Wert angewendet werden kannf
und das Ergebnis wiederum angewendet wirdg
.quelle
Eine Monade ist effektiv eine Form von "Typoperator". Es wird drei Dinge tun. Zuerst wird ein Wert eines Typs in einen anderen Typ "umbrochen" (oder auf andere Weise konvertiert) (normalerweise als "monadischer Typ" bezeichnet). Zweitens werden alle Operationen (oder Funktionen) des zugrunde liegenden Typs für den monadischen Typ verfügbar gemacht. Schließlich wird es Unterstützung für die Kombination seines Selbst mit einer anderen Monade bieten, um eine zusammengesetzte Monade zu erzeugen.
Die "Vielleicht-Monade" entspricht im Wesentlichen den "nullbaren Typen" in Visual Basic / C #. Es nimmt einen nicht nullbaren Typ "T" und konvertiert ihn in einen "nullbaren <T>" und definiert dann, was alle binären Operatoren auf einem nullbaren <T> bedeuten.
Nebenwirkungen werden ähnlich dargestellt. Es wird eine Struktur erstellt, die neben dem Rückgabewert einer Funktion auch Beschreibungen von Nebenwirkungen enthält. Die "aufgehobenen" Operationen kopieren dann Nebenwirkungen, wenn Werte zwischen Funktionen übergeben werden.
Sie werden aus mehreren Gründen eher als "Monaden" als als der leicht verständliche Name "Typoperatoren" bezeichnet:
quelle
(Siehe auch die Antworten unter Was ist eine Monade? )
Eine gute Motivation für Monaden ist Sigfpe (Dan Piponi), Sie hätten Monaden erfinden können ! (Und vielleicht haben Sie schon) . Es gibt eine Menge anderer Monaden-Tutorials , von denen viele fälschlicherweise versuchen, Monaden mit verschiedenen Analogien in "einfachen Worten" zu erklären: Dies ist der Irrtum der Monaden-Tutorials ; vermeide sie.
Wie DR MacIver in Sagen Sie uns, warum Ihre Sprache scheiße ist :
Sie sagen, Sie verstehen die Vielleicht-Monade? Gut, du bist auf dem Weg. Fangen Sie einfach an, andere Monaden zu verwenden, und früher oder später werden Sie verstehen, was Monaden im Allgemeinen sind.
[Wenn Sie mathematisch orientiert sind, möchten Sie möglicherweise Dutzende von Tutorials ignorieren und die Definition lernen oder Vorlesungen in Kategorietheorie folgen :) Der Hauptteil der Definition besteht darin, dass eine Monade M einen "Typkonstruktor" enthält, der für jeden definiert vorhandener Typ "T" ein neuer Typ "MT" und einige Möglichkeiten zum Hin- und Herwechseln zwischen "regulären" Typen und "M" -Typen.]
Überraschenderweise ist eine der besten Einführungen in Monaden tatsächlich eine der frühen wissenschaftlichen Arbeiten, in denen Monaden vorgestellt werden, Philip Wadlers Monaden für die funktionale Programmierung . Im Gegensatz zu vielen künstlichen Tutorials gibt es tatsächlich praktische, nicht triviale Motivationsbeispiele.
quelle
Monaden sollen den Fluss steuern, welche abstrakten Datentypen zu Daten gehören.
Mit anderen Worten, viele Entwickler sind mit der Idee von Sets, Listen, Wörterbüchern (oder Hashes oder Maps) und Bäumen vertraut. Innerhalb dieser Datentypen gibt es viele Sonderfälle (z. B. InsertionOrderPreservingIdentityHashMap).
Wenn viele Entwickler jedoch mit dem Programm "Flow" konfrontiert werden, sind sie nicht viel mehr Konstrukten ausgesetzt als wenn, switch / case, do, while, goto (grr) und (vielleicht) Closures.
Eine Monade ist also einfach ein Kontrollflusskonstrukt. Ein besserer Ausdruck, um die Monade zu ersetzen, wäre "Kontrolltyp".
Daher verfügt eine Monade über Steckplätze für Steuerlogik, Anweisungen oder Funktionen. In Datenstrukturen bedeutet dies, dass Sie in einigen Datenstrukturen Daten hinzufügen und entfernen können.
Zum Beispiel die "wenn" -Monade:
Im einfachsten Fall gibt es zwei Slots - eine Klausel und einen Block. Die
if
Monade wird normalerweise erstellt, um das Ergebnis der Klausel auszuwerten, und wenn nicht falsch, den Block auszuwerten. Viele Entwickler werden nicht in Monaden eingeführt, wenn sie "Wenn" lernen, und es ist einfach nicht notwendig, Monaden zu verstehen, um effektive Logik zu schreiben.Monaden können komplizierter werden, genauso wie Datenstrukturen komplizierter werden können, aber es gibt viele breite Kategorien von Monaden, die eine ähnliche Semantik haben können, aber unterschiedliche Implementierungen und Syntax.
Natürlich können auf die gleiche Weise, wie Datenstrukturen über Monaden iteriert oder durchlaufen werden, Monaden ausgewertet werden.
Compiler unterstützen möglicherweise benutzerdefinierte Monaden oder nicht. Haskell sicherlich. Ioke hat einige ähnliche Fähigkeiten, obwohl der Begriff Monade in der Sprache nicht verwendet wird.
quelle
Mein Lieblings-Monaden-Tutorial:
http://www.haskell.org/haskellwiki/All_About_Monads
(von 170.000 Treffern bei einer Google-Suche nach "Monad Tutorial"!)
@Stu: Der Sinn von Monaden besteht darin, dass Sie (normalerweise) sequentielle Semantik zu ansonsten reinem Code hinzufügen können. Sie können sogar Monaden erstellen (mithilfe von Monadentransformatoren) und eine interessantere und kompliziertere kombinierte Semantik erhalten, z. B. das Parsen mit Fehlerbehandlung, gemeinsam genutztem Status und Protokollierung. All dies ist in reinem Code möglich. Monaden ermöglichen es Ihnen lediglich, ihn zu abstrahieren und in modularen Bibliotheken wiederzuverwenden (immer gut in der Programmierung). Außerdem bieten Sie eine praktische Syntax, damit er zwingend erscheint.
Haskell hat bereits eine Operatorüberladung [1]: Es verwendet Typklassen ähnlich wie Schnittstellen in Java oder C #, aber Haskell lässt zufällig auch nicht-alphanumerische Token wie + && und> als Infix-IDs zu. Es ist nur eine Überladung des Operators in Ihrer Sichtweise, wenn Sie "Überladen des Semikolons" meinen [2]. Es klingt wie schwarze Magie und bittet um Mühe, "das Semikolon zu überladen" (Bild unternehmungslustige Perl-Hacker, die Wind von dieser Idee bekommen), aber der Punkt ist, dass es ohne Monaden kein Semikolon gibt, da rein funktionaler Code keine explizite Sequenzierung erfordert oder erlaubt.
Das klingt alles viel komplizierter als nötig. sigfpes Artikel ist ziemlich cool, verwendet aber Haskell, um ihn zu erklären, was das Henne-Ei-Problem des Verstehens von Haskell, um Monaden zu groken, und des Verstehens von Monaden, um Haskell zu groken, nicht löst.
[1] Dies ist ein von Monaden getrenntes Problem, aber Monaden verwenden die Operatorüberladungsfunktion von Haskell.
[2] Dies ist auch eine übermäßige Vereinfachung, da der Operator für die Verkettung monadischer Aktionen >> = (ausgesprochen "bind") ist, aber es gibt syntaktischen Zucker ("do"), mit dem Sie geschweifte Klammern und Semikolons und / oder Einrückungen und Zeilenumbrüche verwenden können.
quelle
Ich habe in letzter Zeit anders über Monaden nachgedacht. Ich habe sie als mathematische Abstraktion der Ausführungsreihenfolge angesehen , die neue Arten von Polymorphismus ermöglicht.
Wenn Sie eine imperative Sprache verwenden und einige Ausdrücke der Reihe nach schreiben, wird der Code IMMER genau in dieser Reihenfolge ausgeführt.
Und im einfachen Fall, wenn Sie eine Monade verwenden, fühlt es sich genauso an - Sie definieren eine Liste von Ausdrücken, die in der richtigen Reihenfolge vorkommen. Je nachdem, welche Monade Sie verwenden, wird Ihr Code möglicherweise in der richtigen Reihenfolge (wie in der E / A-Monade) parallel über mehrere Elemente gleichzeitig (wie in der Listenmonade) ausgeführt und möglicherweise auf halbem Weg angehalten (wie in der Vielleicht-Monade). Es kann eine Pause einlegen, um später wieder aufgenommen zu werden (wie in einer Wiederaufnahme-Monade), es kann zurückgespult werden und von vorne beginnen (wie in einer Transaktions-Monade) oder es kann teilweise zurückgespult werden, um andere Optionen auszuprobieren (wie in einer Logik-Monade). .
Und da Monaden polymorph sind, können Sie je nach Bedarf denselben Code in verschiedenen Monaden ausführen.
In einigen Fällen ist es außerdem möglich, Monaden (mit Monadentransformatoren) miteinander zu kombinieren, um mehrere Funktionen gleichzeitig zu erhalten.
quelle
Ich bin noch neu in Monaden, aber ich dachte, ich würde einen Link teilen, den ich wirklich gut zum Lesen fand (MIT BILDERN !!): http://www.matusiak.eu/numerodix/blog/2012/3/11/ Monaden für den Laien / (keine Zugehörigkeit)
Grundsätzlich war das warme und unscharfe Konzept, das ich aus dem Artikel erhalten habe, das Konzept, dass Monaden im Grunde genommen Adapter sind, die es ermöglichen, dass unterschiedliche Funktionen auf komponierbare Weise funktionieren, dh mehrere Funktionen aneinanderreihen und mischen und anpassen können, ohne sich um eine inkonsistente Rückkehr sorgen zu müssen Typen und so. Die BIND-Funktion ist also dafür verantwortlich, Äpfel mit Äpfeln und Orangen mit Orangen zu halten, wenn wir versuchen, diese Adapter herzustellen. Und die LIFT-Funktion ist dafür verantwortlich, "untergeordnete" Funktionen zu übernehmen und sie zu "aktualisieren", um mit BIND-Funktionen zu arbeiten und auch zusammensetzbar zu sein.
Ich hoffe, ich habe es richtig verstanden und vor allem hoffe ich, dass der Artikel eine gültige Sicht auf Monaden hat. Wenn nichts anderes, hat dieser Artikel meinen Appetit geweckt, mehr über Monaden zu lernen.
quelle
Zusätzlich zu den hervorragenden Antworten oben möchte ich Ihnen einen Link zum folgenden Artikel (von Patrick Thomson) anbieten, in dem Monaden erläutert werden, indem das Konzept auf die JavaScript-Bibliothek jQuery bezogen wird (und wie "Methodenverkettung" zur Manipulation des DOM verwendet wird). : jQuery ist eine Monade
Die jQuery-Dokumentation selbst bezieht sich nicht auf den Begriff "Monade", sondern spricht über das wahrscheinlich bekanntere "Builder-Muster". Dies ändert nichts an der Tatsache, dass Sie dort eine richtige Monade haben, ohne es zu merken.
quelle
Monaden sind keine Metaphern , sondern eine praktisch nützliche Abstraktion, die aus einem gemeinsamen Muster hervorgeht, wie Daniel Spiewak erklärt.
quelle
Eine Monade ist eine Möglichkeit, Berechnungen miteinander zu kombinieren, die einen gemeinsamen Kontext haben. Es ist wie ein Rohrnetz. Beim Aufbau des Netzwerks fließen keine Daten durch das Netzwerk. Aber wenn ich alle Bits mit 'bind' und 'return' zusammengesetzt habe, rufe ich so etwas auf
runMyMonad monad data
und die Daten fließen durch die Pipes.quelle
In der Praxis ist monad eine benutzerdefinierte Implementierung eines Funktionszusammensetzungsoperators, der Nebenwirkungen und inkompatible Eingabe- und Rückgabewerte (für die Verkettung) berücksichtigt.
quelle
Wenn ich richtig verstanden habe, wird IEnumerable von Monaden abgeleitet. Ich frage mich, ob das ein interessanter Ansatz für diejenigen von uns aus der C # -Welt sein könnte.
Für das, was es wert ist, hier sind einige Links zu Tutorials, die mir geholfen haben (und nein, ich habe immer noch nicht verstanden, was Monaden sind).
quelle
Die beiden Dinge, die mir am besten geholfen haben, als ich davon erfuhr, waren:
Kapitel 8, "Functional Parsers", aus Graham Huttons Buch Programming in Haskell . Hier werden Monaden eigentlich gar nicht erwähnt, aber wenn Sie Kapitel durcharbeiten und wirklich alles darin verstehen können, insbesondere wie eine Folge von Bindungsoperationen bewertet wird, werden Sie die Interna von Monaden verstehen. Erwarten Sie, dass dies mehrere Versuche dauert.
Das Tutorial Alles über Monaden . Dies gibt einige gute Beispiele für ihre Verwendung, und ich muss sagen, dass die Analogie in Appendex, die ich für mich gearbeitet habe.
quelle
Monoid scheint etwas zu sein, das sicherstellt, dass alle Operationen, die für ein Monoid und einen unterstützten Typ definiert sind, immer einen unterstützten Typ innerhalb des Monoid zurückgeben. ZB Beliebige Zahl + Beliebige Zahl = Eine Zahl, keine Fehler.
Während die Division zwei Brüche akzeptiert und einen Bruch zurückgibt, der die Division durch Null als Unendlichkeit in haskell irgendwo definiert (was zufällig ein Bruch ist) ...
In jedem Fall scheinen Monaden nur eine Möglichkeit zu sein, um sicherzustellen, dass sich Ihre Operationskette vorhersehbar verhält, und eine Funktion, die behauptet, Num -> Num zu sein, die mit einer anderen Funktion von Num-> Num zusammengesetzt ist, die mit x aufgerufen wird, nicht Sagen Sie, schießen Sie die Raketen.
Wenn wir andererseits eine Funktion haben, die die Raketen abfeuert, können wir sie mit anderen Funktionen zusammensetzen, die auch die Raketen abfeuern, da unsere Absicht klar ist - wir wollen die Raketen abfeuern -, aber es wird nicht versucht Drucken von "Hello World" aus irgendeinem Grund.
In Haskell ist main vom Typ IO () oder IO [()], die Unterscheidung ist seltsam und ich werde nicht darauf eingehen, aber ich denke, dass Folgendes passiert:
Wenn ich main habe, möchte ich, dass es eine Kette von Aktionen ausführt. Der Grund, warum ich das Programm ausführe, ist, einen Effekt zu erzeugen - normalerweise über IO. Auf diese Weise kann ich E / A-Vorgänge hauptsächlich miteinander verketten, um E / A-Vorgänge auszuführen, sonst nichts.
Wenn ich versuche, etwas zu tun, das keine "E / A zurückgibt", beschwert sich das Programm, dass die Kette nicht fließt, oder im Grunde "Wie hängt dies mit dem zusammen, was wir versuchen - eine E / A-Aktion", scheint es zu erzwingen der Programmierer, um seinen Gedankengang beizubehalten, ohne abzuweichen und über das Abfeuern der Raketen nachzudenken, während er Algorithmen zum Sortieren erstellt - die nicht fließen.
Grundsätzlich scheinen Monaden ein Tipp für den Compiler zu sein: "Hey, Sie kennen diese Funktion, die hier eine Zahl zurückgibt. Sie funktioniert nicht immer, sie kann manchmal eine Zahl erzeugen und manchmal gar nichts. Behalten Sie dies einfach bei." Verstand". Wenn Sie dies wissen und versuchen, eine monadische Aktion zu behaupten, kann die monadische Aktion als Ausnahme für die Kompilierungszeit fungieren und sagen: "Hey, das ist eigentlich keine Zahl, das kann eine Zahl sein, aber Sie können nicht davon ausgehen, dass Sie etwas tun." um sicherzustellen, dass der Durchfluss akzeptabel ist. " Dies verhindert ein unvorhersehbares Programmverhalten - zu einem angemessenen Teil.
Es scheint, dass es bei Monaden nicht um Reinheit oder Kontrolle geht, sondern darum, die Identität einer Kategorie aufrechtzuerhalten, für die alles Verhalten vorhersehbar und definiert ist oder nicht kompiliert wird. Sie können nichts tun, wenn von Ihnen erwartet wird, dass Sie etwas tun, und Sie können nichts tun, wenn von Ihnen erwartet wird, dass Sie nichts tun (sichtbar).
Der größte Grund, an den ich für Monaden denken könnte, ist - schauen Sie sich den Prozedur- / OOP-Code an, und Sie werden feststellen, dass Sie nicht wissen, wo das Programm beginnt oder endet. Sie sehen nur viel Springen und viel Mathe , Magie und Raketen. Sie werden es nicht pflegen können, und wenn Sie können, werden Sie viel Zeit damit verbringen, sich mit dem gesamten Programm zu beschäftigen, bevor Sie einen Teil davon verstehen können, da die Modularität in diesem Kontext auf voneinander abhängigen "Abschnitten" basiert. von Code, wobei Code so optimiert ist, dass er so verwandt wie möglich ist, um Effizienz / Wechselbeziehung zu versprechen. Monaden sind sehr konkret und per Definition gut definiert und stellen sicher, dass der Programmfluss analysiert und Teile isoliert werden können, die schwer zu analysieren sind - da sie selbst Monaden sind. Eine Monade scheint eine " oder das Universum zerstören oder sogar die Zeit verzerren - wir haben weder eine Ahnung noch eine Garantie dafür, dass ES DAS IST, WAS ES IST. Eine Monade GARANTIERT, DASS ES IST, WAS ES IST. Das ist sehr mächtig. oder das Universum zerstören oder sogar die Zeit verzerren - wir haben weder eine Ahnung noch eine Garantie dafür, dass ES DAS IST, WAS ES IST. Eine Monade GARANTIERT, DASS ES IST, WAS ES IST. Das ist sehr mächtig.
Alle Dinge in der "realen Welt" scheinen Monaden zu sein, in dem Sinne, dass sie an bestimmte beobachtbare Gesetze gebunden sind, die Verwirrung verhindern. Dies bedeutet nicht, dass wir alle Operationen dieses Objekts nachahmen müssen, um Klassen zu erstellen. Stattdessen können wir einfach sagen: "Ein Quadrat ist ein Quadrat", nichts als ein Quadrat, nicht einmal ein Rechteck oder ein Kreis, und "ein Quadrat hat Fläche von der Länge einer der vorhandenen Dimensionen multipliziert mit sich selbst. Egal welches Quadrat Sie haben, wenn es ein Quadrat im 2D-Raum ist, kann seine Fläche absolut nichts anderes sein als seine quadratische Länge, es ist fast trivial zu beweisen. Dies ist sehr mächtig, weil Wir müssen keine Aussagen machen, um sicherzustellen, dass unsere Welt so ist, wie sie ist. Wir nutzen lediglich die Auswirkungen der Realität, um zu verhindern, dass unsere Programme aus der Bahn geraten.
Ich bin so ziemlich garantiert falsch, aber ich denke, das könnte jemandem da draußen helfen, also hoffentlich hilft es jemandem.
quelle
Im Zusammenhang mit Scala finden Sie Folgendes als einfachste Definition. Grundsätzlich ist flatMap (oder bind) 'assoziativ' und es gibt eine Identität.
Z.B
ANMERKUNG Genau genommen ist die Definition einer Monade in der funktionalen Programmierung nicht dieselbe wie die Definition einer Monade in der Kategorietheorie , die abwechselnd von
map
und definiert wirdflatten
. Obwohl sie unter bestimmten Zuordnungen eine Art Äquivalent sind. Diese Präsentation ist sehr gut: http://www.slideshare.net/samthemonad/monad-presentation-scala-as-a-categoryquelle
Diese Antwort beginnt mit einem motivierenden Beispiel, arbeitet das Beispiel durch, leitet ein Beispiel für eine Monade ab und definiert formal "Monade".
Betrachten Sie diese drei Funktionen im Pseudocode:
f
nimmt ein bestelltes Paar des Formulars<x, messages>
und gibt ein bestelltes Paar zurück. Der erste Artikel bleibt unberührt und wird"called f. "
an den zweiten Artikel angehängt . Gleiches gilt fürg
.Sie können diese Funktionen zusammenstellen und Ihren ursprünglichen Wert zusammen mit einer Zeichenfolge erhalten, die angibt, in welcher Reihenfolge die Funktionen aufgerufen wurden:
Sie mögen die Tatsache nicht
f
undg
sind dafür verantwortlich, ihre eigenen Protokollnachrichten an die vorherigen Protokollierungsinformationen anzuhängen. (Man stelle sich vor für die Zwecke der Beweisführung, dass anstelle Strings anhängt,f
undg
müssen komplizierte Logik auf dem zweiten Element des Paares ausführen Es wäre ein Schmerz zu wiederholen, dass komplizierte Logik in zwei -. Oder mehr -. Verschiedene Funktionen)Sie bevorzugen es, einfachere Funktionen zu schreiben:
Aber schauen Sie sich an, was passiert, wenn Sie sie komponieren:
Das Problem ist, dass das Übergeben eines Paares an eine Funktion Ihnen nicht das gibt, was Sie wollen. Aber was wäre , wenn Sie füttern ein Paar in eine Funktion:
Lesen Sie
feed(f, m)
als "Feedm
inf
". Um zu füttern ein Paar<x, messages>
in eine Funktionf
zu übergebenx
, inf
, erhalten<y, message>
ausf
und kehren<y, messages message>
.Beachten Sie, was passiert, wenn Sie drei Dinge mit Ihren Funktionen tun:
Erstens: Wenn Sie einen Wert wickeln und dann füttern das resultierende Paar in eine Funktion:
Dies entspricht der Übergabe des Werts an die Funktion.
Zweitens: Wenn Sie ein Paar füttern in
wrap
:Das ändert nichts an dem Paar.
Drittens: Wenn Sie eine Funktion definieren , die nehmen
x
und führeng(x)
inf
:und füttere ein Paar hinein:
Dies entspricht dem Einspeisen des Paares
g
und dem Einspeisen des resultierenden Paaresf
.Sie haben fast eine Monade. Jetzt müssen Sie nur noch die Datentypen in Ihrem Programm kennen.
Was für ein Wert ist das
<x, "called f. ">
? Nun, das hängt davon ab, welche Art von Wertx
ist. Wennx
es sich um einen Typ handeltt
, ist Ihr Paar ein Wert vom Typ "Paart
und Zeichenfolge". Nennen Sie diesen TypM t
.M
ist ein Typkonstruktor:M
allein bezieht sich nicht auf einen Typ, sondernM _
auf einen Typ, sobald Sie die Lücke mit einem Typ ausfüllen. AnM int
ist ein Paar aus einem int und einem String. AnM string
ist ein Paar aus einer Zeichenfolge und einer Zeichenfolge. Usw.Herzlichen Glückwunsch, Sie haben eine Monade erstellt!
Formal ist Ihre Monade das Tupel
<M, feed, wrap>
.Eine Monade ist ein Tupel,
<M, feed, wrap>
in dem:M
ist ein Typkonstruktor.feed
nimmt eine (Funktion, die a nimmtt
und eine zurückgibtM u
) und eineM t
und gibt eine zurückM u
.wrap
nimmt einv
und gibt ein zurückM v
.t
,,u
undv
sind drei beliebige Typen, die gleich sein können oder nicht. Eine Monade erfüllt die drei Eigenschaften, die Sie für Ihre spezifische Monade bewiesen haben:Das Einspeisen eines Wraps
t
in eine Funktion entspricht dem Übergeben des Unwrappedt
in die Funktion.Formal:
feed(f, wrap(x)) = f(x)
Einspeisen
M t
inwrap
tut nichts mit demM t
.Formal:
feed(wrap, m) = m
Einspeisen
M t
(nennenm
) in eine Funktion, diet
ing
M u
(nenne esn
) vong
n
inf
ist das gleiche wie
m
ing
n
vong
n
inf
Formal:
feed(h, m) = feed(f, feed(g, m))
woh(x) := feed(f, g(x))
In der Regel
feed
heißtbind
(AKA>>=
in Haskell) undwrap
heißtreturn
.quelle
Ich werde versuchen,
Monad
im Zusammenhang mit Haskell zu erklären .Bei der funktionalen Programmierung ist die Funktionszusammensetzung wichtig. Dadurch kann unser Programm aus kleinen, leicht lesbaren Funktionen bestehen.
Nehmen wir an, wir haben zwei Funktionen:
g :: Int -> String
undf :: String -> Bool
.Wir können tun
(f . g) x
, was genau das gleiche ist wief (g x)
, wox
einInt
Wert ist.Bei der Komposition / Anwendung des Ergebnisses einer Funktion auf eine andere ist es wichtig, dass die Typen übereinstimmen. Im obigen Fall muss der Typ des zurückgegebenen Ergebnisses
g
mit dem Typ übereinstimmen, der von akzeptiert wirdf
.Aber manchmal befinden sich Werte in Kontexten, und dies macht es etwas weniger einfach, Typen auszurichten. (Es ist sehr nützlich, Werte in Kontexten zu haben. Beispielsweise stellt der
Maybe Int
Typ einenInt
Wert dar, der möglicherweise nicht vorhanden ist. DerIO String
Typ stellt einenString
Wert dar, der aufgrund einiger Nebenwirkungen vorhanden ist.)Nehmen wir an, wir haben jetzt
g1 :: Int -> Maybe String
undf1 :: String -> Maybe Bool
.g1
undf1
sind sehr ähnlichg
undf
sind.Wir können nicht
(f1 . g1) x
oderf1 (g1 x)
wox
ist einInt
Wert. Der Typ des zurückgegebenen Ergebnisses entsprichtg1
nicht denf1
Erwartungen.Wir könnten komponieren
f
undg
mit dem.
Operator, aber jetzt können wir nicht komponierenf1
undg1
mit.
. Das Problem ist, dass wir einen Wert in einem Kontext nicht einfach an eine Funktion übergeben können, die einen Wert erwartet, der sich nicht in einem Kontext befindet.Wäre es nicht schön, wenn wir einen Operator zum Komponieren
g1
und so vorstellenf1
, dass wir schreiben können(f1 OPERATOR g1) x
?g1
Gibt einen Wert in einem Kontext zurück. Der Wert wird aus dem Kontext genommen und auf angewendetf1
. Und ja, wir haben einen solchen Operator. Es ist<=<
.Wir haben auch den
>>=
Operator, der genau dasselbe für uns tut, allerdings in einer etwas anderen Syntax.Wir schreiben :
g1 x >>= f1
.g1 x
ist einMaybe Int
Wert. Der>>=
Operator hilft dabei, diesenInt
Wert aus dem Kontext "Vielleicht nicht da" zu entfernen und auf ihn anzuwendenf1
. Das Ergebnis vonf1
, das a istMaybe Bool
, ist das Ergebnis der gesamten>>=
Operation.Und schließlich, warum ist
Monad
nützlich? DennMonad
die Typklasse, die den>>=
Operator definiert , entspricht weitgehend derEq
Typklasse, die die Operatoren==
und definiert/=
.Zusammenfassend
Monad
definiert die Typklasse den>>=
Operator, mit dem wir Werte in einem Kontext (wir nennen diese monadischen Werte) an Funktionen übergeben können, die keine Werte in einem Kontext erwarten. Der Kontext wird gepflegt.Wenn es hier eine Sache gibt, an die man sich erinnern sollte, ist es, dass man
Monad
die Funktionszusammensetzung zulässt, die Werte in Kontexten beinhaltet .quelle
tl; dr
Prolog
Der Anwendungsoperator
$
von Funktionenist kanonisch definiert
in Bezug auf die Anwendung der Haskell-primitiven Funktion
f x
(infixl 10
).Die Zusammensetzung
.
wird definiert$
alsund erfüllt die Äquivalenzen
forall f g h.
.
ist assoziativ undid
ist seine rechte und linke Identität.Das Kleisli Triple
Bei der Programmierung ist eine Monade ein Konstruktor vom Typ Funktor mit einer Instanz der Klasse vom Typ Monade. Es gibt mehrere äquivalente Varianten der Definition und Implementierung, die jeweils leicht unterschiedliche Intuitionen über die Monadenabstraktion enthalten.
Ein Funktor ist ein
f
Typkonstruktor* -> *
mit einer Instanz der Funktortypklasse.Zusätzlich zum Befolgen des statisch erzwungenen Typprotokolls müssen Instanzen der Funktortypklasse den algebraischen Funktorgesetzen entsprechen
forall f g.
Functor Berechnungen haben den Typ
Eine Berechnung
c r
besteht aus Ergebnissenr
im Kontextc
.Unäre monadische Funktionen oder Kleisli-Pfeile haben den Typ
Kleisi-Pfeile sind Funktionen, die ein Argument annehmen
a
und eine monadische Berechnung zurückgebenm b
.Monaden werden kanonisch im Sinne des Kleisli-Tripels definiert
forall m. Functor m =>
implementiert als Typklasse
Die Kleisli-Identität
return
ist ein Kleisli-Pfeil, der einen Wertt
in einen monadischen Kontext fördertm
. Die Erweiterung oder Kleisli-Anwendung=<<
wendet einen Kleisli-Pfeila -> m b
auf die Ergebnisse einer Berechnung anm a
.Die Kleisli-Komposition
<=<
wird in Bezug auf die Erweiterung definiert als<=<
setzt zwei Kleisli-Pfeile zusammen und wendet den linken Pfeil auf die Ergebnisse der Anwendung des rechten Pfeils an.Instanzen der Monadentypklasse müssen den Monadengesetzen entsprechen , die in Bezug auf die Kleisli-Zusammensetzung am elegantesten angegeben sind:
forall f g h.
<=<
ist assoziativ undreturn
ist seine rechte und linke Identität.Identität
Der Identitätstyp
ist die Identitätsfunktion für Typen
Als Funktor interpretiert,
Im kanonischen Haskell wird die Identitätsmonade definiert
Möglichkeit
Ein Optionstyp
codiert Berechnungen
Maybe t
, die nicht unbedingt zu einem Ergebnis führent
, Berechnungen, die möglicherweise „fehlschlagen“. Die Option Monade ist definierta -> Maybe b
wird nur dann auf ein Ergebnis angewendet, wennMaybe a
ein Ergebnis erhalten wird.Die natürlichen Zahlen können als ganze Zahlen größer oder gleich Null codiert werden.
Die natürlichen Zahlen werden bei Subtraktion nicht geschlossen.
Die Option Monade deckt eine Grundform der Ausnahmebehandlung ab.
Liste
Die Listenmonade über dem Listentyp
und seine additive Monoidoperation "anhängen"
codiert nichtlineare Berechnungen,
[t]
die eine natürliche Menge0, 1, ...
an Ergebnissen liefernt
.Die Erweiterung
=<<
verkettet++
alle Listen,[b]
die sich aus der Anwendungf x
eines Kleisli-Pfeils ergeben,a -> [b]
zu Elementen[a]
einer einzigen Ergebnisliste[b]
.Die richtigen Teiler einer positiven ganzen Zahl
n
seiendann
Bei der Definition der Monadentypklasse verwendet
=<<
der Haskell-Standard anstelle der Erweiterung seinen Flip, den Bind- Operator>>=
.In dieser Erklärung wird der Einfachheit halber die Typklassenhierarchie verwendet
In Haskell ist die aktuelle Standardhierarchie
denn nicht nur jede Monade ist ein Funktor, sondern jede Anwendung ist eine Funktion und jede Monade ist auch eine Anwendung.
Unter Verwendung der Listenmonade wird der imperative Pseudocode verwendet
grob übersetzt in den do-Block ,
das äquivalente Monadenverständnis ,
und der Ausdruck
Notation und Monadenverständnis sind syntaktischer Zucker für verschachtelte Bindungsausdrücke. Der Bindungsoperator wird für die lokale Namensbindung von monadischen Ergebnissen verwendet.
wo
Die Schutzfunktion ist definiert
wo der Einheitentyp oder "leeres Tupel"
Additive Monaden , die Auswahl und Misserfolg unterstützen, können mithilfe einer Typklasse abstrahiert werden
wo
fail
und<|>
bilden ein Monoidforall k l m.
und
fail
ist das absorbierende / vernichtende Nullelement von additiven MonadenWenn in
even p
ist wahr, dann erzeugt der Wächter[()]
und nach der Definition>>
der lokalen konstanten Funktionwird auf das Ergebnis angewendet
()
. Wenn false, erzeugt der Wächter die Liste monad'sfail
([]
), die kein Ergebnis für die Anwendung eines Kleisli-Pfeils ergibt>>
, sodass dieserp
übersprungen wird.Zustand
Monaden werden bekanntlich verwendet, um zustandsbehaftete Berechnungen zu codieren.
Ein Zustandsprozessor ist eine Funktion
das übergeht einen Zustand
st
und ergibt ein Ergebnist
. Der Staatst
kann alles sein. Nichts, Flagge, Anzahl, Array, Handle, Maschine, Welt.Der Typ der Statusprozessoren wird normalerweise aufgerufen
Die State Processor Monad ist der freundliche
* -> *
FunktorState st
. Kleisli-Pfeile der State-Processor-Monade sind FunktionenIm kanonischen Haskell ist die Lazy-Version der State Processor-Monade definiert
Ein Statusprozessor wird ausgeführt, indem ein Anfangszustand bereitgestellt wird:
Der staatliche Zugang wird durch Primitive
get
undput
Abstraktionsmethoden über staatsmässige Monaden ermöglicht:m -> st
deklariert eine funktionale Abhängigkeit des Zustandstypsst
von der Monadem
; dass aState t
zum Beispiel den Zustandstyp alst
eindeutig bestimmt.mit dem Einheitentyp analog zu
void
in C.gets
wird häufig mit Datensatzfeld-Accessoren verwendet.Das Zustandsmonadenäquivalent des variablen Threadings
wo
s0 :: Int
ist das gleichermaßen referenziell transparent, aber unendlich eleganter und praktischermodify (+ 1)
ist eine Berechnung des TypsState Int ()
, mit Ausnahme des Effekts, der äquivalent zu istreturn ()
.Das Monadengesetz der Assoziativität kann in Bezug auf geschrieben werden
>>=
forall m f g.
oder
Wie bei der ausdrucksorientierten Programmierung (z. B. Rust) repräsentiert die letzte Anweisung eines Blocks seine Ausbeute. Der Bindungsoperator wird manchmal als "programmierbares Semikolon" bezeichnet.
Iterationskontrollstrukturprimitive aus der strukturierten imperativen Programmierung werden monadisch emuliert
Input-Output
Die Monade des I / O-Weltzustandsprozessors ist eine Versöhnung von reinem Haskell und der realen Welt, von funktionaler denotativer und zwingender operativer Semantik. Ein enges Analogon zur tatsächlichen strengen Umsetzung:
Die Interaktion wird durch unreine Grundelemente erleichtert
Die Verunreinigung von Code, der
IO
Grundelemente verwendet, wird vom Typsystem permanent protokolliert. Weil Reinheit fantastisch istIO
, bleibt das , was passiert , drinIO
.Oder sollte es zumindest.
Die Typensignatur eines Haskell-Programms
erweitert sich auf
Eine Funktion, die eine Welt verändert.
Epilog
Die Kategorie, deren Objekte Haskell-Typen sind und deren Morphismen Funktionen zwischen Haskell-Typen sind, ist die Kategorie „schnell und locker“
Hask
.Ein Funktor
T
ist eine Zuordnung von einer KategorieC
zu einer KategorieD
. für jedes Objekt inC
einem Objekt inD
und für jeden Morphismus in
C
einem Morphismus inD
wo
X
,Y
sind Objekte inC
.HomC(X, Y)
ist die Homomorphismusklasse aller MorphismenX -> Y
inC
. Der Funktor muss die Identität und Zusammensetzung des Morphismus bewahren, die „Struktur“ vonC
, inD
.Die Kleisli-Kategorie einer Kategorie
C
wird durch ein Kleisli-Tripel angegebeneines Endofunktors
(
f
), ein Identitätsmorphismuseta
(return
) und ein Erweiterungsoperator*
(=<<
).Jeder Kleisli-Morphismus in
Hask
vom Nebenstellenbetreiber
erhält einen Morphismus in
Hask
der Kategorie KleisliDie Zusammensetzung in der Kategorie Kleisli
.T
wird in Bezug auf die Erweiterung angegebenund erfüllt die Kategorie Axiome
welche unter Anwendung der Äquivalenztransformationen
in Bezug auf die Erweiterung sind kanonisch gegeben
Monaden können auch nicht als Kleislsche Erweiterung, sondern als natürliche Transformation
mu
in der Programmierung bezeichnet werdenjoin
. Eine Monade wirdmu
als Triple über einer KategorieC
eines Endofunktors definiertund zwei natürliche Transformationen
Befriedigung der Äquivalenzen
Die Monadentypklasse wird dann definiert
Die kanonische
mu
Implementierung der Option Monade:Die
concat
Funktionist die
join
der Liste Monade.Implementierungen von
join
können mithilfe der Äquivalenz aus dem Erweiterungsformular übersetzt werdenDie umgekehrte Übersetzung von
mu
zum Erweiterungsformular ist gegeben durchPhilip Wadler: Monaden für die funktionale Programmierung
Simon L. Peyton Jones, Philip Wadler: Imperative funktionale Programmierung
Jonathan MD Hill, Keith Clarke: Eine Einführung in die Kategorientheorie, Kategorientheorie Monaden, und ihre Beziehung zu der funktionalen Programmierung "
Kleisli Kategorie
Eugenio Moggi: Vorstellungen von Berechnung und Monaden
Was für eine Monade ist das nicht
von der Verallgemeinerung von Monaden zu Pfeilen von John Hughes
quelle
Was die Welt braucht, ist ein weiterer Monaden-Blog-Beitrag, aber ich denke, dies ist nützlich, um vorhandene Monaden in freier Wildbahn zu identifizieren.
quelle
http://code.google.com/p/monad-tutorial/ ist in Arbeit, um genau diese Frage zu beantworten.
quelle
Lassen Sie das folgende "
{| a |m}
" einige monadische Daten darstellen. Ein Datentyp, der Folgendes ankündigta
:Funktion
f
,, weiß, wie man eine Monade erstellt, wenn sie nur einea
:Hier sehen wir Funktion,
f
versucht eine Monade zu bewerten, wird aber zurechtgewiesen.Funktion
f
findet einen Weg, dasa
mit zu extrahieren>>=
.Wenig
f
weiß, die Monade und>>=
sind in Absprache.Aber worüber reden sie eigentlich? Nun, das hängt von der Monade ab. Nur abstrakt zu sprechen hat nur begrenzten Nutzen. Sie müssen einige Erfahrungen mit bestimmten Monaden haben, um das Verständnis zu konkretisieren.
Zum Beispiel der Datentyp Vielleicht
hat eine Monadeninstanz, die sich wie folgt verhält ...
Worin, wenn der Fall ist
Just a
Aber für den Fall von
Nothing
Die Vielleicht-Monade lässt eine Berechnung also fortgesetzt werden, wenn sie tatsächlich die von
a
ihr angekündigten enthält , bricht die Berechnung jedoch ab, wenn dies nicht der Fall ist. Das Ergebnis ist jedoch immer noch ein Stück monadischer Daten, jedoch nicht die Ausgabe vonf
. Aus diesem Grund wird die Vielleicht-Monade verwendet, um den Kontext des Scheiterns darzustellen.Verschiedene Monaden verhalten sich unterschiedlich. Listen sind andere Datentypen mit monadischen Instanzen. Sie verhalten sich wie folgt:
In diesem Fall wusste die Funktion, wie eine Liste aus ihrer Eingabe erstellt wird, wusste jedoch nicht, was mit zusätzlichen Eingaben und zusätzlichen Listen zu tun ist. Die bind
>>=
halff
durch Kombinieren der mehrere Ausgänge aus. Ich füge dieses Beispiel hinzu, um zu zeigen, dass es zwar>>=
für das Extrahieren verantwortlich ista
, aber auch Zugriff auf die eventuell gebundene Ausgabe von hatf
. In der Tat wird es niemals etwas extrahieren, esa
sei denn, es weiß, dass die endgültige Ausgabe denselben Kontexttyp hat.Es gibt andere Monaden, die verwendet werden, um unterschiedliche Kontexte darzustellen. Hier sind einige weitere Charakterisierungen. Die
IO
Monade hat eigentlich keinea
, aber sie kennt einen Mann und wird dasa
für Sie besorgen . DieState st
Monade hat einen geheimen Vorratst
, den sief
unter dem Tisch weitergeben wird, obwohl sief
gerade nach einem gefragt hata
. DieReader r
Monade ähneltState st
, obwohl sie nur einenf
Blick darauf werfen kannr
.Der Punkt bei all dem ist, dass jede Art von Daten, die sich selbst als Monade deklariert, einen Kontext zum Extrahieren eines Werts aus der Monade deklariert. Der große Gewinn von all dem? Nun, es ist einfach genug, eine Berechnung mit einem Kontext zu formulieren. Es kann jedoch unordentlich werden, wenn mehrere kontextreiche Berechnungen aneinandergereiht werden. Die Monadenoperationen sorgen dafür, dass die Interaktionen des Kontexts aufgelöst werden, damit der Programmierer dies nicht muss.
Beachten Sie, dass die Verwendung von die
>>=
ein Durcheinander erleichtert, indem ein Teil der Autonomie weggenommen wirdf
. Das heißt, im obigen Fall vonNothing
zum Beispiel kannf
nicht mehr entschieden werden, was im Fall von zu tun istNothing
; es ist in verschlüsselt>>=
. Dies ist der Kompromiss. Wenn es notwendig warf
zu entscheiden, was im Fall von zu tun istNothing
, dannf
sollte eine Funktion vonMaybe a
bis gewesen seinMaybe b
. In diesem FallMaybe
ist es irrelevant, eine Monade zu sein.Beachten Sie jedoch, dass ein Datentyp manchmal seine Konstruktoren nicht exportiert (siehe E / A), und wenn wir mit dem angekündigten Wert arbeiten möchten, haben wir keine andere Wahl, als mit seiner monadischen Schnittstelle zu arbeiten.
quelle
Eine Monade wird verwendet, um Objekte mit sich änderndem Status zu kapseln. Es tritt am häufigsten in Sprachen auf, in denen Sie sonst keinen veränderbaren Status haben (z. B. Haskell).
Ein Beispiel wäre für Datei-E / A.
Sie können eine Monade für Datei-E / A verwenden, um die sich ändernde Statusnatur nur auf den Code zu isolieren, der die Monade verwendet hat. Der Code innerhalb der Monade kann den sich ändernden Zustand der Welt außerhalb der Monade effektiv ignorieren - dies macht es viel einfacher, über die Gesamtwirkung Ihres Programms nachzudenken.
quelle