GHC足够聪明,可以在“半并行”的列表上运行多个操作吗?
考虑这个(简化的)代码:
findElements bigList = do
let special = head . filter isSpecial $ bigList
let others = filter isSpecialOrNormal $ bigList
return (special, others)
( Monad由于原始代码)
我猜GHC将运行第一个列表操作,并将所有元素保留在内存中,以便第二个操作能够对它们起作用。
我的问题是我在处理更大的文件时遇到了漏洞。但我相信它应该能够在恒定的空间中运行。有没有办法实现这个目标?
这样写下这个问题的解决办法当然是改变两行的顺序。
但我的问题仍然存在:GHC是否具有足够的智能性,可以在没有monad的情况下找出这种半并行处理?
答案 0 :(得分:4)
我不认为GHC足够智能合并这两个遍历,或者,通常情况下,GHC可能足够聪明,但有些情况下你不想要这种行为,所以GHC没有做到这一点。
以下是我将如何使用monoids和foldMap
。
import Data.Monoid
import Data.Foldable
首先,使用special
monoid,如何使用foldMap
编写First
。
specialF :: a -> First a
specialF a = First $ if isSpecial a then Just a else Nothing
special :: [a] -> a
special as = let (First (Just s)) = foldMap specialF as in s
与specialOrNormal类似,使用列表monoid。
specialOrNormalF :: a -> [a]
specialOrNormalF a = if isSpecialOrNormal a then [a] else []
specialOrNormal :: [a] -> [a]
specialOrNormal = foldMap specialOrNormalF
关于幺半群的一个巧妙的事情是,幺半群的元组也是一个幺半群,这使得合并这些褶皱变得容易:
findElements :: [a] -> (a, [a])
findElements bigList =
let (First (Just s), son) =
foldMap (\a -> (specialF a, specialOrNormalF a)) bigList
in (s, son)
如果你喜欢无点代码,你可以写下这样的全部内容:
findElements :: [a] -> (a, [a])
findElements =
first (fromJust . getFirst) .
foldMap
( First . mfilter isSpecial . return
&&& mfilter isSpecialOrNormal . return
)