Конвейер Conduit пропускает некоторые элементы потока

Я попытался реализовать простой подсчет слов с помощью библиотеки 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 раз слово «привет», результат будет следующим: [(«привет», 100)], вместо этого, если приветствий, например, 100000, результат будет следующим: [(«привет», 99988), ("он", 6), ("ад", 6), ("о", 6), ("привет", 6)]. Чем больше файл растет, тем больше в нем неработающих слов. Что-то не так в моей реализации?


person mennetorelli    schedule 14.05.2019    source источник
comment
Пожалуйста, по одному вопросу.   -  person Michael Litchard    schedule 14.05.2019
comment
Хорошо, извините, я удалю первый   -  person mennetorelli    schedule 14.05.2019
comment
Незначительный момент: word <- takeWhileCE isAlphaNum превращает word в (). Принятое слово проталкивается вниз по течению, а не возвращается. В любом случае, это не должно быть проблемой.   -  person chi    schedule 14.05.2019


Ответы (1)


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

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

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

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

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

        .| splitOnUnboundedE (not . isAlphaNum)
person Anders Kaseorg    schedule 15.05.2019