I am dealing with a library (ghcjs-dom
) in which every function returns an IO (Maybe T)
.
I have a function a
with returns an IO (Maybe x)
and function b
which takes x
as an argument and returns an IO (Maybe y)
.
Is an operator that lets me do a ??? b
and get an IO (Maybe y)
. My Hoogle search turned up nothing.
I am looking something like join
that works for IO (Maybe (IO (Maybe t)))
instead of IO (IO t)
or Maybe (Maybe t)
.
From what I understand, you have:
a :: IO (Maybe X)
b :: X -> IO (Maybe Y)
There is a close relationship between IO (Maybe a)
and MaybeT IO a
, namely MaybeT
converts one to the other:
MaybeT :: IO (Maybe a) -> MaybeT IO a
and the inverse operation is just runMaybeT
:
runMaybeT :: MaybeT IO a -> IO (MaybeT a)
In the MaybeT monad the composition you want to perform is just the bind operation:
MaybeT a >>= (\x -> MaybeT (b x)) :: MaybeT IO Y
This results in a value of type MaybeT IO Y
. To convert it back to a IO (Maybe Y)
just use runMaybeT
.
Update
Here is an operator to "compose" a and b:
andThen :: IO (Maybe a) -> (a -> IO (Maybe b)) -> IO (Maybe b)
andThen a b = runMaybeT $ MaybeT a >>= (\x -> MaybeT (b x) )
However, if you find yourself using this operator a lot, perhaps you
should rework your functions so you work primarily in the MaybeT IO
monad, and then you can just use >>=
with a single runMaybeT
on the outside.
If you don't want to use MaybeT
what you need is sequenceA
or traverse
from 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 your case f is IO and m Maybe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With