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 :-)
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 Nothing
s, and return a Just xs
if the list contains only Just
s with xs
the values that originally have been wrapped in Just
s.