reducers 0.3.0.1 → 3.0
raw patch · 29 files changed
+1321/−1320 lines, 29 filesdep ~comonaddep ~keysdep ~pointed
Dependency ranges changed: comonad, keys, pointed, semigroupoids
Files
- Data/Generator.hs +0/−204
- Data/Generator/Combinators.hs +0/−233
- Data/Semigroup/Alt.hs +0/−38
- Data/Semigroup/Alternative.hs +0/−39
- Data/Semigroup/Applicative.hs +0/−61
- Data/Semigroup/Apply.hs +0/−55
- Data/Semigroup/Generator.hs +0/−71
- Data/Semigroup/Instances.hs +0/−8
- Data/Semigroup/Monad.hs +0/−61
- Data/Semigroup/MonadPlus.hs +0/−39
- Data/Semigroup/Reducer.hs +0/−221
- Data/Semigroup/Reducer/With.hs +0/−59
- Data/Semigroup/Self.hs +0/−51
- Data/Semigroup/Union.hs +0/−174
- reducers.cabal +7/−6
- src/Data/Generator.hs +204/−0
- src/Data/Generator/Combinators.hs +233/−0
- src/Data/Semigroup/Alt.hs +38/−0
- src/Data/Semigroup/Alternative.hs +39/−0
- src/Data/Semigroup/Applicative.hs +61/−0
- src/Data/Semigroup/Apply.hs +55/−0
- src/Data/Semigroup/Generator.hs +71/−0
- src/Data/Semigroup/Instances.hs +8/−0
- src/Data/Semigroup/Monad.hs +61/−0
- src/Data/Semigroup/MonadPlus.hs +39/−0
- src/Data/Semigroup/Reducer.hs +221/−0
- src/Data/Semigroup/Reducer/With.hs +59/−0
- src/Data/Semigroup/Self.hs +51/−0
- src/Data/Semigroup/Union.hs +174/−0
− Data/Generator.hs
@@ -1,204 +0,0 @@-{-# LANGUAGE UndecidableInstances, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, CPP #-}---------------------------------------------------------------------------------- |--- Module : Data.Generator--- Copyright : (c) Edward Kmett 2009--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : portable------ A 'Generator' @c@ is a possibly-specialized container, which contains values of --- type 'Elem' @c@, and which knows how to efficiently apply a 'Reducer' to extract--- an answer.------ Since a 'Generator' is not polymorphic in its contents, it is more specialized--- than "Data.Foldable.Foldable", and a 'Reducer' may supply efficient left-to-right--- and right-to-left reduction strategies that a 'Generator' may avail itself of.--------------------------------------------------------------------------------module Data.Generator- (- -- * Generators- Generator(..)- -- * Generator Transformers- , Keys(Keys, getKeys)- , Values(Values, getValues)- , Char8(Char8, getChar8)- -- * Combinators- , reduce- , mapReduceWith- , reduceWith- ) where--import Data.Monoid (Monoid, mappend, mempty)--import Data.Array -import Data.Text (Text)-import qualified Data.Text as Text-import qualified Data.ByteString as Strict (ByteString, foldl')-import qualified Data.ByteString.Char8 as Strict8 (foldl')-import qualified Data.ByteString.Lazy as Lazy (ByteString, toChunks)-import qualified Data.ByteString.Lazy.Char8 as Lazy8 (toChunks)-import Data.Word (Word8)-import Data.FingerTree (Measured, FingerTree)-import Data.Sequence (Seq)-import qualified Data.Set as Set-import Data.Set (Set)-import qualified Data.IntSet as IntSet-import Data.IntSet (IntSet)-import qualified Data.IntMap as IntMap-import Data.IntMap (IntMap)-import qualified Data.HashSet as HashSet-import Data.HashSet (HashSet)-import qualified Data.HashMap.Lazy as HashMap-import Data.HashMap.Lazy (HashMap)-import qualified Data.Map as Map-import Data.Map (Map)-import Data.List.NonEmpty (NonEmpty)-import qualified Data.List.NonEmpty as NonEmpty--- import Control.Parallel.Strategies (rseq, parMap)-import Data.Foldable (fold,foldMap)-import Data.Semigroup.Reducer---- | minimal definition 'mapReduce' or 'mapTo'-class Generator c where- type Elem c- mapReduce :: (Reducer e m, Monoid m) => (Elem c -> e) -> c -> m- mapTo :: (Reducer e m, Monoid m) => (Elem c -> e) -> m -> c -> m - mapFrom :: (Reducer e m, Monoid m) => (Elem c -> e) -> c -> m -> m-- mapReduce f = mapTo f mempty- mapTo f m = mappend m . mapReduce f- mapFrom f = mappend . mapReduce f---instance Generator Strict.ByteString where- type Elem Strict.ByteString = Word8- mapTo f = Strict.foldl' (\a -> snoc a . f)--instance Generator Lazy.ByteString where- type Elem Lazy.ByteString = Word8- -- mapReduce f = fold . parMap rseq (mapReduce f) . Lazy.toChunks- mapReduce f = fold . map (mapReduce f) . Lazy.toChunks--instance Generator Text where- type Elem Text = Char- mapTo f = Text.foldl' (\a -> snoc a . f)--instance Generator [c] where- type Elem [c] = c- mapReduce f = foldr (cons . f) mempty--instance Generator (NonEmpty c) where- type Elem (NonEmpty c) = c- mapReduce f = mapReduce f . NonEmpty.toList--instance Measured v e => Generator (FingerTree v e) where- type Elem (FingerTree v e) = e- mapReduce f = foldMap (unit . f)--instance Generator (Seq c) where- type Elem (Seq c) = c- mapReduce f = foldMap (unit . f)--instance Generator IntSet where- type Elem IntSet = Int- mapReduce f = mapReduce f . IntSet.toList--instance Generator (HashSet a) where- type Elem (HashSet a) = a- mapReduce f = mapReduce f . HashSet.toList--instance Generator (Set a) where- type Elem (Set a) = a- mapReduce f = mapReduce f . Set.toList--instance Generator (IntMap v) where- type Elem (IntMap v) = (Int,v)- mapReduce f = mapReduce f . IntMap.toList--instance Generator (Map k v) where- type Elem (Map k v) = (k,v) - mapReduce f = mapReduce f . Map.toList--instance Generator (HashMap k v) where- type Elem (HashMap k v) = (k, v)- mapReduce f = mapReduce f . HashMap.toList--instance Ix i => Generator (Array i e) where- type Elem (Array i e) = (i,e)- mapReduce f = mapReduce f . assocs---- | a 'Generator' transformer that asks only for the keys of an indexed container-newtype Keys c = Keys { getKeys :: c } --instance Generator (Keys (IntMap v)) where- type Elem (Keys (IntMap v)) = Int- mapReduce f = mapReduce f . IntMap.keys . getKeys--instance Generator (Keys (Map k v)) where- type Elem (Keys (Map k v)) = k- mapReduce f = mapReduce f . Map.keys . getKeys--instance Ix i => Generator (Keys (Array i e)) where- type Elem (Keys (Array i e)) = i- mapReduce f = mapReduce f . range . bounds . getKeys---- | a 'Generator' transformer that asks only for the values contained in an indexed container-newtype Values c = Values { getValues :: c } --instance Generator (Values (IntMap v)) where- type Elem (Values (IntMap v)) = v- mapReduce f = mapReduce f . IntMap.elems . getValues--instance Generator (Values (Map k v)) where- type Elem (Values (Map k v)) = v- mapReduce f = mapReduce f . Map.elems . getValues--instance Ix i => Generator (Values (Array i e)) where- type Elem (Values (Array i e)) = e- mapReduce f = mapReduce f . elems . getValues---- | a 'Generator' transformer that treats 'Word8' as 'Char'--- This lets you use a 'ByteString' as a 'Char' source without going through a 'Monoid' transformer like 'UTF8'-newtype Char8 c = Char8 { getChar8 :: c } --instance Generator (Char8 Strict.ByteString) where- type Elem (Char8 Strict.ByteString) = Char- mapTo f m = Strict8.foldl' (\a -> snoc a . f) m . getChar8--instance Generator (Char8 Lazy.ByteString) where- type Elem (Char8 Lazy.ByteString) = Char- mapReduce f = fold . map (mapReduce f . Char8) . Lazy8.toChunks . getChar8---- | Apply a 'Reducer' directly to the elements of a 'Generator'-reduce :: (Generator c, Reducer (Elem c) m, Monoid m) => c -> m-reduce = mapReduce id-{-# SPECIALIZE reduce :: (Reducer Word8 m, Monoid m) => Strict.ByteString -> m #-}-{-# SPECIALIZE reduce :: (Reducer Word8 m, Monoid m) => Lazy.ByteString -> m #-}-{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Char8 Strict.ByteString -> m #-}-{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Char8 Lazy.ByteString -> m #-}-{-# SPECIALIZE reduce :: (Reducer c m, Monoid m) => [c] -> m #-}-{-# SPECIALIZE reduce :: (Generator (FingerTree v e), Reducer e m, Monoid m) => FingerTree v e -> m #-}-{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Text -> m #-}-{-# SPECIALIZE reduce :: (Reducer e m, Monoid m) => Seq e -> m #-}-{-# SPECIALIZE reduce :: (Reducer Int m, Monoid m) => IntSet -> m #-}-{-# SPECIALIZE reduce :: (Reducer a m, Monoid m) => Set a -> m #-}-{-# SPECIALIZE reduce :: (Reducer a m, Monoid m) => HashSet a -> m #-}-{-# SPECIALIZE reduce :: (Reducer (Int,v) m, Monoid m) => IntMap v -> m #-}-{-# SPECIALIZE reduce :: (Reducer (k,v) m, Monoid m) => Map k v -> m #-}-{-# SPECIALIZE reduce :: (Reducer (k,v) m, Monoid m) => HashMap k v -> m #-}-{-# SPECIALIZE reduce :: (Reducer Int m, Monoid m) => Keys (IntMap v) -> m #-}-{-# SPECIALIZE reduce :: (Reducer k m, Monoid m) => Keys (Map k v) -> m #-}-{-# SPECIALIZE reduce :: (Reducer v m, Monoid m) => Values (IntMap v) -> m #-}-{-# SPECIALIZE reduce :: (Reducer v m, Monoid m) => Values (Map k v) -> m #-}--mapReduceWith :: (Generator c, Reducer e m, Monoid m) => (m -> n) -> (Elem c -> e) -> c -> n-mapReduceWith f g = f . mapReduce g-{-# INLINE mapReduceWith #-}--reduceWith :: (Generator c, Reducer (Elem c) m, Monoid m) => (m -> n) -> c -> n-reduceWith f = f . reduce-{-# INLINE reduceWith #-}
− Data/Generator/Combinators.hs
@@ -1,233 +0,0 @@-{-# 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, all, elem, filter, concatMap, and, or- , sum, product, notElem, replicate, cycle, repeat- )-import Control.Applicative-import Control.Monad (MonadPlus)-import Data.Generator-import Data.Monoid (Monoid(..))-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 #-}---}
− Data/Semigroup/Alt.hs
@@ -1,38 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Alt--- Copyright : (c) Edward Kmett 2009-2011--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ A semigroup for working 'Alt' or 'Plus' -----------------------------------------------------------------------------------module Data.Semigroup.Alt- ( Alter(..)- ) where--import Data.Functor.Plus-import Data.Monoid (Monoid(..))-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'Alter' turns any 'Alt' instance into a 'Semigroup'.--newtype Alter f a = Alter { getAlter :: f a } - deriving (Functor,Alt,Plus)--instance Alt f => Semigroup (Alter f a) where- Alter a <> Alter b = Alter (a <!> b) --instance Plus f => Monoid (Alter f a) where- mempty = zero- Alter a `mappend` Alter b = Alter (a <!> b) --instance Alt f => Reducer (f a) (Alter f a) where- unit = Alter
− Data/Semigroup/Alternative.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Alternative--- Copyright : (c) Edward Kmett 2009-2011--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ A semigroup for working with 'Alternative' 'Functor's.-----------------------------------------------------------------------------------module Data.Semigroup.Alternative- ( Alternate(..)- ) where--import Control.Applicative-import Data.Monoid (Monoid(..))-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'Alternate' turns any 'Alternative' instance into a 'Monoid'.--newtype Alternate f a = Alternate { getAlternate :: f a } - deriving (Functor,Applicative,Alternative)--instance Alternative f => Semigroup (Alternate f a) where- Alternate a <> Alternate b = Alternate (a <|> b)- -instance Alternative f => Monoid (Alternate f a) where- mempty = empty - Alternate a `mappend` Alternate b = Alternate (a <|> b) --instance Alternative f => Reducer (f a) (Alternate f a) where- unit = Alternate -
− Data/Semigroup/Applicative.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Applicative--- Copyright : (c) Edward Kmett 2009--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ Semigroups for working with 'Applicative' 'Functor's.-----------------------------------------------------------------------------------module Data.Semigroup.Applicative - ( Traversal(..)- , Ap(..)- ) where--import Control.Applicative-import Data.Monoid (Monoid(..))-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'Traversal' uses an glues together 'Applicative' actions with (*>)--- in the manner of 'traverse_' from "Data.Foldable". Any values returned by --- reduced actions are discarded.-newtype Traversal f = Traversal { getTraversal :: f () } --instance Applicative f => Semigroup (Traversal f) where- Traversal a <> Traversal b = Traversal (a *> b)--instance Applicative f => Monoid (Traversal f) where- mempty = Traversal (pure ())- Traversal a `mappend` Traversal b = Traversal (a *> b)--instance Applicative f => Reducer (f a) (Traversal f) where- unit = Traversal . (() <$)- a `cons` Traversal b = Traversal (a *> b)- Traversal a `snoc` b = Traversal (() <$ (a *> b))---- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()--- A rewrite rule automatically applies this when possible-snocTraversal :: Reducer (f ()) (Traversal f) => Traversal f -> f () -> Traversal f-snocTraversal a = (<>) a . Traversal-{-# RULES "unitTraversal" unit = Traversal #-}-{-# RULES "snocTraversal" snoc = snocTraversal #-}--newtype Ap f m = Ap { getApp :: f m } - deriving (Functor,Applicative)--instance (Applicative f, Semigroup m) => Semigroup (Ap f m) where- (<>) = liftA2 (<>)--instance (Applicative f, Monoid m) => Monoid (Ap f m) where- mempty = pure mempty- mappend = liftA2 mappend--instance (Applicative f, Reducer c m) => Reducer (f c) (Ap f m) where- unit = fmap unit . Ap
− Data/Semigroup/Apply.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Apply--- Copyright : (c) Edward Kmett 2009-2011--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ Semigroups for working with 'Apply'-----------------------------------------------------------------------------------module Data.Semigroup.Apply- ( Trav(..)- , App(..)- ) where--import Data.Functor-import Data.Functor.Apply-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'Trav' uses an glues together 'Applicative' actions with (*>)--- in the manner of 'traverse_' from "Data.Foldable". Any values returned by --- reduced actions are discarded.-newtype Trav f = Trav { getTrav :: f () } --instance Apply f => Semigroup (Trav f) where- Trav a <> Trav b = Trav (a .> b)--instance Apply f => Reducer (f a) (Trav f) where- unit = Trav . (() <$)- a `cons` Trav b = Trav (a .> b)- Trav a `snoc` b = Trav (() <$ (a .> b))---- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()--- A rewrite rule automatically applies this when possible-snocTrav :: Reducer (f ()) (Trav f) => Trav f -> f () -> Trav f-snocTrav a = (<>) a . Trav-{-# RULES "unitTrav" unit = Trav #-}-{-# RULES "snocTrav" snoc = snocTrav #-}---- | A 'App' turns any 'Apply' wrapped around a 'Semigroup' into a 'Semigroup'--newtype App f m = App { getApp :: f m } - deriving (Functor,Apply)--instance (Apply f, Semigroup m) => Semigroup (App f m) where- (<>) = liftF2 (<>)--instance (Apply f, Reducer c m) => Reducer (f c) (App f m) where- unit = fmap unit . App
− Data/Semigroup/Generator.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE UndecidableInstances, TypeOperators, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, CPP #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Generator--- Copyright : (c) Edward Kmett 2009--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : portable------ A 'Generator1' @c@ is a possibly-specialized container, which contains values of --- type 'Elem' @c@, and which knows how to efficiently apply a 'Reducer' to extract--- an answer.------ 'Generator1' is to 'Generator' as 'Foldable1' is to 'Foldable'.--------------------------------------------------------------------------------module Data.Semigroup.Generator- (- -- * Generators- Generator1(..)- -- * Combinators- , reduce1- , mapReduceWith1- , reduceWith1- ) where---- import Data.Monoid (Monoid(..))--- import Data.Foldable (fold,foldMap)-import Data.List.NonEmpty-import Data.Semigroup (Semigroup(..)) -- , WrappedMonoid(..))-import Data.Semigroup.Foldable-import Data.Semigroup.Reducer-import Data.Generator---- | minimal definition 'mapReduce1' or 'mapTo1'-class Generator c => Generator1 c where- mapReduce1 :: Reducer e m => (Elem c -> e) -> c -> m- mapTo1 :: Reducer e m => (Elem c -> e) -> m -> c -> m - mapFrom1 :: Reducer e m => (Elem c -> e) -> c -> m -> m-- mapTo1 f m = (<>) m . mapReduce1 f- mapFrom1 f = (<>) . mapReduce1 f--instance Generator1 (NonEmpty e) where- mapReduce1 f = foldMap1 (unit . f)--{--mapReduceDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> c -> m-mapReduceDefault f = unwrapMonoid . mapReduce1 f --mapToDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> m -> c -> m-mapToDefault f = unwrapMonoid . mapTo1 f --mapFromDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> m -> c -> m-mapFromDefault f = unwrapMonoid . mapFrom1 f --}---- | Apply a 'Reducer' directly to the elements of a 'Generator'-reduce1 :: (Generator1 c, Reducer (Elem c) m) => c -> m-reduce1 = mapReduce1 id-{-# SPECIALIZE reduce1 :: Reducer a m => NonEmpty a -> m #-}--mapReduceWith1 :: (Generator1 c, Reducer e m) => (m -> n) -> (Elem c -> e) -> c -> n-mapReduceWith1 f g = f . mapReduce1 g-{-# INLINE mapReduceWith1 #-}--reduceWith1 :: (Generator1 c, Reducer (Elem c) m) => (m -> n) -> c -> n-reduceWith1 f = f . reduce1-{-# INLINE reduceWith1 #-}
− Data/Semigroup/Instances.hs
@@ -1,8 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Data.Semigroup.Instances where--import Data.FingerTree-import Data.Semigroup--instance Measured v a => Semigroup (FingerTree v a) where- (<>) = mappend
− Data/Semigroup/Monad.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Monad--- Copyright : (c) Edward Kmett 2009--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ Semigroups for working with 'Monad's.-----------------------------------------------------------------------------------module Data.Semigroup.Monad- ( Action(..)- , Mon(..)- ) where--import Control.Monad (liftM, liftM2)-import Data.Monoid (Monoid(..))-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'Action' uses an glues together monadic actions with (>>)--- in the manner of 'mapM_' from "Data.Foldable". Any values returned by --- reduced actions are discarded.-newtype Action f = Action { getAction :: f () } --instance Monad f => Semigroup (Action f) where- Action a <> Action b = Action (a >> b)--instance Monad f => Monoid (Action f) where- mempty = Action (return ())- Action a `mappend` Action b = Action (a >> b)--instance Monad f => Reducer (f a) (Action f) where- unit a = Action (a >> return ())- a `cons` Action b = Action (a >> b)- Action a `snoc` b = Action (a >> b >> return ())---- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()--- A rewrite rule automatically applies this when possible-snocAction :: Reducer (f ()) (Action f) => Action f -> f () -> Action f-snocAction a = (<>) a . Action-{-# RULES "unitAction" unit = Action #-}-{-# RULES "snocAction" snoc = snocAction #-}--newtype Mon f m = Mon { getMon :: f m } - deriving (Monad)--instance (Monad f, Semigroup m) => Semigroup (Mon f m) where- (<>) = liftM2 (<>)--instance (Monad f, Monoid m) => Monoid (Mon f m) where- mempty = return mempty- mappend = liftM2 mappend--instance (Monad f, Reducer c m) => Reducer (f c) (Mon f m) where- unit = liftM unit . Mon
− Data/Semigroup/MonadPlus.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.MonadPlus--- Copyright : (c) Edward Kmett 2009-2011--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ A semigroup for working with instances of 'MonadPlus'-----------------------------------------------------------------------------------module Data.Semigroup.MonadPlus- ( MonadSum(..)- ) where--import Control.Monad (MonadPlus(..))-import Data.Monoid (Monoid(..))-import Data.Semigroup (Semigroup(..))-import Data.Semigroup.Reducer (Reducer(..))---- | A 'MonadSum' turns any 'MonadPlus' instance into a 'Monoid'.--newtype MonadSum f a = MonadSum { getMonadSum :: f a } - deriving (Monad,MonadPlus)--instance MonadPlus f => Semigroup (MonadSum f a) where- MonadSum a <> MonadSum b = MonadSum (mplus a b)- -instance MonadPlus f => Monoid (MonadSum f a) where- mempty = mzero- MonadSum a `mappend` MonadSum b = MonadSum (mplus a b) --instance MonadPlus f => Reducer (f a) (MonadSum f a) where- unit = MonadSum -
− Data/Semigroup/Reducer.hs
@@ -1,221 +0,0 @@-{-# LANGUAGE UndecidableInstances , FlexibleContexts , MultiParamTypeClasses , FlexibleInstances , GeneralizedNewtypeDeriving, TypeOperators, ScopedTypeVariables, CPP #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Reducer--- Copyright : (c) Edward Kmett 2009--- License : BSD3--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)------ A @c@-'Reducer' is a 'Semigroup' with a canonical mapping from @c@ to the Semigroup.-----------------------------------------------------------------------------------module Data.Semigroup.Reducer- ( Reducer(..)- , foldMapReduce, foldMapReduce1- , foldReduce, foldReduce1- , pureUnit- , returnUnit- , Count(..)- ) where--import Control.Applicative--import qualified Data.Monoid as Monoid-import Data.Semigroup as Semigroup-import Data.Semigroup.Foldable-import Data.Semigroup.Instances ()-import Data.Hashable-import Data.Foldable-import Data.FingerTree--import qualified Data.Sequence as Seq-import Data.Sequence (Seq)-import qualified Data.Set as Set-import Data.Set (Set)-import qualified Data.IntSet as IntSet-import Data.IntSet (IntSet)-import qualified Data.IntMap as IntMap-import Data.IntMap (IntMap)-import qualified Data.Map as Map-import Data.Map (Map)--#ifdef LANGUAGE_DeriveDataTypeable-import Data.Data-#endif----import Text.Parsec.Prim---- | This type may be best read infix. A @c `Reducer` m@ is a 'Semigroup' @m@ that maps--- values of type @c@ through @unit@ to values of type @m@. A @c@-'Reducer' may also--- supply operations which tack-on another @c@ to an existing 'Monoid' @m@ on the left--- or right. These specialized reductions may be more efficient in some scenarios--- and are used when appropriate by a 'Generator'. The names 'cons' and 'snoc' work--- by analogy to the synonymous operations in the list monoid.------ This class deliberately avoids functional-dependencies, so that () can be a @c@-Reducer--- for all @c@, and so many common reducers can work over multiple types, for instance,--- First and Last may reduce both @a@ and 'Maybe' @a@. Since a 'Generator' has a fixed element--- type, the input to the reducer is generally known and extracting from the monoid usually--- is sufficient to fix the result type. Combinators are available for most scenarios where--- this is not the case, and the few remaining cases can be handled by using an explicit --- type annotation.------ Minimal definition: 'unit' or 'snoc'-class Semigroup m => Reducer c m where- -- | Convert a value into a 'Semigroup'- unit :: c -> m - -- | Append a value to a 'Semigroup' for use in left-to-right reduction- snoc :: m -> c -> m- -- | Prepend a value onto a 'Semigroup' for use during right-to-left reduction- cons :: c -> m -> m -- snoc m = (<>) m . unit- cons = (<>) . unit---- | Apply a 'Reducer' to a 'Foldable' container, after mapping the contents into a suitable form for reduction.-foldMapReduce :: (Foldable f, Monoid m, Reducer e m) => (a -> e) -> f a -> m-foldMapReduce f = foldMap (unit . f)--foldMapReduce1 :: (Foldable1 f, Reducer e m) => (a -> e) -> f a -> m-foldMapReduce1 f = foldMap1 (unit . f)---- | Apply a 'Reducer' to a 'Foldable' mapping each element through 'unit'-foldReduce :: (Foldable f, Monoid m, Reducer e m) => f e -> m-foldReduce = foldMap unit---- | Apply a 'Reducer' to a 'Foldable1' mapping each element through 'unit'-foldReduce1 :: (Foldable1 f, Reducer e m) => f e -> m-foldReduce1 = foldMap1 unit--returnUnit :: (Monad m, Reducer c n) => c -> m n -returnUnit = return . unit--pureUnit :: (Applicative f, Reducer c n) => c -> f n-pureUnit = pure . unit--newtype Count = Count { getCount :: Int } deriving - ( Eq, Ord, Show, Read-#ifdef LANGUAGE_DeriveDataTypeable- , Data, Typeable-#endif- )--instance Hashable Count where- hash = hash . getCount- hashWithSalt n = hashWithSalt n . getCount--instance Semigroup Count where- Count a <> Count b = Count (a + b)- times1p n (Count a) = Count $ (fromIntegral n + 1) * a--instance Monoid Count where- mempty = Count 0- Count a `mappend` Count b = Count (a + b)--instance Reducer a Count where- unit _ = Count 1- Count n `snoc` _ = Count (n + 1)- _ `cons` Count n = Count (n + 1)- -instance (Reducer c m, Reducer c n) => Reducer c (m,n) where- unit x = (unit x,unit x)- (m,n) `snoc` x = (m `snoc` x, n `snoc` x)- x `cons` (m,n) = (x `cons` m, x `cons` n)--instance (Reducer c m, Reducer c n, Reducer c o) => Reducer c (m,n,o) where- unit x = (unit x,unit x, unit x)- (m,n,o) `snoc` x = (m `snoc` x, n `snoc` x, o `snoc` x)- x `cons` (m,n,o) = (x `cons` m, x `cons` n, x `cons` o)--instance (Reducer c m, Reducer c n, Reducer c o, Reducer c p) => Reducer c (m,n,o,p) where- unit x = (unit x,unit x, unit x, unit x)- (m,n,o,p) `snoc` x = (m `snoc` x, n `snoc` x, o `snoc` x, p `snoc` x)- x `cons` (m,n,o,p) = (x `cons` m, x `cons` n, x `cons` o, x `cons` p)--instance Reducer c [c] where- unit = return- cons = (:)- xs `snoc` x = xs ++ [x]--instance Reducer c () where- unit _ = ()- _ `snoc` _ = ()- _ `cons` _ = ()--instance Reducer Bool Any where- unit = Any--instance Reducer Bool All where- unit = All--instance Reducer (a -> a) (Endo a) where- unit = Endo--instance Semigroup a => Reducer a (Dual a) where- unit = Dual- -instance Num a => Reducer a (Sum a) where- unit = Sum--instance Num a => Reducer a (Product a) where- unit = Product--instance Ord a => Reducer a (Min a) where- unit = Min--instance Ord a => Reducer a (Max a) where- unit = Max--instance Reducer (Maybe a) (Monoid.First a) where- unit = Monoid.First--instance Reducer a (Semigroup.First a) where- unit = Semigroup.First--instance Reducer (Maybe a) (Monoid.Last a) where- unit = Monoid.Last--instance Reducer a (Semigroup.Last a) where- unit = Semigroup.Last--instance Measured v a => Reducer a (FingerTree v a) where- unit = singleton- cons = (<|)- snoc = (|>) ----instance (Stream s m t, Reducer c a) => Reducer c (ParsecT s u m a) where--- unit = return . unit--instance Reducer a (Seq a) where- unit = Seq.singleton- cons = (Seq.<|)- snoc = (Seq.|>)--instance Reducer Int IntSet where- unit = IntSet.singleton- cons = IntSet.insert- snoc = flip IntSet.insert -- left bias irrelevant--instance Ord a => Reducer a (Set a) where- unit = Set.singleton- cons = Set.insert- -- pedantic about order in case 'Eq' doesn't implement structural equality- snoc s m | Set.member m s = s - | otherwise = Set.insert m s--instance Reducer (Int, v) (IntMap v) where- unit = uncurry IntMap.singleton- cons = uncurry IntMap.insert- snoc = flip . uncurry . IntMap.insertWith $ const id--instance Ord k => Reducer (k, v) (Map k v) where- unit = uncurry Map.singleton- cons = uncurry Map.insert- snoc = flip . uncurry . Map.insertWith $ const id--instance Monoid m => Reducer m (WrappedMonoid m) where- unit = WrapMonoid
− Data/Semigroup/Reducer/With.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE UndecidableInstances, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Reducer.With--- Copyright : (c) Edward Kmett 2009-2011--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : non-portable (MPTCs)-----------------------------------------------------------------------------------module Data.Semigroup.Reducer.With- ( WithReducer(..)- ) where--import Control.Applicative-import Data.FingerTree-import Data.Foldable-import Data.Traversable-import Data.Hashable-import Data.Monoid-import Data.Semigroup.Reducer-import Data.Semigroup.Foldable-import Data.Semigroup.Traversable-import Data.Semigroup.Instances ()---- | If @m@ is a @c@-"Reducer", then m is @(c `WithReducer` m)@-"Reducer"--- This can be used to quickly select a "Reducer" for use as a 'FingerTree'--- 'measure'.--newtype WithReducer m c = WithReducer { withoutReducer :: c } - deriving (Eq, Ord, Show, Read)--instance Hashable c => Hashable (WithReducer m c) where- hash = hash . withoutReducer- hashWithSalt n = hashWithSalt n . withoutReducer--instance Functor (WithReducer m) where- fmap f = WithReducer . f . withoutReducer--instance Foldable (WithReducer m) where- foldMap f = f . withoutReducer--instance Traversable (WithReducer m) where- traverse f (WithReducer a) = WithReducer <$> f a--instance Foldable1 (WithReducer m) where- foldMap1 f = f . withoutReducer--instance Traversable1 (WithReducer m) where- traverse1 f (WithReducer a) = WithReducer <$> f a--instance Reducer c m => Reducer (WithReducer m c) m where- unit = unit . withoutReducer --instance (Monoid m, Reducer c m) => Measured m (WithReducer m c) where- measure = unit . withoutReducer
− Data/Semigroup/Self.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}---------------------------------------------------------------------------------- |--- Module : Data.Semigroup.Self--- Copyright : (c) Edward Kmett 2009--- License : BSD-style--- Maintainer : ekmett@gmail.com--- Stability : experimental--- Portability : portable------ A simple 'Monoid' transformer that takes a 'Monoid' m and produces a new @m@-Reducer named 'Self' @m@--- --- This is useful when you have a generator that already contains monoidal values or someone supplies--- the map to the monoid in the form of a function rather than as a "Reducer" instance. You can just--- @'getSelf' . `reduce`@ or @'getSelf' . 'mapReduce' f@ in those scenarios. These behaviors are encapsulated --- into the 'fold' and 'foldMap' combinators in "Data.Monoid.Combinators" respectively.-----------------------------------------------------------------------------------module Data.Semigroup.Self- ( Self(..)- ) where--import Control.Applicative-import Data.Foldable-import Data.Traversable-import Data.Semigroup-import Data.Semigroup.Foldable-import Data.Semigroup.Traversable-import Data.Semigroup.Reducer (Reducer(..))--newtype Self m = Self { getSelf :: m } deriving (Semigroup, Monoid)--instance Semigroup m => Reducer m (Self m) where- unit = Self--instance Functor Self where- fmap f (Self x) = Self (f x)--instance Foldable Self where- foldMap f (Self x) = f x--instance Traversable Self where- traverse f (Self x) = Self <$> f x--instance Foldable1 Self where- foldMap1 f (Self x) = f x--instance Traversable1 Self where- traverse1 f (Self x) = Self <$> f x
− Data/Semigroup/Union.hs
@@ -1,174 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving #-}-module Data.Semigroup.Union- ( module Data.Semigroup.Reducer- -- * Unions of Containers- , HasUnion(..)- , HasUnion0(..)- , Union(Union,getUnion)- -- * Unions of Containers of Semigroups- , HasUnionWith(..)- , HasUnionWith0(..)- , UnionWith(UnionWith,getUnionWith)- ) where--import qualified Data.HashMap.Lazy as HashMap-import Data.HashMap.Lazy (HashMap)--import qualified Data.IntMap as IntMap-import Data.IntMap (IntMap)--import qualified Data.IntSet as IntSet-import Data.IntSet (IntSet)--import qualified Data.HashSet as HashSet-import Data.HashSet (HashSet)--import qualified Data.Map as Map-import Data.Map (Map)--import qualified Data.Set as Set-import Data.Set (Set)--import qualified Data.List as List--import Data.Hashable-import Data.Functor-import Data.Foldable-import Data.Traversable-import Data.Semigroup-import Data.Semigroup.Foldable-import Data.Semigroup.Traversable-import Data.Semigroup.Reducer-import Data.Semigroup.Instances ()---- | A Container suitable for the 'Union' 'Monoid'-class HasUnion f where- union :: f -> f -> f--{-# SPECIALIZE union :: IntMap a -> IntMap a -> IntMap a #-}-{-# SPECIALIZE union :: Ord k => Map k a -> Map k a -> Map k a #-}-{-# SPECIALIZE union :: Eq a => [a] -> [a] -> [a] #-}-{-# SPECIALIZE union :: Ord a => Set a -> Set a -> Set a #-}-{-# SPECIALIZE union :: IntSet -> IntSet -> IntSet #-}-{-# SPECIALIZE union :: Eq a => HashSet a -> HashSet a -> HashSet a #-}-{-# SPECIALIZE union :: Eq k => HashMap k a -> HashMap k a -> HashMap k a #-}--class HasUnion f => HasUnion0 f where- empty :: f--instance HasUnion (IntMap a) where- union = IntMap.union--instance HasUnion0 (IntMap a) where- empty = IntMap.empty--instance (Eq k, Hashable k) => HasUnion (HashMap k a) where- union = HashMap.union--instance (Eq k, Hashable k) => HasUnion0 (HashMap k a) where- empty = HashMap.empty--instance Ord k => HasUnion (Map k a) where- union = Map.union--instance Ord k => HasUnion0 (Map k a) where- empty = Map.empty--instance Eq a => HasUnion [a] where- union = List.union--instance Eq a => HasUnion0 [a] where- empty = []--instance Ord a => HasUnion (Set a) where- union = Set.union--instance Ord a => HasUnion0 (Set a) where- empty = Set.empty--instance HasUnion IntSet where- union = IntSet.union--instance HasUnion0 IntSet where- empty = IntSet.empty--instance (Eq a, Hashable a) => HasUnion (HashSet a) where- union = HashSet.union--instance (Eq a, Hashable a) => HasUnion0 (HashSet a) where- empty = HashSet.empty----- | The 'Monoid' @('union','empty')@-newtype Union f = Union { getUnion :: f } - deriving (Eq,Ord,Show,Read)--instance HasUnion f => Semigroup (Union f) where- Union a <> Union b = Union (a `union` b)--instance HasUnion0 f => Monoid (Union f) where- Union a `mappend` Union b = Union (a `union` b)- mempty = Union empty--instance HasUnion f => Reducer f (Union f) where- unit = Union--instance Functor Union where- fmap f (Union a) = Union (f a)--instance Foldable Union where- foldMap f (Union a) = f a--instance Traversable Union where- traverse f (Union a) = Union <$> f a--instance Foldable1 Union where- foldMap1 f (Union a) = f a--instance Traversable1 Union where- traverse1 f (Union a) = Union <$> f a---- | Polymorphic containers that we can supply an operation to handle unions with-class Functor f => HasUnionWith f where- unionWith :: (a -> a -> a) -> f a -> f a -> f a--{-# SPECIALIZE unionWith :: (a -> a -> a) -> IntMap a -> IntMap a -> IntMap a #-}-{-# SPECIALIZE unionWith :: Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a #-}-{-# SPECIALIZE unionWith :: Eq k => (a -> a -> a) -> HashMap k a -> HashMap k a -> HashMap k a #-}--class HasUnionWith f => HasUnionWith0 f where- emptyWith :: f a --instance HasUnionWith IntMap where - unionWith = IntMap.unionWith--instance HasUnionWith0 IntMap where - emptyWith = IntMap.empty--instance Ord k => HasUnionWith (Map k) where - unionWith = Map.unionWith--instance Ord k => HasUnionWith0 (Map k) where - emptyWith = Map.empty---- TODO: add unionWith to unordered-containers----instance Eq k => HasUnionWith (HashMap k) where --- unionWith = HashMap.unionWith----instance Ord k => HasUnionWith0 (Map k) where --- emptyWith = Map.empty---- | The 'Monoid' @('unionWith mappend','empty')@ for containers full of monoids.-newtype UnionWith f m = UnionWith { getUnionWith :: f m } --instance (HasUnionWith f, Semigroup m) => Semigroup (UnionWith f m) where- UnionWith a <> UnionWith b = UnionWith (unionWith (<>) a b)--instance (HasUnionWith0 f, Monoid m) => Monoid (UnionWith f m) where- mempty = UnionWith emptyWith- UnionWith a `mappend` UnionWith b = UnionWith (unionWith mappend a b)--instance (HasUnionWith f, Semigroup m, Monoid m) => Reducer (f m) (UnionWith f m) where- unit = UnionWith-
reducers.cabal view
@@ -1,6 +1,6 @@ name: reducers category: Data, Math, Numerical, Semigroups-version: 0.3.0.1+version: 3.0 license: BSD3 cabal-version: >= 1.6 license-file: LICENSE@@ -20,6 +20,8 @@ location: git://github.com/ekmett/reducers.git library+ hs-source-dirs: src+ build-depends: base >= 4 && < 5, array >= 0.3 && < 0.5,@@ -31,12 +33,11 @@ text >= 0.11.1.5 && < 0.12, unordered-containers >= 0.1.4 && < 0.3, semigroups >= 0.8.3.1 && < 0.9,- semigroupoids >= 1.3.1.2 && < 1.4,- comonad >= 1.1.1.5 && < 1.2,- pointed >= 2.1.0.1 && < 2.2,- keys >= 2.1.3.1 && < 2.2+ semigroupoids >= 3.0 && < 3.1,+ comonad >= 3.0 && < 3.1,+ pointed >= 3.0 && < 3.1,+ keys >= 3.0 && < 3.1 --- parallel >= 3.2 && < 3.3, exposed-modules: Data.Generator Data.Generator.Combinators
+ src/Data/Generator.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE UndecidableInstances, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, CPP #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Generator+-- Copyright : (c) Edward Kmett 2009+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- A 'Generator' @c@ is a possibly-specialized container, which contains values of +-- type 'Elem' @c@, and which knows how to efficiently apply a 'Reducer' to extract+-- an answer.+--+-- Since a 'Generator' is not polymorphic in its contents, it is more specialized+-- than "Data.Foldable.Foldable", and a 'Reducer' may supply efficient left-to-right+-- and right-to-left reduction strategies that a 'Generator' may avail itself of.+-----------------------------------------------------------------------------++module Data.Generator+ (+ -- * Generators+ Generator(..)+ -- * Generator Transformers+ , Keys(Keys, getKeys)+ , Values(Values, getValues)+ , Char8(Char8, getChar8)+ -- * Combinators+ , reduce+ , mapReduceWith+ , reduceWith+ ) where++import Data.Monoid (Monoid, mappend, mempty)++import Data.Array +import Data.Text (Text)+import qualified Data.Text as Text+import qualified Data.ByteString as Strict (ByteString, foldl')+import qualified Data.ByteString.Char8 as Strict8 (foldl')+import qualified Data.ByteString.Lazy as Lazy (ByteString, toChunks)+import qualified Data.ByteString.Lazy.Char8 as Lazy8 (toChunks)+import Data.Word (Word8)+import Data.FingerTree (Measured, FingerTree)+import Data.Sequence (Seq)+import qualified Data.Set as Set+import Data.Set (Set)+import qualified Data.IntSet as IntSet+import Data.IntSet (IntSet)+import qualified Data.IntMap as IntMap+import Data.IntMap (IntMap)+import qualified Data.HashSet as HashSet+import Data.HashSet (HashSet)+import qualified Data.HashMap.Lazy as HashMap+import Data.HashMap.Lazy (HashMap)+import qualified Data.Map as Map+import Data.Map (Map)+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as NonEmpty+-- import Control.Parallel.Strategies (rseq, parMap)+import Data.Foldable (fold,foldMap)+import Data.Semigroup.Reducer++-- | minimal definition 'mapReduce' or 'mapTo'+class Generator c where+ type Elem c+ mapReduce :: (Reducer e m, Monoid m) => (Elem c -> e) -> c -> m+ mapTo :: (Reducer e m, Monoid m) => (Elem c -> e) -> m -> c -> m + mapFrom :: (Reducer e m, Monoid m) => (Elem c -> e) -> c -> m -> m++ mapReduce f = mapTo f mempty+ mapTo f m = mappend m . mapReduce f+ mapFrom f = mappend . mapReduce f+++instance Generator Strict.ByteString where+ type Elem Strict.ByteString = Word8+ mapTo f = Strict.foldl' (\a -> snoc a . f)++instance Generator Lazy.ByteString where+ type Elem Lazy.ByteString = Word8+ -- mapReduce f = fold . parMap rseq (mapReduce f) . Lazy.toChunks+ mapReduce f = fold . map (mapReduce f) . Lazy.toChunks++instance Generator Text where+ type Elem Text = Char+ mapTo f = Text.foldl' (\a -> snoc a . f)++instance Generator [c] where+ type Elem [c] = c+ mapReduce f = foldr (cons . f) mempty++instance Generator (NonEmpty c) where+ type Elem (NonEmpty c) = c+ mapReduce f = mapReduce f . NonEmpty.toList++instance Measured v e => Generator (FingerTree v e) where+ type Elem (FingerTree v e) = e+ mapReduce f = foldMap (unit . f)++instance Generator (Seq c) where+ type Elem (Seq c) = c+ mapReduce f = foldMap (unit . f)++instance Generator IntSet where+ type Elem IntSet = Int+ mapReduce f = mapReduce f . IntSet.toList++instance Generator (HashSet a) where+ type Elem (HashSet a) = a+ mapReduce f = mapReduce f . HashSet.toList++instance Generator (Set a) where+ type Elem (Set a) = a+ mapReduce f = mapReduce f . Set.toList++instance Generator (IntMap v) where+ type Elem (IntMap v) = (Int,v)+ mapReduce f = mapReduce f . IntMap.toList++instance Generator (Map k v) where+ type Elem (Map k v) = (k,v) + mapReduce f = mapReduce f . Map.toList++instance Generator (HashMap k v) where+ type Elem (HashMap k v) = (k, v)+ mapReduce f = mapReduce f . HashMap.toList++instance Ix i => Generator (Array i e) where+ type Elem (Array i e) = (i,e)+ mapReduce f = mapReduce f . assocs++-- | a 'Generator' transformer that asks only for the keys of an indexed container+newtype Keys c = Keys { getKeys :: c } ++instance Generator (Keys (IntMap v)) where+ type Elem (Keys (IntMap v)) = Int+ mapReduce f = mapReduce f . IntMap.keys . getKeys++instance Generator (Keys (Map k v)) where+ type Elem (Keys (Map k v)) = k+ mapReduce f = mapReduce f . Map.keys . getKeys++instance Ix i => Generator (Keys (Array i e)) where+ type Elem (Keys (Array i e)) = i+ mapReduce f = mapReduce f . range . bounds . getKeys++-- | a 'Generator' transformer that asks only for the values contained in an indexed container+newtype Values c = Values { getValues :: c } ++instance Generator (Values (IntMap v)) where+ type Elem (Values (IntMap v)) = v+ mapReduce f = mapReduce f . IntMap.elems . getValues++instance Generator (Values (Map k v)) where+ type Elem (Values (Map k v)) = v+ mapReduce f = mapReduce f . Map.elems . getValues++instance Ix i => Generator (Values (Array i e)) where+ type Elem (Values (Array i e)) = e+ mapReduce f = mapReduce f . elems . getValues++-- | a 'Generator' transformer that treats 'Word8' as 'Char'+-- This lets you use a 'ByteString' as a 'Char' source without going through a 'Monoid' transformer like 'UTF8'+newtype Char8 c = Char8 { getChar8 :: c } ++instance Generator (Char8 Strict.ByteString) where+ type Elem (Char8 Strict.ByteString) = Char+ mapTo f m = Strict8.foldl' (\a -> snoc a . f) m . getChar8++instance Generator (Char8 Lazy.ByteString) where+ type Elem (Char8 Lazy.ByteString) = Char+ mapReduce f = fold . map (mapReduce f . Char8) . Lazy8.toChunks . getChar8++-- | Apply a 'Reducer' directly to the elements of a 'Generator'+reduce :: (Generator c, Reducer (Elem c) m, Monoid m) => c -> m+reduce = mapReduce id+{-# SPECIALIZE reduce :: (Reducer Word8 m, Monoid m) => Strict.ByteString -> m #-}+{-# SPECIALIZE reduce :: (Reducer Word8 m, Monoid m) => Lazy.ByteString -> m #-}+{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Char8 Strict.ByteString -> m #-}+{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Char8 Lazy.ByteString -> m #-}+{-# SPECIALIZE reduce :: (Reducer c m, Monoid m) => [c] -> m #-}+{-# SPECIALIZE reduce :: (Generator (FingerTree v e), Reducer e m, Monoid m) => FingerTree v e -> m #-}+{-# SPECIALIZE reduce :: (Reducer Char m, Monoid m) => Text -> m #-}+{-# SPECIALIZE reduce :: (Reducer e m, Monoid m) => Seq e -> m #-}+{-# SPECIALIZE reduce :: (Reducer Int m, Monoid m) => IntSet -> m #-}+{-# SPECIALIZE reduce :: (Reducer a m, Monoid m) => Set a -> m #-}+{-# SPECIALIZE reduce :: (Reducer a m, Monoid m) => HashSet a -> m #-}+{-# SPECIALIZE reduce :: (Reducer (Int,v) m, Monoid m) => IntMap v -> m #-}+{-# SPECIALIZE reduce :: (Reducer (k,v) m, Monoid m) => Map k v -> m #-}+{-# SPECIALIZE reduce :: (Reducer (k,v) m, Monoid m) => HashMap k v -> m #-}+{-# SPECIALIZE reduce :: (Reducer Int m, Monoid m) => Keys (IntMap v) -> m #-}+{-# SPECIALIZE reduce :: (Reducer k m, Monoid m) => Keys (Map k v) -> m #-}+{-# SPECIALIZE reduce :: (Reducer v m, Monoid m) => Values (IntMap v) -> m #-}+{-# SPECIALIZE reduce :: (Reducer v m, Monoid m) => Values (Map k v) -> m #-}++mapReduceWith :: (Generator c, Reducer e m, Monoid m) => (m -> n) -> (Elem c -> e) -> c -> n+mapReduceWith f g = f . mapReduce g+{-# INLINE mapReduceWith #-}++reduceWith :: (Generator c, Reducer (Elem c) m, Monoid m) => (m -> n) -> c -> n+reduceWith f = f . reduce+{-# INLINE reduceWith #-}
+ src/Data/Generator/Combinators.hs view
@@ -0,0 +1,233 @@+{-# 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, all, elem, filter, concatMap, and, or+ , sum, product, notElem, replicate, cycle, repeat+ )+import Control.Applicative+import Control.Monad (MonadPlus)+import Data.Generator+import Data.Monoid (Monoid(..))+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 #-}++-}
+ src/Data/Semigroup/Alt.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Alt+-- Copyright : (c) Edward Kmett 2009-2011+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- A semigroup for working 'Alt' or 'Plus' +--+-----------------------------------------------------------------------------++module Data.Semigroup.Alt+ ( Alter(..)+ ) where++import Data.Functor.Plus+import Data.Monoid (Monoid(..))+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'Alter' turns any 'Alt' instance into a 'Semigroup'.++newtype Alter f a = Alter { getAlter :: f a } + deriving (Functor,Alt,Plus)++instance Alt f => Semigroup (Alter f a) where+ Alter a <> Alter b = Alter (a <!> b) ++instance Plus f => Monoid (Alter f a) where+ mempty = zero+ Alter a `mappend` Alter b = Alter (a <!> b) ++instance Alt f => Reducer (f a) (Alter f a) where+ unit = Alter
+ src/Data/Semigroup/Alternative.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Alternative+-- Copyright : (c) Edward Kmett 2009-2011+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- A semigroup for working with 'Alternative' 'Functor's.+--+-----------------------------------------------------------------------------++module Data.Semigroup.Alternative+ ( Alternate(..)+ ) where++import Control.Applicative+import Data.Monoid (Monoid(..))+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'Alternate' turns any 'Alternative' instance into a 'Monoid'.++newtype Alternate f a = Alternate { getAlternate :: f a } + deriving (Functor,Applicative,Alternative)++instance Alternative f => Semigroup (Alternate f a) where+ Alternate a <> Alternate b = Alternate (a <|> b)+ +instance Alternative f => Monoid (Alternate f a) where+ mempty = empty + Alternate a `mappend` Alternate b = Alternate (a <|> b) ++instance Alternative f => Reducer (f a) (Alternate f a) where+ unit = Alternate +
+ src/Data/Semigroup/Applicative.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Applicative+-- Copyright : (c) Edward Kmett 2009+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- Semigroups for working with 'Applicative' 'Functor's.+--+-----------------------------------------------------------------------------++module Data.Semigroup.Applicative + ( Traversal(..)+ , Ap(..)+ ) where++import Control.Applicative+import Data.Monoid (Monoid(..))+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'Traversal' uses an glues together 'Applicative' actions with (*>)+-- in the manner of 'traverse_' from "Data.Foldable". Any values returned by +-- reduced actions are discarded.+newtype Traversal f = Traversal { getTraversal :: f () } ++instance Applicative f => Semigroup (Traversal f) where+ Traversal a <> Traversal b = Traversal (a *> b)++instance Applicative f => Monoid (Traversal f) where+ mempty = Traversal (pure ())+ Traversal a `mappend` Traversal b = Traversal (a *> b)++instance Applicative f => Reducer (f a) (Traversal f) where+ unit = Traversal . (() <$)+ a `cons` Traversal b = Traversal (a *> b)+ Traversal a `snoc` b = Traversal (() <$ (a *> b))++-- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()+-- A rewrite rule automatically applies this when possible+snocTraversal :: Reducer (f ()) (Traversal f) => Traversal f -> f () -> Traversal f+snocTraversal a = (<>) a . Traversal+{-# RULES "unitTraversal" unit = Traversal #-}+{-# RULES "snocTraversal" snoc = snocTraversal #-}++newtype Ap f m = Ap { getApp :: f m } + deriving (Functor,Applicative)++instance (Applicative f, Semigroup m) => Semigroup (Ap f m) where+ (<>) = liftA2 (<>)++instance (Applicative f, Monoid m) => Monoid (Ap f m) where+ mempty = pure mempty+ mappend = liftA2 mappend++instance (Applicative f, Reducer c m) => Reducer (f c) (Ap f m) where+ unit = fmap unit . Ap
+ src/Data/Semigroup/Apply.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Apply+-- Copyright : (c) Edward Kmett 2009-2011+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- Semigroups for working with 'Apply'+--+-----------------------------------------------------------------------------++module Data.Semigroup.Apply+ ( Trav(..)+ , App(..)+ ) where++import Data.Functor+import Data.Functor.Apply+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'Trav' uses an glues together 'Applicative' actions with (*>)+-- in the manner of 'traverse_' from "Data.Foldable". Any values returned by +-- reduced actions are discarded.+newtype Trav f = Trav { getTrav :: f () } ++instance Apply f => Semigroup (Trav f) where+ Trav a <> Trav b = Trav (a .> b)++instance Apply f => Reducer (f a) (Trav f) where+ unit = Trav . (() <$)+ a `cons` Trav b = Trav (a .> b)+ Trav a `snoc` b = Trav (() <$ (a .> b))++-- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()+-- A rewrite rule automatically applies this when possible+snocTrav :: Reducer (f ()) (Trav f) => Trav f -> f () -> Trav f+snocTrav a = (<>) a . Trav+{-# RULES "unitTrav" unit = Trav #-}+{-# RULES "snocTrav" snoc = snocTrav #-}++-- | A 'App' turns any 'Apply' wrapped around a 'Semigroup' into a 'Semigroup'++newtype App f m = App { getApp :: f m } + deriving (Functor,Apply)++instance (Apply f, Semigroup m) => Semigroup (App f m) where+ (<>) = liftF2 (<>)++instance (Apply f, Reducer c m) => Reducer (f c) (App f m) where+ unit = fmap unit . App
+ src/Data/Semigroup/Generator.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE UndecidableInstances, TypeOperators, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, CPP #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Generator+-- Copyright : (c) Edward Kmett 2009+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- A 'Generator1' @c@ is a possibly-specialized container, which contains values of +-- type 'Elem' @c@, and which knows how to efficiently apply a 'Reducer' to extract+-- an answer.+--+-- 'Generator1' is to 'Generator' as 'Foldable1' is to 'Foldable'.+-----------------------------------------------------------------------------++module Data.Semigroup.Generator+ (+ -- * Generators+ Generator1(..)+ -- * Combinators+ , reduce1+ , mapReduceWith1+ , reduceWith1+ ) where++-- import Data.Monoid (Monoid(..))+-- import Data.Foldable (fold,foldMap)+import Data.List.NonEmpty+import Data.Semigroup (Semigroup(..)) -- , WrappedMonoid(..))+import Data.Semigroup.Foldable+import Data.Semigroup.Reducer+import Data.Generator++-- | minimal definition 'mapReduce1' or 'mapTo1'+class Generator c => Generator1 c where+ mapReduce1 :: Reducer e m => (Elem c -> e) -> c -> m+ mapTo1 :: Reducer e m => (Elem c -> e) -> m -> c -> m + mapFrom1 :: Reducer e m => (Elem c -> e) -> c -> m -> m++ mapTo1 f m = (<>) m . mapReduce1 f+ mapFrom1 f = (<>) . mapReduce1 f++instance Generator1 (NonEmpty e) where+ mapReduce1 f = foldMap1 (unit . f)++{-+mapReduceDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> c -> m+mapReduceDefault f = unwrapMonoid . mapReduce1 f ++mapToDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> m -> c -> m+mapToDefault f = unwrapMonoid . mapTo1 f ++mapFromDefault :: (Generator1 c, Reducer (Elem c) m, Monoid m) => (Elem c -> e) -> m -> c -> m+mapFromDefault f = unwrapMonoid . mapFrom1 f +-}++-- | Apply a 'Reducer' directly to the elements of a 'Generator'+reduce1 :: (Generator1 c, Reducer (Elem c) m) => c -> m+reduce1 = mapReduce1 id+{-# SPECIALIZE reduce1 :: Reducer a m => NonEmpty a -> m #-}++mapReduceWith1 :: (Generator1 c, Reducer e m) => (m -> n) -> (Elem c -> e) -> c -> n+mapReduceWith1 f g = f . mapReduce1 g+{-# INLINE mapReduceWith1 #-}++reduceWith1 :: (Generator1 c, Reducer (Elem c) m) => (m -> n) -> c -> n+reduceWith1 f = f . reduce1+{-# INLINE reduceWith1 #-}
+ src/Data/Semigroup/Instances.hs view
@@ -0,0 +1,8 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Data.Semigroup.Instances where++import Data.FingerTree+import Data.Semigroup++instance Measured v a => Semigroup (FingerTree v a) where+ (<>) = mappend
+ src/Data/Semigroup/Monad.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Monad+-- Copyright : (c) Edward Kmett 2009+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- Semigroups for working with 'Monad's.+--+-----------------------------------------------------------------------------++module Data.Semigroup.Monad+ ( Action(..)+ , Mon(..)+ ) where++import Control.Monad (liftM, liftM2)+import Data.Monoid (Monoid(..))+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'Action' uses an glues together monadic actions with (>>)+-- in the manner of 'mapM_' from "Data.Foldable". Any values returned by +-- reduced actions are discarded.+newtype Action f = Action { getAction :: f () } ++instance Monad f => Semigroup (Action f) where+ Action a <> Action b = Action (a >> b)++instance Monad f => Monoid (Action f) where+ mempty = Action (return ())+ Action a `mappend` Action b = Action (a >> b)++instance Monad f => Reducer (f a) (Action f) where+ unit a = Action (a >> return ())+ a `cons` Action b = Action (a >> b)+ Action a `snoc` b = Action (a >> b >> return ())++-- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()+-- A rewrite rule automatically applies this when possible+snocAction :: Reducer (f ()) (Action f) => Action f -> f () -> Action f+snocAction a = (<>) a . Action+{-# RULES "unitAction" unit = Action #-}+{-# RULES "snocAction" snoc = snocAction #-}++newtype Mon f m = Mon { getMon :: f m } + deriving (Monad)++instance (Monad f, Semigroup m) => Semigroup (Mon f m) where+ (<>) = liftM2 (<>)++instance (Monad f, Monoid m) => Monoid (Mon f m) where+ mempty = return mempty+ mappend = liftM2 mappend++instance (Monad f, Reducer c m) => Reducer (f c) (Mon f m) where+ unit = liftM unit . Mon
+ src/Data/Semigroup/MonadPlus.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.MonadPlus+-- Copyright : (c) Edward Kmett 2009-2011+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- A semigroup for working with instances of 'MonadPlus'+--+-----------------------------------------------------------------------------++module Data.Semigroup.MonadPlus+ ( MonadSum(..)+ ) where++import Control.Monad (MonadPlus(..))+import Data.Monoid (Monoid(..))+import Data.Semigroup (Semigroup(..))+import Data.Semigroup.Reducer (Reducer(..))++-- | A 'MonadSum' turns any 'MonadPlus' instance into a 'Monoid'.++newtype MonadSum f a = MonadSum { getMonadSum :: f a } + deriving (Monad,MonadPlus)++instance MonadPlus f => Semigroup (MonadSum f a) where+ MonadSum a <> MonadSum b = MonadSum (mplus a b)+ +instance MonadPlus f => Monoid (MonadSum f a) where+ mempty = mzero+ MonadSum a `mappend` MonadSum b = MonadSum (mplus a b) ++instance MonadPlus f => Reducer (f a) (MonadSum f a) where+ unit = MonadSum +
+ src/Data/Semigroup/Reducer.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE UndecidableInstances , FlexibleContexts , MultiParamTypeClasses , FlexibleInstances , GeneralizedNewtypeDeriving, TypeOperators, ScopedTypeVariables, CPP #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Reducer+-- Copyright : (c) Edward Kmett 2009+-- License : BSD3+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-- A @c@-'Reducer' is a 'Semigroup' with a canonical mapping from @c@ to the Semigroup.+--+-----------------------------------------------------------------------------++module Data.Semigroup.Reducer+ ( Reducer(..)+ , foldMapReduce, foldMapReduce1+ , foldReduce, foldReduce1+ , pureUnit+ , returnUnit+ , Count(..)+ ) where++import Control.Applicative++import qualified Data.Monoid as Monoid+import Data.Semigroup as Semigroup+import Data.Semigroup.Foldable+import Data.Semigroup.Instances ()+import Data.Hashable+import Data.Foldable+import Data.FingerTree++import qualified Data.Sequence as Seq+import Data.Sequence (Seq)+import qualified Data.Set as Set+import Data.Set (Set)+import qualified Data.IntSet as IntSet+import Data.IntSet (IntSet)+import qualified Data.IntMap as IntMap+import Data.IntMap (IntMap)+import qualified Data.Map as Map+import Data.Map (Map)++#ifdef LANGUAGE_DeriveDataTypeable+import Data.Data+#endif++--import Text.Parsec.Prim++-- | This type may be best read infix. A @c `Reducer` m@ is a 'Semigroup' @m@ that maps+-- values of type @c@ through @unit@ to values of type @m@. A @c@-'Reducer' may also+-- supply operations which tack-on another @c@ to an existing 'Monoid' @m@ on the left+-- or right. These specialized reductions may be more efficient in some scenarios+-- and are used when appropriate by a 'Generator'. The names 'cons' and 'snoc' work+-- by analogy to the synonymous operations in the list monoid.+--+-- This class deliberately avoids functional-dependencies, so that () can be a @c@-Reducer+-- for all @c@, and so many common reducers can work over multiple types, for instance,+-- First and Last may reduce both @a@ and 'Maybe' @a@. Since a 'Generator' has a fixed element+-- type, the input to the reducer is generally known and extracting from the monoid usually+-- is sufficient to fix the result type. Combinators are available for most scenarios where+-- this is not the case, and the few remaining cases can be handled by using an explicit +-- type annotation.+--+-- Minimal definition: 'unit' or 'snoc'+class Semigroup m => Reducer c m where+ -- | Convert a value into a 'Semigroup'+ unit :: c -> m + -- | Append a value to a 'Semigroup' for use in left-to-right reduction+ snoc :: m -> c -> m+ -- | Prepend a value onto a 'Semigroup' for use during right-to-left reduction+ cons :: c -> m -> m ++ snoc m = (<>) m . unit+ cons = (<>) . unit++-- | Apply a 'Reducer' to a 'Foldable' container, after mapping the contents into a suitable form for reduction.+foldMapReduce :: (Foldable f, Monoid m, Reducer e m) => (a -> e) -> f a -> m+foldMapReduce f = foldMap (unit . f)++foldMapReduce1 :: (Foldable1 f, Reducer e m) => (a -> e) -> f a -> m+foldMapReduce1 f = foldMap1 (unit . f)++-- | Apply a 'Reducer' to a 'Foldable' mapping each element through 'unit'+foldReduce :: (Foldable f, Monoid m, Reducer e m) => f e -> m+foldReduce = foldMap unit++-- | Apply a 'Reducer' to a 'Foldable1' mapping each element through 'unit'+foldReduce1 :: (Foldable1 f, Reducer e m) => f e -> m+foldReduce1 = foldMap1 unit++returnUnit :: (Monad m, Reducer c n) => c -> m n +returnUnit = return . unit++pureUnit :: (Applicative f, Reducer c n) => c -> f n+pureUnit = pure . unit++newtype Count = Count { getCount :: Int } deriving + ( Eq, Ord, Show, Read+#ifdef LANGUAGE_DeriveDataTypeable+ , Data, Typeable+#endif+ )++instance Hashable Count where+ hash = hash . getCount+ hashWithSalt n = hashWithSalt n . getCount++instance Semigroup Count where+ Count a <> Count b = Count (a + b)+ times1p n (Count a) = Count $ (fromIntegral n + 1) * a++instance Monoid Count where+ mempty = Count 0+ Count a `mappend` Count b = Count (a + b)++instance Reducer a Count where+ unit _ = Count 1+ Count n `snoc` _ = Count (n + 1)+ _ `cons` Count n = Count (n + 1)+ +instance (Reducer c m, Reducer c n) => Reducer c (m,n) where+ unit x = (unit x,unit x)+ (m,n) `snoc` x = (m `snoc` x, n `snoc` x)+ x `cons` (m,n) = (x `cons` m, x `cons` n)++instance (Reducer c m, Reducer c n, Reducer c o) => Reducer c (m,n,o) where+ unit x = (unit x,unit x, unit x)+ (m,n,o) `snoc` x = (m `snoc` x, n `snoc` x, o `snoc` x)+ x `cons` (m,n,o) = (x `cons` m, x `cons` n, x `cons` o)++instance (Reducer c m, Reducer c n, Reducer c o, Reducer c p) => Reducer c (m,n,o,p) where+ unit x = (unit x,unit x, unit x, unit x)+ (m,n,o,p) `snoc` x = (m `snoc` x, n `snoc` x, o `snoc` x, p `snoc` x)+ x `cons` (m,n,o,p) = (x `cons` m, x `cons` n, x `cons` o, x `cons` p)++instance Reducer c [c] where+ unit = return+ cons = (:)+ xs `snoc` x = xs ++ [x]++instance Reducer c () where+ unit _ = ()+ _ `snoc` _ = ()+ _ `cons` _ = ()++instance Reducer Bool Any where+ unit = Any++instance Reducer Bool All where+ unit = All++instance Reducer (a -> a) (Endo a) where+ unit = Endo++instance Semigroup a => Reducer a (Dual a) where+ unit = Dual+ +instance Num a => Reducer a (Sum a) where+ unit = Sum++instance Num a => Reducer a (Product a) where+ unit = Product++instance Ord a => Reducer a (Min a) where+ unit = Min++instance Ord a => Reducer a (Max a) where+ unit = Max++instance Reducer (Maybe a) (Monoid.First a) where+ unit = Monoid.First++instance Reducer a (Semigroup.First a) where+ unit = Semigroup.First++instance Reducer (Maybe a) (Monoid.Last a) where+ unit = Monoid.Last++instance Reducer a (Semigroup.Last a) where+ unit = Semigroup.Last++instance Measured v a => Reducer a (FingerTree v a) where+ unit = singleton+ cons = (<|)+ snoc = (|>) ++--instance (Stream s m t, Reducer c a) => Reducer c (ParsecT s u m a) where+-- unit = return . unit++instance Reducer a (Seq a) where+ unit = Seq.singleton+ cons = (Seq.<|)+ snoc = (Seq.|>)++instance Reducer Int IntSet where+ unit = IntSet.singleton+ cons = IntSet.insert+ snoc = flip IntSet.insert -- left bias irrelevant++instance Ord a => Reducer a (Set a) where+ unit = Set.singleton+ cons = Set.insert+ -- pedantic about order in case 'Eq' doesn't implement structural equality+ snoc s m | Set.member m s = s + | otherwise = Set.insert m s++instance Reducer (Int, v) (IntMap v) where+ unit = uncurry IntMap.singleton+ cons = uncurry IntMap.insert+ snoc = flip . uncurry . IntMap.insertWith $ const id++instance Ord k => Reducer (k, v) (Map k v) where+ unit = uncurry Map.singleton+ cons = uncurry Map.insert+ snoc = flip . uncurry . Map.insertWith $ const id++instance Monoid m => Reducer m (WrappedMonoid m) where+ unit = WrapMonoid
+ src/Data/Semigroup/Reducer/With.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE UndecidableInstances, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Reducer.With+-- Copyright : (c) Edward Kmett 2009-2011+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : non-portable (MPTCs)+--+-----------------------------------------------------------------------------++module Data.Semigroup.Reducer.With+ ( WithReducer(..)+ ) where++import Control.Applicative+import Data.FingerTree+import Data.Foldable+import Data.Traversable+import Data.Hashable+import Data.Monoid+import Data.Semigroup.Reducer+import Data.Semigroup.Foldable+import Data.Semigroup.Traversable+import Data.Semigroup.Instances ()++-- | If @m@ is a @c@-"Reducer", then m is @(c `WithReducer` m)@-"Reducer"+-- This can be used to quickly select a "Reducer" for use as a 'FingerTree'+-- 'measure'.++newtype WithReducer m c = WithReducer { withoutReducer :: c } + deriving (Eq, Ord, Show, Read)++instance Hashable c => Hashable (WithReducer m c) where+ hash = hash . withoutReducer+ hashWithSalt n = hashWithSalt n . withoutReducer++instance Functor (WithReducer m) where+ fmap f = WithReducer . f . withoutReducer++instance Foldable (WithReducer m) where+ foldMap f = f . withoutReducer++instance Traversable (WithReducer m) where+ traverse f (WithReducer a) = WithReducer <$> f a++instance Foldable1 (WithReducer m) where+ foldMap1 f = f . withoutReducer++instance Traversable1 (WithReducer m) where+ traverse1 f (WithReducer a) = WithReducer <$> f a++instance Reducer c m => Reducer (WithReducer m c) m where+ unit = unit . withoutReducer ++instance (Monoid m, Reducer c m) => Measured m (WithReducer m c) where+ measure = unit . withoutReducer
+ src/Data/Semigroup/Self.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Semigroup.Self+-- Copyright : (c) Edward Kmett 2009+-- License : BSD-style+-- Maintainer : ekmett@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- A simple 'Monoid' transformer that takes a 'Monoid' m and produces a new @m@-Reducer named 'Self' @m@+-- +-- This is useful when you have a generator that already contains monoidal values or someone supplies+-- the map to the monoid in the form of a function rather than as a "Reducer" instance. You can just+-- @'getSelf' . `reduce`@ or @'getSelf' . 'mapReduce' f@ in those scenarios. These behaviors are encapsulated +-- into the 'fold' and 'foldMap' combinators in "Data.Monoid.Combinators" respectively.+--+-----------------------------------------------------------------------------++module Data.Semigroup.Self+ ( Self(..)+ ) where++import Control.Applicative+import Data.Foldable+import Data.Traversable+import Data.Semigroup+import Data.Semigroup.Foldable+import Data.Semigroup.Traversable+import Data.Semigroup.Reducer (Reducer(..))++newtype Self m = Self { getSelf :: m } deriving (Semigroup, Monoid)++instance Semigroup m => Reducer m (Self m) where+ unit = Self++instance Functor Self where+ fmap f (Self x) = Self (f x)++instance Foldable Self where+ foldMap f (Self x) = f x++instance Traversable Self where+ traverse f (Self x) = Self <$> f x++instance Foldable1 Self where+ foldMap1 f (Self x) = f x++instance Traversable1 Self where+ traverse1 f (Self x) = Self <$> f x
+ src/Data/Semigroup/Union.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving #-}+module Data.Semigroup.Union+ ( module Data.Semigroup.Reducer+ -- * Unions of Containers+ , HasUnion(..)+ , HasUnion0(..)+ , Union(Union,getUnion)+ -- * Unions of Containers of Semigroups+ , HasUnionWith(..)+ , HasUnionWith0(..)+ , UnionWith(UnionWith,getUnionWith)+ ) where++import qualified Data.HashMap.Lazy as HashMap+import Data.HashMap.Lazy (HashMap)++import qualified Data.IntMap as IntMap+import Data.IntMap (IntMap)++import qualified Data.IntSet as IntSet+import Data.IntSet (IntSet)++import qualified Data.HashSet as HashSet+import Data.HashSet (HashSet)++import qualified Data.Map as Map+import Data.Map (Map)++import qualified Data.Set as Set+import Data.Set (Set)++import qualified Data.List as List++import Data.Hashable+import Data.Functor+import Data.Foldable+import Data.Traversable+import Data.Semigroup+import Data.Semigroup.Foldable+import Data.Semigroup.Traversable+import Data.Semigroup.Reducer+import Data.Semigroup.Instances ()++-- | A Container suitable for the 'Union' 'Monoid'+class HasUnion f where+ union :: f -> f -> f++{-# SPECIALIZE union :: IntMap a -> IntMap a -> IntMap a #-}+{-# SPECIALIZE union :: Ord k => Map k a -> Map k a -> Map k a #-}+{-# SPECIALIZE union :: Eq a => [a] -> [a] -> [a] #-}+{-# SPECIALIZE union :: Ord a => Set a -> Set a -> Set a #-}+{-# SPECIALIZE union :: IntSet -> IntSet -> IntSet #-}+{-# SPECIALIZE union :: Eq a => HashSet a -> HashSet a -> HashSet a #-}+{-# SPECIALIZE union :: Eq k => HashMap k a -> HashMap k a -> HashMap k a #-}++class HasUnion f => HasUnion0 f where+ empty :: f++instance HasUnion (IntMap a) where+ union = IntMap.union++instance HasUnion0 (IntMap a) where+ empty = IntMap.empty++instance (Eq k, Hashable k) => HasUnion (HashMap k a) where+ union = HashMap.union++instance (Eq k, Hashable k) => HasUnion0 (HashMap k a) where+ empty = HashMap.empty++instance Ord k => HasUnion (Map k a) where+ union = Map.union++instance Ord k => HasUnion0 (Map k a) where+ empty = Map.empty++instance Eq a => HasUnion [a] where+ union = List.union++instance Eq a => HasUnion0 [a] where+ empty = []++instance Ord a => HasUnion (Set a) where+ union = Set.union++instance Ord a => HasUnion0 (Set a) where+ empty = Set.empty++instance HasUnion IntSet where+ union = IntSet.union++instance HasUnion0 IntSet where+ empty = IntSet.empty++instance (Eq a, Hashable a) => HasUnion (HashSet a) where+ union = HashSet.union++instance (Eq a, Hashable a) => HasUnion0 (HashSet a) where+ empty = HashSet.empty+++-- | The 'Monoid' @('union','empty')@+newtype Union f = Union { getUnion :: f } + deriving (Eq,Ord,Show,Read)++instance HasUnion f => Semigroup (Union f) where+ Union a <> Union b = Union (a `union` b)++instance HasUnion0 f => Monoid (Union f) where+ Union a `mappend` Union b = Union (a `union` b)+ mempty = Union empty++instance HasUnion f => Reducer f (Union f) where+ unit = Union++instance Functor Union where+ fmap f (Union a) = Union (f a)++instance Foldable Union where+ foldMap f (Union a) = f a++instance Traversable Union where+ traverse f (Union a) = Union <$> f a++instance Foldable1 Union where+ foldMap1 f (Union a) = f a++instance Traversable1 Union where+ traverse1 f (Union a) = Union <$> f a++-- | Polymorphic containers that we can supply an operation to handle unions with+class Functor f => HasUnionWith f where+ unionWith :: (a -> a -> a) -> f a -> f a -> f a++{-# SPECIALIZE unionWith :: (a -> a -> a) -> IntMap a -> IntMap a -> IntMap a #-}+{-# SPECIALIZE unionWith :: Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a #-}+{-# SPECIALIZE unionWith :: Eq k => (a -> a -> a) -> HashMap k a -> HashMap k a -> HashMap k a #-}++class HasUnionWith f => HasUnionWith0 f where+ emptyWith :: f a ++instance HasUnionWith IntMap where + unionWith = IntMap.unionWith++instance HasUnionWith0 IntMap where + emptyWith = IntMap.empty++instance Ord k => HasUnionWith (Map k) where + unionWith = Map.unionWith++instance Ord k => HasUnionWith0 (Map k) where + emptyWith = Map.empty++-- TODO: add unionWith to unordered-containers++--instance Eq k => HasUnionWith (HashMap k) where +-- unionWith = HashMap.unionWith++--instance Ord k => HasUnionWith0 (Map k) where +-- emptyWith = Map.empty++-- | The 'Monoid' @('unionWith mappend','empty')@ for containers full of monoids.+newtype UnionWith f m = UnionWith { getUnionWith :: f m } ++instance (HasUnionWith f, Semigroup m) => Semigroup (UnionWith f m) where+ UnionWith a <> UnionWith b = UnionWith (unionWith (<>) a b)++instance (HasUnionWith0 f, Monoid m) => Monoid (UnionWith f m) where+ mempty = UnionWith emptyWith+ UnionWith a `mappend` UnionWith b = UnionWith (unionWith mappend a b)++instance (HasUnionWith f, Semigroup m, Monoid m) => Reducer (f m) (UnionWith f m) where+ unit = UnionWith+