Question

How can a output a list of strings using putStr and map? I want to do something like:

s=["test1","test2"]
map putStr s

But have no experience with monads and don't know how to get it right...

Any kind of hint is enormously welcome!

Was it helpful?

Solution 2

The type of map is:

map :: (a -> b) -> [a] -> [b]

this means that, since putStr returns an IO (), your expression will return a [IO ()].

You can, instead, use mapM_ (imported from Prelude) that will ignore the return type from the mapping and return an IO () which is a suitable return type for main:

main = do
    let s=["test1","test2"]
    mapM_ putStr s

Live demo

OTHER TIPS

The correct thing to do here is use mapM_ :: Monad m => (a -> m b) -> [a] -> m (). But if you'd like to learn a little about some useful Prelude functions...

We have two functions here,

map :: (a -> b) -> [a] -> [b]
putStr :: String -> IO ()

if we substitute the type of putStr into map (ie. a ~ String, b ~ IO ()) we get

map putStr :: [String] -> [IO ()]

so this takes a list of strings and gives us a list of IO () actions; IO computations that don't return anything usefull.

We'd like to turn that [IO ()] into something like IO (...) because we need IO to be the outermost layer in order to use it in main :: IO ()

The function sequence :: Monad m => [m a] -> m [a] from the Prelude is exactly what we need. It takes a list of monadic actions, executes them and returns the results in a list wrapped in the monad. Intuitively it moves the monad to the outermost layer.

sequence . map putStr :: [String] -> IO [()]

This is quite close, but we still have IO [()] instead of IO (), we don't really care about the [()] result and it'd be nice to ignore it. Again, the Prelude has what we need: sequence_ :: Monad m => [m a] -> m () which executes each monadic action in the list and ignores their return values.

Note that mapM_ is defined as

mapM_ f = sequence_ . map f
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top