{-# 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 ( module Data.Generator -- * 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.Applicative import Data.Monoid.Self import Data.Monoid.Monad -- | 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 #-}