{-# LANGUAGE CPP #-} {-# LANGUAGE UndecidableInstances, TypeOperators, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-} #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702 && __GLASGOW_HASKELL__ < 710 {-# LANGUAGE Trustworthy #-} #endif ----------------------------------------------------------------------------- -- | -- 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, all, elem, filter, concatMap, and, or , sum, product, notElem, replicate, cycle, repeat #if __GLASGOW_HASKELL__ >= 710 , foldMap #endif ) import Control.Applicative import Control.Monad (MonadPlus) import Data.Generator #if __GLASGOW_HASKELL__ < 710 import Data.Monoid (Monoid(..)) #endif import Data.Semigroup (Sum(..), Product(..), All(..), Any(..), WrappedMonoid(..)) import Data.Semigroup.Applicative (Traversal(..)) import Data.Semigroup.Alternative (Alternate(..)) import Data.Semigroup.Monad (Action(..)) import Data.Semigroup.MonadPlus (MonadSum(..)) import Data.Semigroup.Reducer (Reducer(..)) -- | 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 getAlternate {-# 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 'WrappedMonoid' monoid. A specialized version of its namesake from "Data.Foldable" -- -- @ -- 'mapReduceWith' 'unwrapMonoid' -- @ foldMap :: (Monoid m, Generator c) => (Elem c -> m) -> c -> m foldMap = mapReduceWith unwrapMonoid {-# 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 'WrappedMonoid' monoid. A specialized version of its namesake from "Data.Foldable" -- -- @ -- 'reduceWith' 'unwrapMonoid' -- @ fold :: (Monoid m, Generator c, Elem c ~ m) => c -> m fold = reduceWith unwrapMonoid {-# 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, Reducer (Elem c) m, Monoid 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, Reducer (Elem c) m, Monoid 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 #-} -}