题 Haskell:不能使用“map putStrLn”?


我有一个字符串列表,并试过这个:

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'

任何提示?我想它与地图返回列表而不是值有关,但我没有找到一种简单的方法来解决这个问题。

现在,我知道打印字符串列表的唯一方法是编写一个函数来迭代列表,打印每个元素(如果列表是[a]则打印,但如果是(a:b)则打印和递归)。但它会 许多 更简单地使用地图......

谢谢!


51
2018-05-31 19:08


起源




答案:


的类型 main 功能应该是 IO t (哪里 t 是一个类型变量)。的类型 map putStrLn ls 是 [IO ()]。这就是您收到此错误消息的原因。您可以通过运行以下内容来自行验证 ghci

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

该问题的一个解决方案是使用 mapM,这是“monadic”版本 map。或者你可以使用 mapM_ 这是一样的 mapM 但不从函数中收集返回的值。因为你不关心的回报值 putStrLn,它更适合使用 mapM_ 这里。 mapM_ 有以下类型:

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

以下是如何使用它:

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

91
2018-05-31 19:28



我希望我早点学到的东西是Data.Traversable中定义的另一个mapM。除了列表(例如地图和数组)之外,此mapM还可以处理更多数据结构。 - Dietrich Epp
我一直以为 main 应该是类型 IO (),从来不知道它可能 forall t. IO t。这表明你每天都能学到新东西:-) - Tom Lokhorst


艾曼的回答对这种情况最有意义。一般来说,如果你有 [m ()] 而你想要的 m (),然后使用 sequence_,哪里 m 可以是任何单子包括 IO


20
2018-05-31 19:32