7

所以这个问题更普遍地是关于 Monads(特别是 Fay),但我的例子使用了 IO monad。

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

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

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

funct :: [String] -> IO ()
funct strs = do
    putStrLn (strs !! 0)
    putStrLn (strs !! 1)
    ...
4

2 回答 2

16

大多数标准库列表函数都有以 结尾的 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]

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

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

于 2014-05-20T23:31:57.210 回答
6

使用顺序

sequence $ map putStrLn strings

序列将单子从单子列表中拉出

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

从而将 (map putStrLn strings)::[IO a] 转换为 IO [a]。您可能还想使用相关的 sequence_ 来删除返回值。

您也可以使用forM_:: Monad m => [a] -> (a -> m b) -> m ()(它通常看起来更好,但对我来说有点命令式的感觉)。

于 2014-05-20T23:24:18.507 回答