In meiner bescheidenen Meinung versuchen die Antworten auf die berühmte Frage "Was ist ein Monoid?", insbesondere die am meisten bewerteten, zu erklären, was ein Monoid ist, ohne klar zu erklären, warum Monaden wirklich notwendig sind. Können sie als Lösung für ein Problem erklärt werden?
Antworten
Zu viele Anzeigen?Sie benötigen Monaden, wenn Sie einen Typkonstruktor und Funktionen haben, die Werte dieser Typfamilie zurückgeben. Schließlich möchten Sie diese Art von Funktionen kombinieren. Dies sind die drei Schlüsselelemente, um warum zu beantworten.
Lassen Sie mich näher darauf eingehen. Sie haben Int
, String
und Real
und Funktionen vom Typ Int -> String
, String -> Real
und so weiter. Sie können diese Funktionen leicht kombinieren und landen bei Int -> Real
. Das Leben ist gut.
Dann, eines Tages, müssen Sie eine neue Familie von Typen erstellen. Es könnte sein, weil Sie die Möglichkeit in Betracht ziehen müssen, keinen Wert zurückzugeben (Maybe
), einen Fehler zurückzugeben (Either
), mehrere Ergebnisse zurückzugeben (List
) und so weiter.
Beachten Sie, dass Maybe
ein Typkonstruktor ist. Er nimmt einen Typ wie Int
und gibt einen neuen Typ Maybe Int
zurück. Erste Sache zu merken: kein Typkonstruktor, keine Monad.
Natürlich möchten Sie Ihren Typkonstruktor verwenden in Ihrem Code, und bald enden Sie mit Funktionen wie Int -> Maybe String
und String -> Maybe Float
. Jetzt können Sie Ihre Funktionen nicht mehr einfach kombinieren. Das Leben ist nicht mehr gut.
Und hier kommen die Monaden zur Rettung. Sie ermöglichen es Ihnen, diese Art von Funktionen wieder zu kombinieren. Sie müssen nur die Komposition von . in >== ändern.
Monaden sind nur ein praktisches Rahmenwerk zur Lösung einer Klasse wiederkehrender Probleme. Erstens müssen Monaden Funktoren sein (d.h. sie müssen das Abbilden ohne Betrachten der Elemente (oder ihres Typs) unterstützen), sie müssen auch eine Bindung (oder Verkettung) und eine Möglichkeit zum Erstellen eines monadischen Werts aus einem Elementtyp bringen ( return
). Schließlich müssen bind
und return
zwei Gleichungen erfüllen (linke und rechte Identitäten), die auch als Monadengesetze bezeichnet werden. (Alternativ könnte man Monaden definieren, um eine Aplattierungsoperation
anstelle von Bindung zu haben.)
Der Listen-Monad wird häufig zur Behandlung von Nicht-Determinismus verwendet. Die Bindungsausführung wählt ein Element der Liste aus (intuitiv alle in parallelen Welten), ermöglicht dem Programmierer eine Berechnung mit ihnen durchzuführen und kombiniert dann die Ergebnisse in allen Welten zu einer einzelnen Liste (durch Konkatenieren oder Abflachen einer verschachtelten Liste). Hier ist, wie man eine Permutationsfunktion im monadischen Rahmenwerk von Haskell definieren würde:
perm [e] = [[e]]
perm l = do (führer, index) <- zip l [0 :: Int ..]
lassen Sie verkürzen = nehmen Sie den Index l ++ überspringen Sie (Index + 1) l
trailer <- perm verkürzt
return (Führer : Anhänger)
Hier ist ein Beispiel für eine repl Sitzung:
*Main> perm "a"
["a"]
*Main> perm "ab"
["ab","ba"]
*Main> perm ""
[]
*Main> perm "abc"
["abc","acb","bac","bca","cab","cba"]
Es sei darauf hingewiesen, dass der Listen-Monad in keiner Weise eine Seiteneffektberechnung ist. Eine mathematische Struktur, die eine Monade ist (d.h. den oben genannten Schnittstellen und Gesetzen entspricht), impliziert keine Nebeneffekte, obwohl sich nebenwirkende Phänomene oft gut in das monadische Rahmenwerk einfügen.
- See previous answers
- Weitere Antworten anzeigen