monoids-0.1.25: Data/Generator/Combinators.hs
{-# 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 #-}