Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use map over a list with do notation - ie avoid type `IO ()' with type `[IO ()]'?

So this question is about Monads more generally (in particuar for Fay), but my example uses the IO monad.

I have a function where the input is a list of strings and I would like to print each string one by one. So here was my idea:

funct :: [String] -> ?
funct strs = do
    map putStrLn strs

But doesn't work because it returns a type [IO ()]. So my question is, how would I map over a list, and treat it as if I'm performing the function line by line, in typical do-notation, iterative style (like below)?

funct :: [String] -> IO ()
funct strs = do
    putStrLn (strs !! 0)
    putStrLn (strs !! 1)
    ...
like image 686
aled1027 Avatar asked May 20 '14 23:05

aled1027


People also ask

What is IO () Haskell?

IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.

What is an i/o action?

7.1 Basic I/O Operations Actions are sequenced using an operator that has a rather cryptic name: >>= (or `bind'). Instead of using this operator directly, we choose some syntactic sugar, the do notation, to hide these sequencing operators under a syntax resembling more conventional languages.

What is an IO string?

An IO String is a String in the IO-Monad. If a function in the IO-Monad returns an IO String, you get the String by doing: do str <- ioFunc.

Is IO a Monad Haskell?

The IO type constructor provides a way to represent actions as Haskell values, so that we can manipulate them with pure functions. In the Prologue chapter, we anticipated some of the key features of this solution. Now that we also know that IO is a monad, we can wrap up the discussion we started there.


2 Answers

Most of the standard library list functions have monadic versions that end with M:

map :: (a -> b) -> [a] -> [b]
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]

replicate :: Int -> a -> [a]
replicateM :: (Monad m) => Int -> m a -> m [a]

etc. Sometimes they are in Prelude, sometimes they are in the Control.Monad. I recommend using hoogle to find them.

Specifically for your case, i use mapM_ putStrLn quite often.

like image 99
luqui Avatar answered Sep 29 '22 04:09

luqui


Use sequence

sequence $ map putStrLn strings

sequence pulls the monad out of a list of monads

sequence :: Monad m => [m a] -> m [a]

thus converting (map putStrLn strings)::[IO a] to IO [a]. You might want to use the related sequence_ to drop the return value also.

You can also use forM_:: Monad m => [a] -> (a -> m b) -> m () (which often looks nicer, but has a bit of an imperative feel to me).

like image 42
jamshidh Avatar answered Sep 29 '22 03:09

jamshidh