我不认为 GHC 足够聪明来合并这两个遍历,或者,通常情况下,GHC 可能足够聪明,但是在某些情况下你不想要这种行为,所以 GHC 不会这样做。
这是我将如何使用幺半群和foldMap
.
import Data.Monoid
import Data.Foldable
首先,这是使用幺半群编写special
with的方法。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
)