Трубопровод трубопровода пропускает некоторые элементы потока - PullRequest
3 голосов
/ 14 мая 2019

Я попытался реализовать простой подсчет слов с помощью библиотеки 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), ( "о", 6), ( "LLO", 6)]. Чем больше растет файл, тем больше встречаются неработающие слова. Что-то не так в моей реализации?

1 Ответ

2 голосов
/ 15 мая 2019

Чи правильно прокомментировал , что takeWhileCE возвращает () и отправляет результат в нисходящем направлении вместо его возврата.Однако они ошибаются в одном: эта является , на самом деле проблема.

Ваш канал работает с потоком фрагментов, и одна из причин, по которой takeWhileCE отправляетв результате получается нисходящий поток, поэтому он может оставить входной разделитель на исходных границах чанка.Таким образом, это не заставляет вас использовать неограниченную память только потому, что вы можете получить длинную последовательность совпадающих значений.

Но если вы хотите объединить потенциально несколько кусков, составляющих каждое слово, вам нужно сделатьнемного больше работы.Отправка их через foldC является одним из способов сделать это.

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

В вашем случае проще использовать комбинатор splitOnUnboundedE, который делает этовсе для тебя.

        .| splitOnUnboundedE (not . isAlphaNum)
...