2015-12-21 5 views
6

In Haskell sind Monaden durch die Funktionen return und bind definiert, wobei return den Typ a -> m a und bind den Typ m a -> (a -> m b) -> m b hat. Es wurde vorher darauf hingewiesen, monads can also be defined in terms of return and join, wo Join eine Funktion mit dem Typ m (m a) -> m a ist. Bindung kann in Join definiert werden, aber ist das Umgekehrte möglich? Kann Join in Bezug auf Bindung definiert werden?Mit Monaden kann verbunden werden definiert in Bezug auf binden?

Ohne Join, ich habe keine Ahnung, was ich tun würde, wenn ich jemals einen "zweimal verpackt" monadischen Wert, m (m a) - keine der Funktor oder Monad Operationen "entfernen Sie alle Schichten", sozusagen. Wenn dies nicht möglich ist, warum definieren Haskell und viele andere Monad-Implementierungen sie hinsichtlich der Bindung? Es scheint streng weniger sinnvoll als eine Join-basierte Definition.

+5

Hinweis „auch“: wenn konnte beitreten nicht in Bezug auf die bind definiert werden, wäre es _have_ Mitglied von 'Monad' sein (oder wäre nicht für alle Monaden definiert), und das ist es nicht. –

Antwort

9

Es ist möglich:

join :: Monad m => m (m a) -> m a 
join m = (m >>= id) 

Hinweis der schwierige Instanziierung >>=:

(>>=) :: m b -> (b -> m c) -> m c 
-- choosing b ~ m a , c ~ a 
(>>=) :: m (m a) -> (m a -> m a) -> m a 

so können wir richtig wählen id für die zweite Streit.

6

Ja, es ist ziemlich einfach:

join m = m >>= id 
3

Bind (>>=) in der Tat "entfernen, um eine Schicht":

(>>=) :: Monad m => m a -> (a -> m b) -> m b 

Intuitiv it "bekommt einig a s aus den m a", und führt dann die a -> m b Funktion und erzeugt dann ein einzigen m b aus den Ergebnissen.

Leute sagen normalerweise, dass es das Funktionsargument benötigt, um seine Ausgabe in m wieder einzuschließen, aber das ist nicht wirklich der Fall. Es erfordert die Ausgabe der Funktion zu sein etwas eingewickelt in m, aber es spielt keine Rolle, woher die Verpackung kam.

Im Falle der Implementierung join beginnen wir von etwas "doppelt verpackt": m (m a). Das können wir in die Signatur für bind stecken und sofort die Art der Funktion herauszufinden, die wir verwenden könnten, wenn ein „double-wrapped“ Wert Bindung:

m (m a) -> (m a -> m b) -> m b 

Nun ist die mit bind hier verwendete Funktion wird einen Wert erhalten das ist bereits eingewickelt in m. Wir müssen also nichts "umhüllen". Wenn wir es unverändert zurückgeben, ist es bereits der richtige Typ für die Ausgabe. Effektiv ist das "eine Schicht Verpackung entfernt" - und das funktioniert für jede Ebene außer der letzten.

Damit sagt uns, dass wir nur mit id binden:

join = (>>= id) 
Verwandte Themen