Functoren, applikative Funktoren und Monaden mit TypeScript verstehen
(evan-moon.github.io)Text
- Erklärt anhand von TypeScript-Code den Weg von zwei Problemen, die sich allein mit
mapbei Funktoren nicht lösen lassen (in einem Container eingeschlossene Funktionen und verschachtelte Kontexte bei Komposition), bis hin zu applikativen Funktoren und Monaden - Beginnt mit dem Hintergrund, dass Eugenio Moggi 1988 Programme nicht als
A → B, sondern alsA → T(B)modellierte - Behandelt die Struktur
flatMap = map + joinund die drei Gesetze für ihre sichere Verwendung (Assoziativität, linke Einheit, rechte Einheit) - Erklärt, warum die Monade ein „Monoidobjekt in der Kategorie der Endofunktoren“ ist, im Vergleich zum Monoid der Ganzzahladdition
- Erwähnt auch, warum
Promisezwar monadisch funktioniert, aber keine strenge mathematische Monade ist
Die Grenzen von Funktoren: Was mit map nicht geht
- Wendet man eine gecurryte Funktion mit
mapan, landet das Ergebnis als Funktion im Container, etwaMaybe<(b: number) => number>mapkann nur Funktionen außerhalb des Containers entgegennehmen, daher gibt es keine Möglichkeit, eine darin eingeschlossene Funktion auf einen anderen Wert anzuwenden
- Komponiert man zwei Funktionen, die selbst wieder einen Funktor zurückgeben, verschachtelt sich der Kontext zu etwas wie
Maybe<Maybe>- Mit jedem zusätzlichen Schritt wächst das zu einer unendlichen Verschachtelung wie
Maybe<Maybe<Maybe<...>>>
- Mit jedem zusätzlichen Schritt wächst das zu einer unendlichen Verschachtelung wie
Applikative Funktoren: Funktionen im Container anwenden
- Mit der Operation
applylässt sich eine im Container eingeschlossene Funktion auf den Wert eines anderen Containers anwendenapply: T<(A → B)> → T<A> → T<B>
- Mit der Operation
purewird ein reiner Wert in den Container eingefügt - Grenze: Es muss im Voraus feststehen, welche Container komponiert werden
- Dynamische sequenzielle Abhängigkeiten, bei denen die nächste Berechnung vom Ergebnis der vorherigen abhängt, lassen sich damit nicht ausdrücken
Monaden: Die Erfindung einer Operation zum Entschachteln
- Die Operation
joinfaltet einen doppelten ContainerT<T<A>>zuT<A>zusammenArray.prototype.flatin JavaScript übernimmt dieselbe Rolle
- In der Praxis verwendet man
flatMap, dasmapundjoinkombiniertflatMap: T<A> → (A → T<B>) → T<B>mapnimmtA → Bentgegen,flatMapdagegenA → T<B>und hält das Ergebnis dadurch auf einer Ebene
Die drei Gesetze von flatMap
- Assoziativgesetz: Beim Entschachteln einer dreifachen Verschachtelung
T(T(T(A)))muss das Ergebnis gleich sein, egal ob man zuerst innen oder außen entfaltetm.flatMap(f).flatMap(g) === m.flatMap(x => f(x).flatMap(g))
- Gesetz der linken Einheit: Wenn man einen Wert mit
pureeinfügt und sofortflatMapanwendet, ist das dasselbe wie die Funktion direkt anzuwendenpure(a).flatMap(f) === f(a)
- Gesetz der rechten Einheit: Übergibt man
pureanflatMap, bleibt der ursprüngliche Container unverändertm.flatMap(pure) === m
Zerlegung von „Monoidobjekt in der Kategorie der Endofunktoren“
- Funktoren in der Programmierung gehen von der Typwelt in die Typwelt und sind daher Endofunktoren
- Man kann eine Kategorie der Endofunktoren bilden, in der die Endofunktoren selbst die Objekte sind
- Setzt man darauf die Anforderungen eines Monoids an (binäre Operation + Assoziativgesetz + neutrales Element), ergibt sich:
- binäre Operation =
join - neutrales Element =
pure - Die Struktur entspricht exakt dem Monoid der Ganzzahladdition
- binäre Operation =
Warum Promise keine Monade ist
thenverarbeitet abhängig vom Rückgabewert eine Mischung ausmapundflatMap- Ein Zustand vom Typ
Promise<Promise>ist zur Laufzeit nicht erlaubt und wird sofort zu einer einzigen Ebene zusammengeführt - Das ist in der Praxis bequem, erfüllt aber nicht die mathematischen Monadengesetze
Noch keine Kommentare.