Values inside monads, nested in data structures?

functional-programming, haskell, monads

Solution

You could use the `liftM*` function from the Control.Monad module, or the `liftA*` functions for applicatives.

`liftM` allows you to lift a pure function to work inside a Monad, e.g.:

ghci> let s = return "Hello" :: IO String
ghci> liftM reverse s
"olleH"

This way you don't have to manually write things like "`s >>= \x -> return (reverse x)`" everywhere.

Although, this won't help you with your `[(String, Int, IO Int)]` example, if the pure function you have deals with a `[(String, Int, Int)]`. Since the third element in the tuple really isn't an `Int`.

In that case I'd suggest to first write a function `[(String, Int, IO Int)] -> IO [(String, Int, Int)]` and that apply the lifted pure function.

This is the most general function I could come up with to do this:

conv :: Monad m => (f (m a) -> m (f a)) -> [f (m a)] -> m [f a]
conv f = sequence . map f

You can call it like so:

liftTrd :: Monad m => (a, b, m c) -> m (a, b, c)
liftTrd (x, y, mz) = mz >>= \z -> return (x, y, z)

conv liftTrd [("hi", 4, return 2)] :: IO [(String, Int, Int)]

This function will only work if you have a single monad that's somewhere deep in a type. If you have multiple, I think you should really be thinking about the type your working in with and see if you can't make it simpler.

Problem

Suppose that in a Haskell program I have some data whose type is something like: - `IO [ IO (Int, String, Int) ]`, or - `IO [ (Int, String, IO Int) ]`, or - `[ (Int, String, IO Int) ]` but I have pure functions that should operate on `[ (Int, String, Int) ]`. It seems that I'd have to clumsily remove the inside values from the IO monad, until I got something like IO [ (Int, string, Int) ] and then (from inside the IO monad) apply the pure functions. There is no easy pre-defined way to do this, I suppose? Something that would lift a whole data structure into a monad, turning all inside types into pure types? (That would be very convenient!)

Original source