【问题标题】:Conduit pipeline skips some elements of a stream管道管道跳过流的一些元素
【发布时间】:2019-05-14 16:33:37
【问题描述】:

我尝试使用 Haskell 的 Conduit 库实现一个简单的字数统计:

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)

问题是这个函数可以很好地处理中小型输入文件,但是随着文件大小的增长,它往往会破坏一些单词。例如,如果我使用一个包含 100 次单词“hello”的小文件,结果是:[("hello",100)],而不是如果 hellos 是例如 100000,结果是:[("hello", 99988),("他",6),("地狱",6),("o",6),("llo",6)]。文件增长得越多,断词就越多。我的实现有问题吗?

【问题讨论】:

  • 请一次一个问题。
  • 好吧对不起,我删第一个
  • 次要观点:word &lt;- takeWhileCE isAlphaNum 使 word 成为 ()。取出的单词被推送到下游,而不是返回。无论如何,这应该不是问题。

标签: haskell conduit


【解决方案1】:

chi 正确地 commented takeWhileCE 返回 () 并将结果发送到下游而不是返回它。不过,他们在一件事情上错了:这,事实上,问题。

您的管道在块流上运行,takeWhileCE 将结果发送到下游的原因之一是它可以将输入拆分留在原始块边界上。这样,它就不会因为您可能会收到一长串匹配值而强迫您消耗无限的内存。

但是,如果您想组合构成每个单词的潜在多个块,则需要做更多的工作。通过foldC 发送它们是一种方法。

        .| peekForeverE (do
            word <- takeWhileCE isAlphaNum .| foldC
            dropCE 1
            yield word)

在您的情况下,使用 splitOnUnboundedE 组合器会更容易,它可以为您完成所有工作。

        .| splitOnUnboundedE (not . isAlphaNum)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-15
    • 2020-10-22
    • 2020-01-30
    • 1970-01-01
    • 2018-03-17
    • 2022-11-03
    • 1970-01-01
    • 2021-10-10
    相关资源
    最近更新 更多