2016-08-02 10 views
4

Ich habe es mit einer Bibliothek (ghcjs-dom) zu tun, in der jede Funktion eine IO (Maybe T) zurückgibt.Wie man mit einem IO (Vielleicht (IO (Vielleicht t))) Typ umgehen?

Ich habe eine Funktion a mit Renditen eine IO (Maybe x) und Funktion b die x als Argument und gibt eine IO (Maybe y).

Ist ein Operator, der mich a ??? b tun und eine IO (Maybe y) bekommen kann. Meine Hoogle-Suche ergab nichts.

Ich suche etwas wie join, die für IO (Maybe (IO (Maybe t))) statt IO (IO t) oder Maybe (Maybe t) funktioniert.

+1

Was ist 'IO Maybe T'? Das sieht wie ein freundlicher Fehler aus. – augustss

+0

@augustss IO (Vielleicht anyRandomType) – 2426021684

+2

Nun, bearbeiten Sie die Frage post dann. Im Moment ist es ziemlich unlesbar. – leftaroundabout

Antwort

10

Von dem, was ich verstehe, Sie haben:

a :: IO (Maybe X) 
b :: X -> IO (Maybe Y) 

Es besteht eine enge Beziehung zwischen IO (Maybe a) und MaybeT IO a, nämlich MaybeT wandelt einen zum anderen:

MaybeT :: IO (Maybe a) -> MaybeT IO a 

und die inverse Operation ist nur runMaybeT:

runMaybeT :: MaybeT IO a -> IO (MaybeT a) 

Im MaybeT Monade der Zusammensetzung Sie ausführen wollen, ist nur die Bindeoperation:

MaybeT a >>= (\x -> MaybeT (b x)) :: MaybeT IO Y 

Daraus ergibt sich ein Wert vom Typ MaybeT IO Y. Um es zurück zu IO (Maybe Y) zu konvertieren, verwenden Sie einfach runMaybeT.

aktualisieren

Hier ist ein Operator zu "komponieren" eine und b:

andThen :: IO (Maybe a) -> (a -> IO (Maybe b)) -> IO (Maybe b) 
andThen a b = runMaybeT $ MaybeT a >>= (\x -> MaybeT (b x)) 

jedoch, wenn Sie sich mit diesem Operator viel finden, vielleicht Sie sollten überarbeiten Sie Ihre Funktionen, so dass Sie in erster Linie in der MaybeT IO Monade arbeiten, und dann können Sie einfach >>= mit einer einzigenverwenden auf der Außenseite.

+0

Woher weiß MaybeT, ob die Operation erfolgreich war oder nicht, wenn sie nicht ausgeführt wurde? – 2426021684

+1

Antwort aktualisiert für den Betreiber. Sowohl 'MaybeT' als auch' runMaybeT' ändern nichts an der IO-Aktion außer ihrem Typ. 'MaybeT' richtet Dinge so ein, dass' >> = 'die Kleberlogik für den Fall Nothing hinzufügt und die Rückgabewerte mit Just umschließt.'runMaybeT' wandelt es zurück in eine IO-Aktion, so dass es in' main' ausgeführt werden kann. Nichts passiert wirklich, bis die IO-Aktion ausgeführt wird, wenn sie Teil von 'main' ist. – ErikR

+0

Danke. Leider sind die Funktionen von ghcjs-dom, so dass ich sie nicht einfach ändern kann. – 2426021684

3

Wenn Sie nicht MaybeT verwenden möchten, benötigen Sie sequenceA oder traverse von Data.Traversable.

Prelude Data.Traversable Control.Monad> :t fmap join . join . fmap sequenceA 

fmap join . join . fmap sequenceA 
    :: (Traversable m, Control.Applicative.Applicative f, Monad m, 
     Monad f) => 
     f (m (f (m a))) -> f (m a) 

In Ihrem Fall ist f IO und m Vielleicht.

+0

Ihre Antwort funktioniert genauso wie die von ErikR, funktioniert aber für alle Monaden? Welche Antwort soll ich verwenden? – 2426021684

+1

Mine funktioniert nicht auf irgendeiner Monade, man muss traversable sein, was die Form der Form ist. Vielleicht, Liste etc ... Verwenden Sie die, die Ihnen passt. Wenn Sie so viele Fälle haben, sollten Sie wahrscheinlich mit MaybeT gehen. – mb14