2015-09-01 1 views
11

join wird zusammen mit bind definiert, um die kombinierte Datenstruktur in eine einzelne Struktur zu reduzieren.Gibt es irgendeine Intuition, um zwei Funktionen in Monad zu verbinden?

Vom Typ Systemansicht, (+) 7 :: Num a => a -> a als Functor in Betracht gezogen werden könnte, (+) :: Num a => a -> a -> a als Functor von Functor in Betracht gezogen werden könnte, wie eine Intuition es auf Typ-System nur unter Berufung statt zu bekommen? Warum join (+) 7 === 14?

Obwohl es möglich ist, das Endergebnis durch manuelles Steigen durch den Funktionsbindungsvorgang zu erhalten, wäre es großartig, wenn eine Intuition gegeben wäre.

Dies ist von den NICTA Übungen.

-- | Binds a function on the reader ((->) t). 
-- 
-- >>> ((*) =<< (+10)) 7 
-- 119 
instance Bind ((->) t) where 
    (=<<) :: 
    (a -> ((->) t b)) 
    -> ((->) t a) 
    -> ((->) t b) 
    (f =<< a) t = 
    f (a t) t 

-- | Flattens a combined structure to a single structure. 
-- 
-- >>> join (+) 7 
-- 14 
join :: 
    Bind f => 
    f (f a) 
    -> f a 
join f = 
    id =<< f 

*Course.State> :t join (+) 
join (+) :: Num a => a -> a 
*Course.State> :t join 
join :: Bind f => f (f a) -> f a 
*Course.State> :t (+) 
(+) :: Num a => a -> a -> a 
+7

"' (+) 7 :: Num a => a -> a 'könnte als 'Functor' betrachtet werden ... bitte sag sowas nicht. '(7+)' ist kein Funktor, es ist, als würde man sagen, ein Kohlenstoffatom sei ein Diamant. Der Funktor ist '(Int ->)', d. H. Der Typkonstruktor, der Typen akzeptiert und Funktionen von Zahlen zu diesem Typ erzeugt. – leftaroundabout

+0

Für Funktionen, 'Join f = \ a -> f a a'. Also 'verbinden (+) = \ a -> a + a'. – AJFarmar

+0

@leftaroundabout Ist nicht '(+) 7 :: Num a => a -> a' ein Funktor in der Kategorie 'Num'? – Kamel

Antwort

9

Wie bekommt man etwas Intuition, anstatt sich nur auf das Typsystem zu verlassen?

Ich würde eher sagen, dass das Vertrauen auf das Typsystem eine gute Möglichkeit ist, eine bestimmte Art von Intuition zu bauen.Die Art der join ist:

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

Specialized zu (->) r, wird es:

(r -> (r -> a)) -> (r -> a) 

Nun wollen wir versuchen join für Funktionen zu definieren:

-- join :: (r -> (r -> a)) -> (r -> a) 
join f = -- etc. 

kennen wir das Ergebnis sein, muss r -> a Funktion:

join f = \x -> -- etc. 

Allerdings wissen wir überhaupt nichts darüber, was die r und a Typen sind, und deshalb wissen wir nichts besonderes über f :: r -> (r -> a) und x :: r. Unsere Unwissenheit bedeutet, dass es buchstäblich nur eine Sache, die wir mit ihnen tun können: passing x als Argument, die beide zu f und f x:

join f = \x -> f x x 

Daher join für Funktionen übergibt das gleiche Argument zweimal, weil das der einzige ist mögliche Umsetzung. Natürlich ist, dass die Umsetzung nur eine richtige monadischen join, weil sie die Gesetze Monade folgt:

join . fmap join = join . join 
join . fmap return = id 
join . return = id 

dass Überprüfen der ebenfalls eine sehr schöne Übung sein könnte.

7

