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)
...
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.
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.
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.
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With