Ich komme aus einem C # -Hintergrund, in dem sich LINQ zu Rx.NET entwickelt hat, hatte aber immer ein gewisses Interesse an FP. Nach einer Einführung in Monaden und einigen Nebenprojekten in F # war ich bereit zu versuchen, die nächste Stufe zu erreichen.
Nach mehreren Gesprächen über die freie Monade von Leuten aus Scala und mehreren Zuschreibungen in Haskell oder F # habe ich Grammatiken mit eingeschalteten Dolmetschern gefunden, damit das Verständnis IObservable
Ketten ziemlich ähnlich ist.
In FRP erstellen Sie eine Operationsdefinition aus kleineren domänenspezifischen Abschnitten, einschließlich Nebenwirkungen und Fehlern, die in der Kette verbleiben, und modellieren Ihre Anwendung als eine Reihe von Operationen und Nebenwirkungen. In der freien Monade tun Sie, wenn ich es richtig verstanden habe, dasselbe, indem Sie Ihre Operationen als Funktoren ausführen und sie mit coyoneda anheben.
Was wären die Unterschiede zwischen beiden, die die Nadel in Richtung eines der Ansätze neigen? Was ist der grundlegende Unterschied bei der Definition Ihres Dienstes oder Programms?
quelle
Cont
die einzige Monade ist, die ich gesehen habe und die nicht über die freie Monade ausgedrückt werden kann, kann man wahrscheinlich davon ausgehen, dass es sich um eine FRP handelt. Da kann fast alles andere .IObservable
ist eine Instanz der Fortsetzung Monade.Antworten:
Monaden
Eine Monade besteht aus
Ein Endofunktor . In unserer Welt der Softwareentwicklung können wir sagen, dass dies einem Datentyp mit einem einzigen, uneingeschränkten Typparameter entspricht. In C # wäre dies etwa so:
Zwei über diesen Datentyp definierte Operationen:
return
Ichpure
nehme einen "reinen" Wert (dh einenT
Wert) und "hülle" ihn in die Monade (dh es wird einM<T>
Wert erzeugt ). Dareturn
es sich bei C # um ein reserviertes Schlüsselwort handelt, werde ichpure
von nun an auf diesen Vorgang verweisen. In C #pure
wäre eine Methode mit einer Signatur wie:bind
/flatmap
nimmt einen monadischen Wert (M<A>
) und eine Funktion anf
.f
Nimmt einen reinen Wert und gibt einen monadischen Wert zurück (M<B>
). Darausbind
ergibt einen neuen monadischen Wert (M<B>
).bind
hat die folgende C # Signatur:Auch, um eine Monade zu sein,
pure
undbind
müssen die drei Monadengesetze befolgen.Eine Möglichkeit, Monaden in C # zu modellieren, besteht darin, eine Schnittstelle zu erstellen:
(Hinweis: Um die Dinge kurz und aussagekräftig zu halten, nehme ich mir in dieser Antwort einige Freiheiten mit dem Code.)
Jetzt können wir Monaden für konkrete Datentypen implementieren, indem wir konkrete Implementierungen von implementieren
Monad<M>
. Beispielsweise könnten wir die folgende Monade implementieren fürIEnumerable
:(Ich verwende die LINQ-Syntax absichtlich, um die Beziehung zwischen LINQ-Syntax und Monaden herauszufinden. Beachten Sie jedoch, dass wir die LINQ-Abfrage durch einen Aufruf von ersetzen können
SelectMany
.)Können wir nun eine Monade definieren für
IObservable
? Es scheint so:Um sicherzugehen, dass wir eine Monade haben, müssen wir die Monadengesetze beweisen. Dies kann nicht trivial sein (und ich kenne Rx.NET nicht gut genug, um zu wissen, ob sie auch nur anhand der Spezifikation bewiesen werden können), aber es ist ein vielversprechender Anfang. Um den Rest dieser Diskussion zu vereinfachen, nehmen wir einfach die in diesem Fall geltenden Monadengesetze an.
Freie Monaden
Es gibt keine singuläre "freie Monade". Freie Monaden sind vielmehr eine Klasse von Monaden, die aus Funktoren aufgebaut sind. Das heißt, wenn ein Funktor gegeben ist
F
, können wir automatisch eine Monade fürF
(dh die freie Monade vonF
) ableiten .Functors
Wie Monaden können Funktoren durch die folgenden drei Elemente definiert werden:
Zwei Operationen:
pure
Wickelt einen reinen Wert in den Funktor. Dies ist analog zupure
einer Monade. Tatsächlich sollten für Funktoren, die auch Monaden sind, die beiden identisch sein.fmap
Ordnet Werte in der Eingabe über eine bestimmte Funktion neuen Werten in der Ausgabe zu. Ihre Unterschrift lautet:Wie Monaden müssen auch Funktoren die Funktorgesetze einhalten.
Ähnlich wie bei Monaden können wir Funktoren über die folgende Schnittstelle modellieren:
Nun, da Monaden eine Unterklasse von Funktoren sind, können wir auch
Monad
ein wenig überarbeiten :Hier habe ich eine zusätzliche Methode hinzugefügt
join
und Standardimplementierungen von beidenjoin
und bereitgestelltbind
. Beachten Sie jedoch, dass dies zirkuläre Definitionen sind. Sie müssten also mindestens das eine oder andere außer Kraft setzen. Beachten Sie außerdem, dasspure
jetzt von geerbt wirdFunctor
.IObservable
und freie MonadenDa wir nun eine Monade für definiert haben
IObservable
und Monaden eine Unterklasse von Funktoren sind, müssen wir in der Lage sein, eine Funktorinstanz für zu definierenIObservable
. Hier ist eine Definition:Jetzt, da wir einen Funktor definiert haben
IObservable
, können wir aus diesem Funktor eine freie Monade konstruieren. Und genau soIObservable
verhält es sich mit freien Monaden - nämlich, aus denen wir eine freie Monade konstruieren könnenIObservable
.quelle