zusammen mit der traditionellen Analogie eines monadisch als Kontext für die Berechnung geht, sind join Verfahren Kontexte zu kombinieren. Beginnen wir mit Ihrem Beispiel. join (+) 7. Die Verwendung einer Funktion als Monade impliziert die Leser-Monade. (+ 1) ist eine Leser-Monade, die die Umgebung aufnimmt und ihr eine hinzufügt. Somit wäre (+) eine Leser-Monade innerhalb einer Leser-Monade. Die äußere Leser-Monade nimmt die Umgebung n und gibt einen Leser des Formulars (n +) zurück, der eine neue Umgebung einnehmen wird. join kombiniert einfach die zwei Umgebungen, so dass Sie es einmal bereitstellen und den angegebenen Parameter zweimal anwendet. join (+) === \x -> (+) x x.

Nun, mehr im Allgemeinen, schauen wir uns einige andere Beispiele an. Die Maybe Monade repräsentiert einen möglichen Fehler. Ein Wert von Nothing ist eine fehlgeschlagene Berechnung, während ein Just x ein Erfolg ist. Eine Maybe innerhalb einer Maybe ist eine Berechnung, die zweimal fehlschlagen könnte. Ein Wert von Just (Just x) ist offensichtlich ein Erfolg, so dass Beitritt, produziert Just x. Ein Nothing oder ein Just Nothing zeigt einen Fehler an einem Punkt an, so dass das Verbinden des möglichen Fehlers anzeigen sollte, dass die Berechnung fehlgeschlagen ist, d. H. Nothing.

Eine ähnliche Analogie kann für die Liste Monade gemacht werden, für die join lediglich concat, der Schriftsteller Monade ist, der die monoidal Operator verwendet <> die Ausgangswerte in Frage, oder jede andere Monade zu kombinieren.

join ist eine fundamentale Eigenschaft von Monaden und ist die Operation, die es deutlich stärker macht als ein Funktor oder ein Anwendungsfunktor. Funktoren können überlagert werden, Anwendungen können Sequenzen sein, Monaden können kombiniert werden. Kategorisch wird eine Monade oft als join und return definiert. Es passiert einfach, dass es in Haskell praktischer ist, es in Bezug auf return, (>>=) und fmap zu definieren, aber die beiden Definitionen wurden synonym bewiesen.

+0

Wie ist '+ 1' eine Leser-Monade? meinst du das irgendwie konzeptuell oder auch auf der type level? –

+0

'(+ 1)' ist eine Funktion, die ein Argument übernimmt und eins hinzufügt. Konzeptionell kann es als ein Wert angesehen werden, der von einem schreibgeschützten Wert abhängt, den er noch nicht kennt. '(+ 1)' kann als eine ganze Zahl betrachtet werden, die wir erst untersuchen können, wenn wir ihr die "Umgebung" geben. –

+0

so ist es nur eine begriffliche Analogie, nicht eine Typ-Level-Tatsache. –

2

Eine Intuition über join ist, dass Kürbisse 2 Container in eins sind. .e.g

join [[1]] => [1] 
join (Just (Just 1)) => 1 
join (a christmas tree decorated with small cristmas tree) => a cristmas tree 

etc ...

Nun, wie können Sie Funktionen beitreten? In der Tat Funktionen, kann als ein Container gesehen werden. Wenn Sie zum Beispiel eine Hash-Tabelle betrachten. Du gibst einen Schlüssel und du bekommst einen Wert (oder nicht). Es ist eine Funktion key -> value (oder wenn Sie key -> Maybe value bevorzugen). Also, wie würdest du 2 HashMap beitreten?

Sagen wir, ich habe (im Python-Stil) h={"a": {"a": 1, "b": 2}, "b" : {"a" : 10, "b" : 20 }} Wie kann ich es beitreten, oder wenn Sie es lieber abflachen? Gegeben "a" Welchen Wert sollte ich bekommen? h["a"] gibt mir {"a":1, "b":2}. Das einzige, was ich damit machen kann, ist, in diesem neuen Wert wieder "a" zu finden, was mir 1 gibt. Daher join h entspricht {"a":1, "b":20}.

Es ist das gleiche für eine Funktion.

Verwandte Themen