我尝试使用Haskell的管道库实现简单的字数统计:
wordcountCv2 :: IO ()
wordcountCv2 = do
hashMap <- runConduitRes $ sourceFile "input.txt"
.| decodeUtf8C
.| omapCE Data.Char.toLower
.| peekForeverE (do
word <- takeWhileCE isAlphaNum
dropCE 1
return word)
.| foldMC insertInHashMap empty
print (toList hashMap)
insertInHashMap x v = do
return (insertWith (+) v 1 x)
问题是此功能对于中小型输入文件可以正常使用,但是随着文件大小的增加,它往往会破坏某些单词。例如,如果我使用的小文件包含单词“ hello”的100倍,则结果为:[(“ hello”,100)],如果例如hello是100000,则结果为:[(“ hello”, 99988),(“ he”,6),(“ hell”,6),(“ o”,6),(“ llo”,6)]。文件增长得越多,破碎的单词就越多。我的实现中有问题吗?
答案 0 :(得分:2)
takeWhileCE
返回()
并将结果发送到下游而不是返回。不过,他们在一件事情上是错的:实际上,这是 问题。
您的管道在大块流上运行,而takeWhileCE
向下游发送结果的原因之一是这样,它可以使输入拆分在原始大块边界上进行。这样一来,它不会因为您可能会收到很长的匹配值序列而迫使您消耗无限的内存。
但是,如果您想组合构成每个单词的潜在多个块,则需要做更多的工作。通过foldC
发送邮件是一种方法。
.| peekForeverE (do
word <- takeWhileCE isAlphaNum .| foldC
dropCE 1
yield word)
就您而言,使用splitOnUnboundedE
组合器可以轻松完成所有工作。
.| splitOnUnboundedE (not . isAlphaNum)