如何在带有符号的列表上使用映射 - 即避免使用类型"[IO()]"键入`IO()'?

ale*_*027 5 monads haskell io-monad

所以这个问题更多地是关于Monads(尤其是Fay),但是我的例子使用了IO monad.

我有一个函数,其中输入是一个字符串列表,我想逐个打印每个字符串.所以这是我的想法:

funct :: [String] -> ?
funct strs = do
    map putStrLn strs
Run Code Online (Sandbox Code Playgroud)

但是不起作用,因为它返回一个类型[IO()].所以我的问题是,我将如何映射列表,并将其视为我在逐行执行函数,以典型的符号,迭代风格(如下所示)?

funct :: [String] -> IO ()
funct strs = do
    putStrLn (strs !! 0)
    putStrLn (strs !! 1)
    ...
Run Code Online (Sandbox Code Playgroud)

luq*_*qui 14

大多数标准库列表函数都具有以下结尾的monadic版本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]
Run Code Online (Sandbox Code Playgroud)

有时他们在Prelude,有时他们在Control.Monad.我建议使用hoogle来查找它们.

特别针对您的情况,我mapM_ putStrLn经常使用.


jam*_*idh 5

使用顺序

sequence $ map putStrLn strings
Run Code Online (Sandbox Code Playgroud)

sequence将monad从monad列表中拉出来

sequence :: Monad m => [m a] -> m [a]
Run Code Online (Sandbox Code Playgroud)

从而将(将putStrLn字符串):: [IO a]转换为IO [a].您可能希望使用相关的sequence_来删除返回值.

你也可以使用forM_:: Monad m => [a] -> (a -> m b) -> m ()(通常看起来更好,但对我有一点迫切的感觉).

  • `序列。map f` 作为`mapM f`包含在库中。 (2认同)