Ich denke, Ihre Verwirrung entsteht durch die Verwendung von Funktionen, die zu einfach sind. Insbesondere schreiben Sie
const inc = x => x + 1;
, deren Typ eine Funktion, die Werte in der gleichen Raum als seine Eingabe zurückgibt. Nehmen wir an, inc
beschäftigt sich mit ganzen Zahlen. Da sowohl seine Ein- und Ausgangs ganze Zahlen sind, wenn Sie eine andere Funktion foo
haben, die ganze Zahlen nimmt, ist es einfach, mit dem Ausgang von inc
als Eingang-foo
vorzustellen.
Die reale Welt enthält jedoch aufregendere Funktionen. Betrachten Sie die Funktion tree_of_depth
, die eine ganze Zahl annimmt und einen Baum mit Strings dieser Tiefe erstellt. (Ich werde nicht versuchen, es zu implementieren, weil ich nicht genug JavaScript, um eine überzeugende Arbeit davon zu tun.) Jetzt plötzlich ist es schwieriger, die Ausgabe von tree_of_depth
als eine Eingabe an foo
übergeben, da foo
ist erwartet ganze Zahlen und tree_of_depth
produziert Bäume, richtig? Das einzige, was wir an foo
weiterleiten können, ist der Eingang zu tree_of_depth
, denn das ist die einzige ganze Zahl, die wir herumliegen haben, selbst nach dem Lauf tree_of_depth
.
Mal sehen, wie das in der Art Signatur Haskell manifestiert für bind:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
Diese besagt, dass (>>=)
zwei Argumente übernimmt, die jeweils Funktionen. Die erste Funktion kann einen beliebigen alten Typ haben - sie kann einen Wert vom Typ r
annehmen und einen Wert vom Typ a
erzeugen. Insbesondere müssen Sie nicht versprechen, dass r
und a
die gleichen sind.Aber sobald Sie seinen Typ auswählen, ist der Typ des nächsten Funktionsarguments auf (>>=)
beschränkt: Es muss eine Funktion von zwei Argumenten sein, deren Typen die gleichenr
und a
wie zuvor sind.
Jetzt können Sie sehen, warum wir den gleichen Wert vom Typ r
auf diese beiden Funktionen übergeben haben: die erste Funktion erzeugt ein a
, nicht eine aktualisierte r
, so haben wir keinen anderen Wert vom Typ r
an die weitergeben zweite Funktion! Anders als bei Ihrer Situation mit inc
, wo die erste Funktion auch und r
passiert, produzieren wir möglicherweise einen anderen sehr unterschiedlichen Typ.
Dies erklärt, warum Bindung muss so implementiert werden, wie es ist, aber vielleicht nicht erklären, warum diese Monade eine nützliche ist. An anderer Stelle wird darüber geschrieben. Der kanonische Anwendungsfall ist jedoch für Konfigurationsvariablen. Angenommen, Sie starten beim Programmstart eine Konfigurationsdatei; Für den Rest des Programms möchten Sie das Verhalten verschiedener Funktionen beeinflussen können, indem Sie Informationen aus dieser Konfiguration betrachten. In jedem Fall ist es sinnvoll, die gleichen Konfigurationsinformationen zu verwenden - sie müssen nicht geändert werden. Dann wird diese Monade nützlich: Sie können einen impliziten Konfigurationswert haben, und die Bindeoperation der Monade stellt sicher, dass die beiden Funktionen, die Sie sequenzieren, beide Zugriff auf diese Informationen haben, ohne sie manuell an beide Funktionen übergeben zu müssen.
P.S. Sie sagen
Es ist umso überraschender, dass die monadische Funktion das Ergebnis der vorherigen Berechnung nicht dem folgenden liefert.
, die ich etwas ungenau finden: in der Tat in m >>= f
die Funktion f
sowohl das Ergebnis m
(als erstes Argument) und der ursprüngliche Wert (als zweites Argument) erhält.
Die Faustregel lautet: 'bind (...) (x => ...)' nimmt den Wert der vorherigen Berechnung und bindet ihn an 'x'. Andere lambdas 'x => ...' (nicht nach einer Bindung) greifen stattdessen auf dasselbe implizite Nur-Lese-Argument zu, das am Anfang an 'f' übergeben wird. – chi
Randnotiz: 'x => x <= 5 ? x => x * 2: x => x * 3' ist nicht lesbar, bitte verwenden Sie z. 'x => x <= 5 ? y => y * 2: z => z * 3' - ein Computer interessiert sich nicht für Alpha-Äquivalenz, aber Menschen tun ;-) – chi
Weil es * muss * - diese Funktion ist die einzig gültige Umsetzung von eine Funktion, deren Typ 'forall rab ist. (r -> a) -> (a -> (r -> b)) -> r -> b '(außer undefiniert, natürlich). Die JavaScript-Funktion kann natürlich tun, was auch immer sie in der Abwesenheit von formalen Typen mag, aber dann wäre das Nachdenken darüber viel schwieriger (und nannte es "bind" wäre einfach falsch) – user2407038