Фьюзинг несколько раз в Haskell - PullRequest
0 голосов
/ 08 июня 2018

Я пытаюсь прочитать и проанализировать огромный CSV-файл.Я использовал Data.Csv.Streaming из кассавы, и функции применяются в следующем порядке:

Data.ByteString.Lazy.readFile -- Gives lazy stream
Data.Csv.Streaming.decodeByname -- Gives Either String (Header Records t)
\(Right (_, v)) -> v -- Gives right side of either (Records t)
Data.Foldable.toList -- Gives [t]

После этого программа переходит в стадию анализа и выполняет four (это очень важно)различные экземпляры (то есть с разными фильтрами) следующего

filter -- Result of toList is applied through a filter
map
Data.Foldable.foldl' -- Does bin counting using a map. The map has at most 60 keys.

Однако, похоже, что программа занимает огромный объем памяти при попытке загрузить весь файл CSV.

ЕслиУ меня есть только один экземпляр выполнения foldl ', программа делает один единственный проход через данные CSV и не потребляет столько памяти.Есть ли способ соединить складки?То есть, имея

x = foldl' f Map.empty $ filter cx li
y = foldl' f Map.empty $ filter cy li
...

и заставляя его выполняться за один проход.

Редактировать: Следующая функция используется в foldl с Data.Map.Strict как Map:

bincollect :: Ord a => Num b => Map.Map a b -> a -> Map.Map a b
bincollect !m !key = Map.insertWith (+) key 1 m

и сгиб начинается с пустой карты.

Использование памяти увеличивается с числом элементов take d с включенной оптимизацией или без нее.

1 Ответ

0 голосов
/ 09 июня 2018

Да, вы действительно можете объединить четыре сгиба, но вам придется делать это вручную.Вы можете попробовать написать логику самостоятельно или использовать библиотеку (например, foldl ), чтобы помочь.Например, вы можете превратить ваш bincollect в складку:

bincollect :: (Ord a, Num b) => Fold a (Map.Map a b)
bincollect = Fold (\m key -> Map.insertWith (+) key 1 m) Map.empty id

Затем вы можете фильтровать, используя prefilter:

x = prefilter cx bincollect

Наконец, вы можете объединить их вместе, используя Applicative экземпляр:

(w,x,y,z) = fold ((,,,) <$> prefilter cw bincollect
                        <*> prefilter cx bincollect
                        <*> prefilter cy bincollect
                        <*> prefilter cz bincollect)
                 input
...