Search code examples
haskellcompositionmonad-transformers

How to deal with an IO (Maybe (IO (Maybe t))) type?


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).


Solution

  • 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.