Фьюзинг несколько раз в Haskell
Я пытаюсь прочитать и проанализировать огромный файл 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]
После этого программа входит в стадию анализа и выполняет четыре (это очень важно) разных экземпляра (т.е. с разными фильтрами) следующего
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 ответ
Да, вы действительно можете объединить четыре сгиба, но вам придется делать это вручную. Вы можете попробовать написать логику самостоятельно или использовать библиотеку (например, 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