2013-05-06 14 views
6

Ist es sinnvoll, in einem Monad mehrere Methoden flatMap (oder /bind in Haskell) zu definieren? Die wenigen Monaden, die ich tatsächlich verwende (Option, Try, Either Projektionen) definieren nur eine flatMap-Methode.Mehrere FlatMap-Methoden für eine einzelne Monade?

Zum Beispiel könnte es sinnvoll sein, eine flatMap Methode auf Option zu definieren, die eine Funktion nehmen würde, die eine Try erzeugt? So dass Option[Try[User]] zum Beispiel als Option[User] abgeflacht wäre? (Unter Berücksichtigung der Ausnahme ist kein Problem ...)

Oder eine Monade sollte nur eine flatMap Methode definieren, wobei eine Funktion, die die gleiche Art von Monade produziert? Ich denke, in diesem Fall würden die Either Projektionen nicht Monaden sein? Sind sie?

+0

@ om-nom-nom und Liste ist dann eine Monade? Übrigens kann ich nicht finden, wie es für 'List [Option [_]]' funktioniert, da Option keine GenTraversableOnce ist –

+0

'Entweder' ist eine Monade über seine beiden Typvariablen. Ist es das wonach Sie fragen? –

Antwort

5

Ich habe einmal ernsthaft darüber nachgedacht. Wie sich herausstellt, ein solches Konstrukt (abgesehen von allen monadischen Fähigkeiten zu verlieren) ist nicht wirklich interessant, da es ausreichend ist, eine Umwandlung vom inneren zum äußeren Behälter zu schaffen:

joinWith :: (Functor m, Monad m) => (n a -> m a) -> m (n a) -> m a 
joinWith i = join . (fmap i) 

bindWith :: (Functor m, Monad m) => (n a -> m a) -> m a -> (a -> n a) -> m a 
bindWith i x f = joinWith i $ fmap f x 

*Main> let maybeToList = (\x -> case x of Nothing -> []; (Just y) -> [y]) 
*Main> bindWith maybeToList [1..9] (\x -> if even x then Just x else Nothing) 
[2,4,6,8] 
+2

Dies ist eine gute Antwort. Mein Verständnis ist, dass es auch gut mit der Theorie übereinstimmt: Die 'n a -> m a'-Funktion repräsentiert eine natürliche Transformation zwischen den' n'- und 'm'-Funktoren. Unter der Annahme, dass es die Monadenoperationen respektiert, stellt es auch einen Monaden-Homomorphismus zwischen "n" und "m" dar. –

+0

Sorry, wie schlau Ihre Antwort ist, beantwortet dies nicht die Frage, die mehrere Flatmap-Methoden für eine einzelne Monade ist? Natürlich können wir einen Weg finden, zwei verschiedene Monaden zu einer gewählten zu verschmelzen, aber führt diese Art von Transformation auch zu einer Monade? Und ich sehe nicht, wie deine Antwort ihm helfen kann zu verstehen, warum das keine Monade ist. – zurgl

+0

diese antwort ist fast perfekt, imo. Die eine weitere Sache, auf die ich hinweisen würde, wäre, wenn Sie eine Funktion 'ma-> (a -> nb) -> nb' hätten, die den Monadish-Gesetzen gehorchte, könnten Sie einen Monad-Morphismus' ma -> nb' konstruieren, indem Sie ihr ein '' übergeben Rückkehr als zweites Argument. Gleichzeitig kann eine Funktion wie 'm a -> (a -> n b) -> m b' in einen Monadenmorphismus 'n a -> m b' mit deutlich mehr Arbeit umgewandelt werden. –

1

Es hängt davon ab, was "sinnvoll" bedeutet.

Wenn Sie meinen, dass es mit den Monadengesetzen übereinstimmt, dann ist es mir nicht ganz klar, dass die Frage durchaus Sinn ergibt. Ich müsste einen konkreten Vorschlag sehen. Wenn du es so machst, wie ich es dir vorschlägst, wirst du wahrscheinlich wenigstens in einigen Fällen die Komposition verletzen.

