module Hcompta.Lib.Foldable where import Data.Monoid import Data.Maybe (listToMaybe, maybeToList) import Data.Foldable (Foldable, foldMap, foldr) -- | Return the first non-'Nothing' returned by the given function -- applied on the elements of a 'Foldable'. find :: Foldable t => (a -> Maybe b) -> t a -> Maybe b find f = listToMaybe . Data.Foldable.foldMap (maybeToList . f) -- | Like 'Data.Either.partitionEithers' but generalized -- to work on a 'Foldable' containing 'Monoid's. -- -- NOTE: any lazyness on resulting 'Monoid's is preserved. partitionEithers :: (Foldable t, Monoid r, Monoid l) => t (Either l r) -> (l, r) partitionEithers m = Data.Foldable.foldr (either left right) (mempty, mempty) m where left a ~(l, r) = (a`mappend`l, r) right a ~(l, r) = (l, a`mappend`r) -- | Return a tuple of accumulated 'Left's and folded 'Right's -- in the given 'Foldable'. -- -- * NOTE: any lazyness on resulting 'Monoid's is preserved. -- * WARNING: beware that given an infinite 'Foldable', -- the initial 'Right' accumulator will never be appended -- to the final 'Right' accumulator. accumLeftsAndFoldrRights :: (Foldable t, Monoid l) => (r -> ra -> ra) -> ra -> t (Either l r) -> (l, ra) accumLeftsAndFoldrRights f rempty m = Data.Foldable.foldr (either left right) (mempty, rempty) m where left a ~(l, r) = (a`mappend`l, r) right a ~(l, r) = (l, f a r) -- | Type composition. -- -- NOTE: this could eventually be replaced by -- adding a dependency on -- newtype Composition g f a = Composition (g (f a)) -- | A 'Foldable' of a 'Foldable' is itself a 'Foldable'. instance (Foldable f1, Foldable f2) => Foldable (Composition f1 f2) where foldr f acc (Composition o) = Data.Foldable.foldr (flip $ Data.Foldable.foldr f) acc o