我对 Haskell 很陌生,所以这可能是一个愚蠢的问题。我有一个功能
foo :: Int -> IO ()
其结果将打印一些有用的信息。现在我想这样做:
do
foo 0
foo 1
foo 0
foo 2
foo 3
我怎样才能把它写成一个循环?我的问题是“连接” Monads,这是由 do 语句自动完成的......
感谢您的帮助!
我对 Haskell 很陌生,所以这可能是一个愚蠢的问题。我有一个功能
foo :: Int -> IO ()
其结果将打印一些有用的信息。现在我想这样做:
do
foo 0
foo 1
foo 0
foo 2
foo 3
我怎样才能把它写成一个循环?我的问题是“连接” Monads,这是由 do 语句自动完成的......
感谢您的帮助!
mapM_ foo [0,1,0,2,3]
会成功的。
或许更重要的是“一个人是如何解决这个问题的?” Hoogle是一个很棒的工具。您想将带有签名的函数应用于Int -> IO ()
一堆Int
s 以获得新的 IO 操作。因此,您要查找的东西将具有签名(Int -> IO ()) -> [Int] -> IO ()
,因此我们去向Hoogle 询问具有该签名的功能。第二个结果是mapM_
,其签名是
Monad m => (a -> m b) -> [a] -> m ()
是的,所以mapM_
实际上适用于任何monad(不仅仅是IO
)和任何类型(不仅仅是Int
)。仔细想想,这一点也不奇怪。
您需要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
。