{-# LANGUAGE UndecidableInstances, TypeOperators, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Generator.Combinators -- Copyright : (c) Edward Kmett 2009 -- License : BSD-style -- Maintainer : ekmett@gmail.com -- Stability : experimental -- Portability : non-portable (type families, MPTCs) -- -- Utilities for working with Monoids that conflict with names from the "Prelude", -- "Data.Foldable", "Control.Monad" or elsewhere. Intended to be imported qualified. -- -- > import Data.Generator.Combinators as Generator -- ----------------------------------------------------------------------------- module Data.Generator.Combinators ( -- * Monadic Reduction mapM_ , forM_ , msum -- * Applicative Reduction , traverse_ , for_ , asum -- * Logical Reduction , and , or , any , all -- * Monoidal Reduction , foldMap , fold , toList -- * List-Like Reduction , concatMap , elem , filter , filterWith , find , sum , product , notElem ) where import Prelude hiding (mapM_, any, elem, filter, concatMap, and, or, all, sum, product, notElem, replicate, cycle, repeat) import Control.Applicative import Control.Monad (MonadPlus) import Data.Generator import Data.Monoid (Monoid, mempty, Sum(..), Product(..), All(..), Any(..), First(..)) import Data.Monoid.Applicative (Alt(..), Traversal(..)) import Data.Monoid.Self (Self(..)) import Data.Monoid.Monad (MonadSum(..), Action(..)) import Data.Monoid.Reducer (Reducer, unit) -- | Efficiently 'mapReduce' a 'Generator' using the 'Traversal' monoid. A specialized version of its namesake from "Data.Foldable" -- -- @ -- 'mapReduce' 'getTraversal' -- @ traverse_ :: (Generator c, Applicative f) => (Elem c -> f b) -> c -> f () traverse_ = mapReduceWith getTraversal {-# INLINE traverse_ #-} -- | Convenience function as found in "Data.Foldable" -- -- @ -- 'flip' 'traverse_' -- @ for_ :: (Generator c, Applicative f) => c -> (Elem c -> f b) -> f () for_ = flip traverse_ {-# INLINE for_ #-} -- | The sum of a collection of actions, generalizing 'concat' -- -- @ -- 'reduceWith' 'getAlt' -- @ asum :: (Generator c, Alternative f, f a ~ Elem c) => c -> f a asum = reduceWith getAlt {-# INLINE asum #-} -- | Efficiently 'mapReduce' a 'Generator' using the 'Action' monoid. A specialized version of its namesake from "Data.Foldable" and "Control.Monad" -- -- @ -- 'mapReduceWith' 'getAction' -- @ mapM_ :: (Generator c, Monad m) => (Elem c -> m b) -> c -> m () mapM_ = mapReduceWith getAction {-# INLINE mapM_ #-} -- | Convenience function as found in "Data.Foldable" and "Control.Monad" -- -- @ -- 'flip' 'mapM_' -- @ forM_ :: (Generator c, Monad m) => c -> (Elem c -> m b) -> m () forM_ = flip mapM_ {-# INLINE forM_ #-} -- | The sum of a collection of actions, generalizing 'concat' -- -- @ -- 'reduceWith' 'getMonadSum' -- @ msum :: (Generator c, MonadPlus m, m a ~ Elem c) => c -> m a msum = reduceWith getMonadSum {-# INLINE msum #-} -- | Efficiently 'mapReduce' a 'Generator' using the 'Self' monoid. A specialized version of its namesake from "Data.Foldable" -- -- @ -- 'mapReduceWith' 'getSelf' -- @ foldMap :: (Monoid m, Generator c) => (Elem c -> m) -> c -> m foldMap = mapReduceWith getSelf {-# INLINE foldMap #-} -- | Type specialization of "foldMap" above concatMap :: Generator c => (Elem c -> [b]) -> c -> [b] concatMap = foldMap {-# INLINE concatMap #-} -- | Efficiently 'reduce' a 'Generator' using the 'Self' monoid. A specialized version of its namesake from "Data.Foldable" -- -- @ -- 'reduceWith' 'getSelf' -- @ fold :: (Monoid m, Generator c, Elem c ~ m) => c -> m fold = reduceWith getSelf {-# INLINE fold #-} -- | Convert any 'Generator' to a list of its contents. Specialization of 'reduce' toList :: Generator c => c -> [Elem c] toList = reduce {-# INLINE toList #-} -- | Efficiently 'reduce' a 'Generator' that contains values of type 'Bool' -- -- @ -- 'reduceWith' 'getAll' -- @ and :: (Generator c, Elem c ~ Bool) => c -> Bool and = reduceWith getAll {-# INLINE and #-} -- | Efficiently 'reduce' a 'Generator' that contains values of type 'Bool' -- -- @ -- 'reduceWith' 'getAny' -- @ or :: (Generator c, Elem c ~ Bool) => c -> Bool or = reduceWith getAny {-# INLINE or #-} -- | Efficiently 'mapReduce' any 'Generator' checking to see if any of its values match the supplied predicate -- -- @ -- 'mapReduceWith' 'getAny' -- @ any :: Generator c => (Elem c -> Bool) -> c -> Bool any = mapReduceWith getAny {-# INLINE any #-} -- | Efficiently 'mapReduce' any 'Generator' checking to see if all of its values match the supplied predicate -- -- @ -- 'mapReduceWith' 'getAll' -- @ all :: Generator c => (Elem c -> Bool) -> c -> Bool all = mapReduceWith getAll {-# INLINE all #-} -- | Efficiently sum over the members of any 'Generator' -- -- @ -- 'reduceWith' 'getSum' -- @ sum :: (Generator c, Num (Elem c)) => c -> Elem c sum = reduceWith getSum {-# INLINE sum #-} -- | Efficiently take the product of every member of a 'Generator' -- -- @ -- 'reduceWith' 'getProduct' -- @ product :: (Generator c, Num (Elem c)) => c -> Elem c product = reduceWith getProduct {-# INLINE product #-} -- | Check to see if 'any' member of the 'Generator' matches the supplied value elem :: (Generator c, Eq (Elem c)) => Elem c -> c -> Bool elem = any . (==) {-# INLINE elem #-} -- | Check to make sure that the supplied value is not a member of the 'Generator' notElem :: (Generator c, Eq (Elem c)) => Elem c -> c -> Bool notElem x = not . elem x {-# INLINE notElem #-} -- | Efficiently 'mapReduce' a subset of the elements in a 'Generator' filter :: (Generator c, Elem c `Reducer` m) => (Elem c -> Bool) -> c -> m filter p = foldMap f where f x | p x = unit x | otherwise = mempty {-# INLINE filter #-} -- | Allows idiomatic specialization of filter by proving a function that will be used to transform the output filterWith :: (Generator c, Elem c `Reducer` m) => (m -> n) -> (Elem c -> Bool) -> c -> n filterWith f p = f . filter p {-# INLINE filterWith #-} -- | A specialization of 'filter' using the 'First' 'Monoid', analogous to 'Data.List.find' -- -- @ -- 'filterWith' 'getFirst' -- @ find :: Generator c => (Elem c -> Bool) -> c -> Maybe (Elem c) find = filterWith getFirst {-# INLINE find #-}