8

我对 Haskell 很陌生,所以这可能是一个愚蠢的问题。我有一个功能

foo :: Int -> IO ()

其结果将打印一些有用的信息。现在我想这样做:

do
    foo 0
    foo 1
    foo 0
    foo 2
    foo 3

我怎样才能把它写成一个循环?我的问题是“连接” Monads,这是由 do 语句自动完成的......

感谢您的帮助!

4

2 回答 2

14

mapM_ foo [0,1,0,2,3]会成功的。

或许更重要的是“一个人是如何解决这个问题的?” Hoogle是一个很棒的工具。您想将带有签名的函数应用于Int -> IO ()一堆Ints 以获得新的 IO 操作。因此,您要查找的东西将具有签名(Int -> IO ()) -> [Int] -> IO (),因此我们去向Hoogle 询问具有该签名的功能。第二个结果是mapM_,其签名是

Monad m => (a -> m b) -> [a] -> m ()

是的,所以mapM_实际上适用于任何monad(不仅仅是IO)和任何类型(不仅仅是Int)。仔细想想,这一点也不奇怪。

于 2013-02-10T13:11:55.050 回答
12

您需要mapM_组合器,它将返回单子值的函数映射到列表上,并使用绑定运算符对结果进行排序:

>> let foo n = putStrLn (show n ++ "!")
>> mapM_ foo [0,1,0,2,3]
0!
1!
0!
2!
3!

有时人们喜欢使用翻转版

for :: Monad m => [a] -> (a -> m b) -> m ()
for = flip mapM_

这看起来更像是命令式代码:

>> for [1..5] $ \n ->
     putStrLn ("Number: " ++ show n)
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

请注意,调用的组合forM_器定义在 中Control.Monad,并且与我调用的组合器完全相同for

于 2013-02-10T13:17:52.467 回答