Haskell:无法使用“map putStrLn”?

66

我有一个字符串列表,并尝试了以下代码:

ls = [ "banana", "mango", "orange" ]

main = do
       map PutStrLn list_of_strings

这没起作用,我不明白为什么。

ghc print-list.hs
print-list.hs:3:0:
    Couldn't match expected type `IO t' against inferred type `[IO ()]'
    In the expression: main
    When checking the type of the function `main'

任何提示?我想这与map返回列表而不是值有关,但我没有找到简单的方法来解决这个问题。
目前,我知道打印字符串列表的唯一方法是编写一个函数来迭代列表,打印每个元素(如果列表是[a],则打印,但如果是(a:b),则打印并递归)。但是,使用map会更简单...
谢谢!
2个回答

111

main函数的类型应该是IO t(其中t是一个类型变量)。map putStrLn ls的类型是[IO ()]。这就是为什么你会收到这个错误信息。你可以在ghci中运行以下命令来验证:

Prelude> :type map putStrLn ls
map putStrLn ls :: [IO ()]

解决这个问题的方案之一是使用mapM,它是map的“单子”版本。或者你可以使用mapM_,它与mapM相同,但不会收集函数的返回值。由于你不关心putStrLn的返回值,因此在这里使用mapM_更加合适。 mapM_具有以下类型:

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

以下是如何使用它的方法:

ls = [ "banana", "mango", "orange" ]
main = mapM_ putStrLn ls

17
我希望我早点学会的一件事是,Data.Traversable中定义了另一个mapM。这个mapM可以处理更多的数据结构,包括映射和数组,而不仅仅是列表。 - Dietrich Epp
5
我一直认为main的类型应该是IO (),从未知道它可以是forall t. IO t。这表明我们每天都能学到新东西 :-) - Tom Lokhorst
我有一个 IO String,我想将它映射到 IO Int 并打印出这个 Int。如何在 一行 中完成?这可能吗? - Nawaz

23

Ayman的回答对这种情况最有意义。通常,如果你有[m ()]且你想要m (),那么使用sequence_,其中m可以是任何单子,包括IO


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接