Reputation: 151
Is there a traditional way to map over a function that uses IO? Specifically, I'd like to map over a function that returns a random value of some kind. Using a normal map will result in an output of type ([IO b]), but to unpack the values in the list from IO, I need a something of type (IO [b]). So I wrote...
mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b]
mapIO f [] acc = do return acc
mapIO f (x:xs) acc = do
new <- f x
mapIO f xs (new:acc)
... which works fine. But it seems like there ought to be a solution for this built into Haskell. For instance, an example use case:
getPercent :: Int -> IO Bool
getPercent x = do
y <- getStdRandom (randomR (1,100))
return $ y < x
mapIO (\f -> getPercent 50) [0..10] []
Upvotes: 10
Views: 6250
Reputation: 1856
Just to add to Don's answer, hake a look to the mapM_
function as well, which does exactly what mapM
does but discards all the results so you get only side-effects.
This is useful if you want the have computations executed (for example IO computations) but are not interested in the result (for example, unlinking files).
And also see forM
and forM_
.
Upvotes: 15
Reputation: 137987
The standard way is via:
Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
which is implemented in terms of sequence:
sequence :: (Monad m) => [m a] -> m [a]
Upvotes: 25