在哈斯克尔的Monads上循环

Sh4*_*4pe 8 haskell

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

foo :: Int -> IO ()
Run Code Online (Sandbox Code Playgroud)

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

do
    foo 0
    foo 1
    foo 0
    foo 2
    foo 3
Run Code Online (Sandbox Code Playgroud)

我怎么能把它写成循环?我的问题是'连接'Monads,这是由do语句自动完成的......

谢谢您的帮助!

gsp*_*spr 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 ()
Run Code Online (Sandbox Code Playgroud)

是的,所以mapM_实际上适用于任何 monad(不仅仅是IO)和任何类型(不仅仅是Int).当你想到它时,这一点都不奇怪.


Chr*_*lor 12

你想要mapM_组合器,它映射一个函数,在一个列表上返回一个monadic值,并使用bind运算符对结果进行排序:

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

有时人们喜欢使用翻转版本

for :: Monad m => [a] -> (a -> m b) -> m ()
for = flip mapM_
Run Code Online (Sandbox Code Playgroud)

看起来更像命令式代码:

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

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