unignorant
unignorant

Reputation: 151

Mapping over IO in Haskell

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

Answers (2)

Cristiano Paris
Cristiano Paris

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

Don Stewart
Don Stewart

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

Related Questions