简体   繁体   中英

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)
    ...

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 -> mb) -> m () (which often looks nicer, but has a bit of an imperative feel to me).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM