{-# LANGUAGE Safe #-} -- | A collection of monoidal folds. These are all short circuiting and -- are designed to handle certain infinite cases properly. These are -- useful for operations which don't require the full list to -- calculate the output. module Data.Fold.Common.M where import Prelude hiding (any, all) import Data.Fold import Data.Monoid -- | Check that if predicate holds for any inputs to the fold. -- -- >>> run [1, 2, 3, 4] (any even) -- True -- -- >>> run [] (any $ const False) -- False any :: (a -> Bool) -> M a Bool any p = M getAny (Any . p) (<>) (Any False) -- | Check that if predicate holds for all inputs to the fold. -- -- >>> run [1, 2, 3, 4] (all (< 6)) -- True -- -- >>> run [1, 2, 3, 4] (all (> 1)) -- False all :: (a -> Bool) -> M a Bool all p = M getAll (All . p) (<>) (All True) -- | Check whether all elements are 'True'. -- -- >>> run (repeat False) and -- False -- -- >>> run (repeat True) and -- ... diverges ... and :: M Bool Bool and = all id -- | Check whether any elements are 'True'. -- -- >>> run (True : repeat False) or -- True -- >>> run (repeat False) or -- ... diverges ... or :: M Bool Bool or = any id -- | Check whether an element is fed into the fold. -- -- >>> run [1, 2, 3] (elem 3) -- True -- -- >>> run [] (elem 1) -- False elem :: Eq a => a -> M a Bool elem a = any (== a) -- | Check whther an element isn't fed into the fold. -- >>> run [1, 2, 3] (notElem 3) -- False -- -- >>> run [] (notElem 1) -- True notElem :: Eq a => a -> M a Bool notElem a = all (/= a) -- | Find the first element for which a predicate holds. -- -- >>> run [1, 2, 3, 4] (find even) -- Just 2 -- -- >>> run [1, 2, 3, 4] (find (> 4)) -- Nothing find :: (a -> Bool) -> M a (Maybe a) find p = M getFirst to (<>) (First Nothing) where to a = First $ if p a then Just a else Nothing -- | Grab the first inputted element. -- -- >>> run [1 ..] head -- Just 1 -- -- >>> run [] head -- Nothing head :: M a (Maybe a) head = M getFirst (First . Just) (<>) (First Nothing) -- | Check whether a fold was fed any elements. -- -- >>> run [] null -- True -- -- >>> run [1..] null -- False null :: M a Bool null = M id (const False) (&&) True -- | Occasionally we want to use a short-circuiting fold with other, -- nonlazy folds. This function drops laziness on the floor for a @L'@ -- fold. This is dangerous because it can potentially effect -- termination behavior. -- -- >>> run (repeat False) and -- False -- -- >>> run (repeat False) (strictify and) -- ... diverges ... -- -- This is generally an advantage when we want to combine a monoidal -- fold with a left one. -- -- >>> run [1.0, 2, 3, 4] $ (/) <$> strictify head <*> maximum -- 0.25 strictify :: M a b -> L' a b strictify (M p to m z) = L' p (\z a -> z `m` to a) z