Welche Programmierprobleme lösen Monaden? [geschlossen]

14

Ich habe eine Menge Posts gelesen, die erklären, was Monaden sind, wie unitund wie sie bindfunktionieren. 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?

Dummy ich
quelle
3
Programme sind groß und komplex. Wir brauchen Wege, sie zu strukturieren. Es gibt viele Wege. Monaden sind eins. Pfeile sind eins. Functors sind eins. Objekte, Klassen, Funktionen, Methoden, Module, Eigenschaften, Mixins, Pakete sind einige andere. Es ist wirklich nicht klar, was Ihre spezifische Frage ist. Fragen Sie sich, warum wir Programme strukturieren müssen?
Jörg W Mittag
1
@ JörgWMittag: Ich frage NICHT, warum wir Programme strukturieren müssen. Offensichtlich wird ein großes Problem in kleinere Probleme aufgeteilt, die Sie lösen und dann kombinieren können, um die Lösung für das große Problem zu erhalten. Ich frage, welche Probleme Monaden lösen. Ist es das? Code strukturieren? Ist das die ganze Aufregung? In Haskell ist dies beispielsweise die Art und Weise, wie Sie E / A-Vorgänge ausführen. Dort ist die Monade ein Stück, das so tut, als wäre es etwas Reines, obwohl es nicht so ist. Meine Frage steht im Titel, ich weiß nicht, wie ich das klarer ausdrücken soll.
Dummy Me
2
Warum Monaden?
Robert Harvey
1
@RobertHarvey: Ich habe auch die ersten beiden Links gefunden, die Sie hinzugefügt haben, aber wie in den Antworten dieser und anderer Posts, gehen die Antworten direkt zu Vielleicht, Status- und E / A-Monaden, springen schnell zu Beispielen oder Code und enden mit "Es gibt viel von Problemen, die mit Monaden gelöst werden können ". Was sind die anderen Probleme? Ich suche nach einer Antwort auf höherer Ebene, die, anstatt dieselben Beispiele zu wiederholen, die eigentlichen Ursachen der Probleme aufzeigt (was auch immer diese sind) und erklärt, wie Monaden sie lösen und warum es die beste Wahl ist, anstatt etwas anderes zu verwenden. Vielen Dank für das Feedback.
Dummy Me

Antworten:

10

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.

Karl Bielefeldt
quelle
2
Ich würde tatsächlich sagen, dass das sichtbarste, was Haskell-Monaden ermöglichen, eine einfache Möglichkeit ist, E / A-Effekte zu erzielen, die tatsächlich so funktionieren, wie Sie es erwarten. Ich denke, jeder, der sich fragt, was Monaden uns geben, sollte Miranda ausprobieren . Miranda ist die Sprache, die Haskell ersetzen soll, und sollte für alle mit Haskell-Erfahrung sehr einfach zu erlernen sein. Der Hauptunterschied besteht darin, dass es kein monadisches IO gibt, was die Arbeit mit der Sprache für nicht-triviale Projekte viel schwieriger macht als mit Haskell.
Jules
Ja, es IOist 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.
Karl Bielefeldt
1
@Jules: Oder schauen Sie sich die Geschichte von Haskell an. Vor Monaden experimentierten die Haskell-Designer mit Lazy Streams und Continuations als Grundlage für E / A, und beide waren schwer zu verwenden.
Jörg W Mittag
5

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.

JacquesB
quelle
2

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 Kontext f, 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 mit fmapoder 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 vonzip :: [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 Applicativeeine Kombination aus Functorund Monoidalund Unit, 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.

Monadist 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 nur pairsie, 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ätten FilePath -> IO (IO a). Wie können wir dieses Stapeln loswerden, um eine ausführbare Funktion zu erhalten IO a? Hier kommt Monads ins joinSpiel, 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.

MarLinn
quelle
1

Mit Monaden können Sie verschiedene nicht reine Berechnungen ausführen und den Code vereinfachen

  • Zustandsberechnung (Zustand über Monade holen / setzen)
  • I / O (Protokollierung, Benutzeroberfläche, Datei oder nur eine Liste von X erstellen / verbrauchen)
  • Auch "nichtlinearer" Kontrollfluss (dh Ausnahmen, vielleicht, etc.)

Und vor allem, ohne Kompromisse mit den reinen Sprachkonstrukten einzugehen und eine sauberere Sprache daraus zu machen

Macke
quelle
2
Stimmt - aber das ist nur ein Teil dessen, wofür Monaden verwendet werden. Listenverständnis oder Maybehaben nichts mit Äußerem zu tun.
JacquesB
Es wäre hilfreich, wenn die Abwähler erklären würden, warum sie dies getan haben. Ich sehe nichts falsch mit dieser Antwort.
Jules
@JacquesB sie sind jedoch zustandsbehaftet.
Jules
1
Mit Welttypen, Eindeutigkeitstypen und linearen Typen können Sie dies jedoch auch tun.
Jörg W. Mittag
@Jules Listen als Nichtdeterminismus-Monade ist stateful? Können Sie klarstellen, was Ihre Definition von "zustandsbehaftet" ist?
Jack