在 Haskell 中融合多个 foldl'
Fusing multiple foldl' in 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
foldl 以一张空地图开始。
内存使用量随着元素数量的增加而增加 take
d 有或没有优化。
是的,您确实可以将四个折叠融合在一起,但您必须手动进行。您可以尝试自己写出逻辑,也可以使用库(如 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
我正在尝试读取和分析一个巨大的 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
foldl 以一张空地图开始。
内存使用量随着元素数量的增加而增加 take
d 有或没有优化。
是的,您确实可以将四个折叠融合在一起,但您必须手动进行。您可以尝试自己写出逻辑,也可以使用库(如 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