Unterschied in der Fähigkeit zwischen fmap und bind?

8

Ich bin neu in der funktionalen Programmierung (komme von Javascript), und es fällt mir schwer, den Unterschied zwischen den beiden zu erklären, was auch mit meinem Verständnis von Funktoren vs. Monaden zu tun hat.

Funktion:

%Vor%

Monade (vereinfacht):

%Vor%
  • fmap verwendet eine Funktion und einen Funktor und gibt einen Funktor zurück.
  • >>= nimmt eine Funktion und eine Monade und gibt eine Monade zurück.

Der Unterschied zwischen den beiden ist im Funktionsparameter:

  • fmap - (a -> b)
  • >>= - (a -> m b)

>>= verwendet einen Funktionsparameter, der eine Monade zurückgibt. Ich weiß, dass das wichtig ist, aber ich habe Schwierigkeiten zu sehen, wie dieses eine kleine Ding Monaden viel mächtiger macht als Funktoren. Kann jemand erklären?

    
m0meni 14.02.2016, 01:04
quelle

3 Antworten

13

Nun, (<$>) ist ein Alias ​​für fmap und (=<<) ist identisch mit (>>=) mit den vertauschten Argumenten:

%Vor%

Der Unterschied ist jetzt ziemlich klar: Mit der Bindefunktion wenden wir eine Funktion an, die ein b y anstatt eines y zurückgibt. Welchen Unterschied macht das?

Betrachten Sie dieses kleine Beispiel:

%Vor%

Beachten Sie, dass (<$>) foo auf 3 anwendet und das Ergebnis in ein Just zurückversetzt. Mit anderen Worten, das Ergebnis dieser Berechnung kann nicht Nothing sein. Im Gegenteil:

%Vor%

Diese Berechnung kann Nothing zurückgeben. (Zum Beispiel wird bar x = Nothing es tun.)

Wir können eine ähnliche Sache mit der Listenmonade machen:

%Vor%

Kurz gesagt, mit (<$>) (d. h. fmap ) ist die "Struktur" des Ergebnisses immer identisch mit der Eingabe. Aber mit (=<<) (d. H.% Co_de%) kann sich die Struktur des Ergebnisses ändern. Dies ermöglicht die bedingte Ausführung, Reaktion auf Eingabe und eine ganze Reihe anderer Dinge.

    
MathematicalOrchid 14.02.2016, 13:39
quelle
8

Eine kurze Antwort ist, dass wenn Sie m (m a) in m a auf eine Weise umwandeln können, die sinnvoll ist, dann ist es eine Monade. Dies ist für alle Monaden möglich, aber nicht unbedingt für Funktoren.

Ich denke, die verwirrendste Sache ist, dass alle gängigen Beispiele von Funktoren (z. B. List , Maybe , IO ) ebenfalls Monaden sind. Wir brauchen ein Beispiel für etwas, das ein Functor ist, aber kein Monad.

Ich werde ein Beispiel aus einem hypothetischen Kalenderprogramm verwenden. Der folgende Code definiert einen Event Functor, der einige Daten speichert, die zu dem Ereignis und der Zeit gehören, zu der es auftritt.

%Vor%

Das Objekt Event speichert die Uhrzeit, zu der das Ereignis eintritt, und einige zusätzliche Daten, die mit fmap geändert werden können. Versuchen wir nun, es zu einer Monade zu machen:

%Vor%

Wir finden, dass wir das nicht können, weil Sie zwei LocalTime -Objekte haben werden. timeA von der angegebenen Event und timeB von Event , gegeben durch das Ergebnis von f a . Unser Event -Typ ist so definiert, dass er nur ein LocalTime ( time ) hat, an dem er auftritt, und daher ist es nicht möglich, eine Monade zu erstellen, ohne zwei LocalTime s in eins zu verwandeln. (Es kann einen Fall geben, in dem dies Sinn machen könnte und du könntest dies in eine Monade verwandeln, wenn du es wirklich willst).

    
HEGX64 14.02.2016 04:06
quelle
3

Nehmen wir an, dass IO nur ein Functor und nicht Monad sind. Wie könnten wir zwei Aktionen abfolgen? Sagen wir, wie getChar :: IO Char und putChar :: Char -> IO () .

Wir könnten versuchen, über getChar (eine Aktion, die, wenn sie ausgeführt wird, Char von stdin liest) mit putChar zu mappen.

%Vor%

Nun haben wir ein Programm, das, wenn es ausgeführt wird, ein Char von stdin liest und ein Programm erzeugt, das, wenn es ausgeführt wird, Char nach stdout schreibt. Aber was wir eigentlich wollen, ist ein Programm, das, wenn es ausgeführt wird, ein Char von stdin liest und das Char nach stdout schreibt. Also brauchen wir eine Funktion "flattern" (in der IO case, "sequencing") mit type:

%Vor%

Functor selbst bietet diese Funktion nicht. Aber es ist eine Funktion von Monad , wo es den allgemeineren Typ hat:

%Vor%

Was hat das alles mit >>= zu tun? Zufällig ist monadische Bindung nur eine Kombination aus fmap und join :

%Vor%

Eine weitere Möglichkeit, den Unterschied zu sehen, ist, dass fmap niemals die Gesamtstruktur des gemappten Wertes ändert, aber join (und daher auch >>= ) kann das tun.

In IO -Aktionen bewirkt fmap nie zusätzliche Lese- / Schreibvorgänge oder andere Effekte. Aber join sequenziert das Lesen / Schreiben der inneren Aktion nach denen der äußeren Aktion.

    
danidiaz 14.02.2016 10:39
quelle