看看下面的函数:readCSVFile :: :: (MonadResource m, CSV ByteString a) => CSVSettings -> FilePath -> m [a]
调用起来相对简单,因为我们只需要一个CSVSettings
,例如defCSVSettings
,和一个FilePath
(aka String
),"file.csv"
或其他东西。
因此,在调用之后,我们得到(MonadResource m, CSV ByteString a)
. 我们可以一次解决这个问题,以找出合适的类型。我们正在执行IO
这个操作,所以 for MonadResource m
,m
应该只是ResourceT IO
,它恰好是MonadBaseControl IO
as 要求的一个实例runResourceT
。这是一个conduit
具体的事情。
对于CSV ByteString a
,我们需要找到 的哪些实例CSV
。为此,请访问http://hackage.haskell.org/packages/archive/csv-conduit/0.2.1.1/doc/html/Data-CSV-Conduit.html#t:CSV(其中包的文档在我看来有点令人讨厌的是所有都塞进了类型类...)然后单击 Instances 以查看我们有哪些可用的实例CSV ByteString a
。两个选项是CSV ByteString ByteString
和CSV ByteString Text
。
在这两者中,Text
更可取,因为它处理 unicode,而 CSV 不太可能包含二进制数据。ByteString
或多或少类似于一段[Word8]
时间Text
更类似于[Char]
这可能是您想要的。因此,a
应该是Text
(尽管ByteString
仍然有效)。
这意味着函数调用的结果是ResourceT IO [Row Text]
. 我们对此无能为力,但因为ResourceT
它是一个 monad 转换器,我们可以使用 函数轻松“弹出” monad 转换层runResourceT
。因此,
readFile :: FilePath -> IO [Row Text]
readFile = runResourceT . readCSVFile defCSVSettings
这很容易在 main 中使用,然后您可以使用 a或 a[Row Text]
进行迭代以获取各个行。map
fold
要在 GHCI 中运行这类事情,您绝对必须特别指出类型。原因是结果类实例不依赖于任何参数;因此,对于任何一组CSVSettings
and FilePath
,readCSVFile
只要它们 asm
是MonadResource m
和a
的一个实例,就可以返回任意数量的不同类型CSV ByteString a
。因此,我们必须明确指出 GHCi 您想要哪种类型。