【问题标题】:Applying putStr to each item of a list将 putStr 应用于列表的每个项目
【发布时间】:2013-03-05 05:36:30
【问题描述】:

我正在尝试以这种格式打印出一个整数列表

[1]
[2]
[3]

所以我的函数接受一个整数列表并返回一个 IO (),如下所示:

import System.IO

printVector :: [Integer] -> IO ()
printVector (x:xs) = putStr("[" ++ show(x) ++ "]" ++ "\n") : printVector xs

但是 ghc 给了我错误:

lin-test.hs:5:22:
Couldn't match expected type `IO ()' with actual type `[a0]'
In the expression:
  putStr ("[" ++ show (x) ++ "]" ++ "") : printVector xs
In an equation for `printVector':
    printVector (x : xs)
      = putStr ("[" ++ show (x) ++ "]" ++ "") : printVector xs
Failed, modules loaded: none.

现在我的理解是,该函数将遍历列表,首先获取第一个项目“x”,然后使用 : printVector xs 它将递归调用列表的其余部分,将相同的 putStr 函数应用于每个项目列表。

但我认为我的问题出在哪里:printVector xs? 谁能指出我在这里做错了什么?

【问题讨论】:

  • 最简单的更改:>> printVector xs 而不是 : printVector xs

标签: list haskell printing


【解决方案1】:

您需要映射列表,但由于这些是 IO 操作,您还需要执行它们(因为map 将返回一个 IO 操作列表而不执行它们,请参见以下示例)。

sequence $ map (putStrLn . show) [1,2,3,4]

已经有一个函数可以做到这一点,它是mapM。所以这个例子可以简化为:

mapM (putStrLn . show) [1,2,3,4]

您可以做的另一件事是使用mapM_,它使用sequence_,并且将忽略对每个元素执行IO 操作的结果。因此,返回类型将是 IO () 而不是 IO [()](上一个示例)。

mapM_ (putStrLn . show) [1,2,3,4]

【讨论】:

  • 我明白了。这是一个非常有用的功能。有没有办法让我补充一下,说我想像上面写的那样自己进行格式化, mapM_ ("[" ++ putStr ++ "]" ++ "\n" . show) [1,2 ,3,4]。这当然是错误的,但我真的很希望能够像这样打印出来
  • @enkitosh:拆分 IO 和格式:mapM_ (putStr . format) [1..4]format x = "[" ++ show x ++ "]\n"
  • @enkitosh 使用 lambda,mapM_ (\n -> putStrLn $ "[" ++ show n ++ "]") [1,2,3,4],或者,IMO 更具可读性,import Control.Monad (forM_)forM_ [1,2,3,4] $ \n -> putStrLn $ "[" ++ show n ++ "]"。 (forM_ = flip mapM_)
  • 太棒了。谢谢。您的两个答案都非常有帮助!
猜你喜欢
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 2014-10-09
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多