GHCは、これら2つのトラバーサルをマージするほどスマートではないと思います。または、通常の場合、GHCは十分にスマートである可能性がありますが、この動作を望まない場合があるため、GHCはそれを行いません。
これが、モノイドとを使用して、私がそれを行う方法ですfoldMap。
import Data.Monoid
import Data.Foldable
まず、モノイドspecialを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
そして、list monoidを使用して、specialOrNormalについても同様です。
specialOrNormalF :: a -> [a]
specialOrNormalF a = if isSpecialOrNormal a then [a] else []
specialOrNormal :: [a] -> [a]
specialOrNormal = foldMap specialOrNormalF
モノイドの優れた点の1つは、モノイドのタプルもモノイドであるため、これらのフォールドを簡単にマージできることです。
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
)