Search code examples
haskellmonad-transformers

Haskell - How to combine two monadic Maybe functions into a single function


Let's say I have these two data records, X and Y and following two functions:

f1 :: IO (Maybe [X])
f2 :: X -> IO (Maybe Y)

I need to call the f1 first and then, for each element of returned list (stored in IO (Maybe)) call the f2, which would result in something like IO (Maybe [IO (Maybe Y)]). How can I compose them to get something meaningful, such as

result :: Maybe (IO [Y])

or

result :: IO (Maybe [Y])

?

Thanks a lot for any help :-)


Solution

  • A candidate could be:

    result :: IO (Maybe [Y])
    result = f1 >>= fmap sequenceA . mapM f2 . concat

    Here concat is a function concat :: Foldable f => f [a] -> [a] that will convert a Nothing to an empty list, and a Just xs to xs.

    We can then make a mapM f2 to generate an IO [Maybe a], and fmap :: Functor f => (a -> b) -> f a -> f b with sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a) to convert an IO [Maybe Y] to an IO (Maybe [Y]).

    sequenceA will return a Nothing if the list contains one or more Nothings, and return a Just xs if the list contains only Justs with xs the values that originally have been wrapped in Justs.