我是Haskell的新手,所以这可能是一个愚蠢的问题。我有一个函数
foo :: Int -> IO ()
其结果将打印一些有用的信息。现在我想要做到这一点:
do
foo 0
foo 1
foo 0
foo 2
foo 3
我该如何用循环来写这个程序?我的问题是“连接”单子,这一过程在do语句中自动完成...
谢谢你的帮助!
我是Haskell的新手,所以这可能是一个愚蠢的问题。我有一个函数
foo :: Int -> IO ()
其结果将打印一些有用的信息。现在我想要做到这一点:
do
foo 0
foo 1
foo 0
foo 2
foo 3
我该如何用循环来写这个程序?我的问题是“连接”单子,这一过程在do语句中自动完成...
谢谢你的帮助!
mapM_ foo [0,1,0,2,3]
可以完成任务。
更重要的是,“如何找到这个方法?” Hoogle 是一个很好的工具。你想将一个带有签名 Int -> IO ()
的函数应用于一堆 Int
,以得到一个新的 IO 操作。因此,你要找的东西将具有签名 (Int -> IO ()) -> [Int] -> IO ()
,所以我们去 询问 Hoogle 是否有该签名的函数。第二个结果是 mapM_
,其签名为
Monad m => (a -> m b) -> [a] -> m ()
没错,实际上mapM_
可以与任何单子一起使用(不仅限于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
注意,在Control.Monad
中定义了一个名为forM_
的组合子,它与我所称呼的for
组合子完全相同。
forM_
是正确的名称,因为标准库中使用了它。 - leftaroundabout
[0, 1, 0, 2, 0, 3]
吗? - poitroaeIO
是一个单子,IO ()
(以及IO Int
,IO a
等)是一种类型,而foo 0
是类型为IO ()
的值(类似于foo 0
的常见词汇是“动作”,“单子动作”或“单子计算”)。因此,您正在尝试连接(或更常见的是“序列化”)操作,而不是单子-这里只有一个单子,它是IO
。 - luqui