Wenn Sie meinen, es ist nützlich, sicher, Sie können immer Fälle finden, in denen solche Dinge nützlich sind. Das Problem ist, dass wenn Sie anfangen, Monad-Gesetze zu verletzen, Sie Fallen in Ihrem Code für den unachtsamen funktionalen (Kategorien-Theorie) Reasoner gelassen haben. Besser, Dinge, die wie Monaden aussehen, tatsächlich Monaden zu sein (und nur eine nach der anderen, obwohl Sie eine explizite Möglichkeit bieten können, eine La Either - aber Sie haben Recht, dass wie geschrieben LeftProjection und RightProjection sind nicht streng Sprechen, Monaden). Oder schreiben Sie wirklich klare Dokumente, die erklären, dass es nicht so ist, wie es aussieht. Sonst wird jemand munter weitergehen, vorausgesetzt, die Gesetze halten und * splat *.

1

Es macht keinen Sinn, für einen bestimmten Datentyp, so weit ich weiß, können Sie nur eine Definition für bind haben.

in Haskell eine Monade der folgende Typ-Klasse,

instance Monad m where 
    return :: a -> m a 
    bind :: m a -> (a -> m b) -> m b 

Konkret Für Liste Monad wir haben,

instance Monad [] where 
    return :: a -> [] a 
    (>>=) :: [] a -> (a -> [] b) -> [] b 

Lassen Sie uns jetzt eine einstellige Funktion prüfen, wie.

actOnList :: a -> [] b 
.... 

Ein Anwendungsfall, zu veranschaulichen

$ [1,2,3] >>= actOnList 

Auf der Funktion actOnList wir sehen, dass eine Liste von einem anderen Typ eine polymorphe Typeinschränkung (hier []). Wenn wir dann über den Bindeoperator für listenmonad sprechen, sprechen wir über den Bindeoperator, der durch [] a -> (a -> [] b) -> [] b definiert ist.

Was Sie wollen, zu erreichen, ist ein bind Operator wie [] Maybe a -> (a -> [] b) -> [] b definiert, ist dies nicht eine Spezialisierung Version des ersten aber eine andere Funktion und in Bezug auf sie Unterschrift geben ich wirklich bezweifle, dass es die bind Betreiber von jeder Art von Monade sein kann als Du gibst nicht zurück, was du konsumiert hast.Sie gehen sicher von einer Monade zur anderen mit einer Funktion, aber diese Funktion ist definitiv keine andere Version des bind Operators der Liste.

Das ist, warum ich gesagt habe, es macht keinen Sinn, für einen bestimmten Datentyp, so weit ich weiß, können Sie nur eine Definition für bind haben.

1

flatMap oder (>>=) nicht typecheck für Ihre Option[Try[ ]] Beispiel. In pseudo-Haskell Notation

type OptionTry x = Option (Try x) 

instance Monad OptionTry where 
    (>>=) :: OptionTry a -> (a -> OptionTry b) -> OptionTry b 
    ... 

Wir brauchen bind/flatMap Wert im selben Kontext als Eingabewert gewickelt zurückzukehren.

Wir können das auch sehen, indem wir uns die Entsprechung return/join Implementierung einer Monade ansehen. Für OptionTry hat join die spezielle Art

instance Monad OptionTry where 
    join :: OptionTry (OptionTry a) -> OptionTry a 
    ... 

Es sollte mit ein wenig schielen, dass die „flat“ Teil flatMap ist join (oder concat für Listen, in denen der Name von ableitet) klar sein.

Nun ist es möglich, dass ein einzelner Datentyp mehrere verschiedene bind s hat. Mathematisch ist ein Monad tatsächlich der Datentyp (oder, wirklich, der Satz von Werten, aus dem die Monade besteht) zusammen mit die bestimmten bind und return Operationen. Verschiedene Operationen führen zu unterschiedlichen (mathematischen) Monaden.

Verwandte Themen