module Data.Monoid.Union
    ( module Data.Monoid.Reducer
    
    , HasUnion
    , empty
    , union
    , Union(Union,getUnion)
    
    , HasUnionWith
    , emptyWith
    , unionWith
    , UnionWith(UnionWith,getUnionWith)
    ) where
import qualified Data.IntMap as IntMap
import Data.IntMap (IntMap)
import qualified Data.IntSet as IntSet
import Data.IntSet (IntSet)
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.Monoid
import Data.Monoid.Reducer
class HasUnion f where
    empty :: f
    
    
    
    
    
    union :: f -> f -> f
instance HasUnion (IntMap a) where
    empty = IntMap.empty
    union = IntMap.union
instance Ord k => HasUnion (Map k a) where
    empty = Map.empty
    union = Map.union
instance Eq a => HasUnion [a] where
    empty = []
    union = List.union
instance Ord a => HasUnion (Set a) where
    empty = Set.empty
    union = Set.union
instance HasUnion IntSet where
    empty = IntSet.empty
    union = IntSet.union
newtype Union f = Union { getUnion :: f } 
    deriving (Eq,Ord,Show,Read)
instance (HasUnion f) => Monoid (Union f) where
    mempty = Union empty
    Union a `mappend` Union b = Union (a `union` b)
instance (HasUnion f) => Reducer f (Union f) where
    unit = Union
instance Functor Union where
    fmap f (Union a) = Union (f a)
class Functor f => HasUnionWith f where
    
    
    unionWith :: (a -> a -> a) -> f a -> f a -> f a
    emptyWith :: f a 
instance HasUnionWith IntMap where 
    emptyWith = IntMap.empty
    unionWith = IntMap.unionWith
instance Ord k => HasUnionWith (Map k) where 
    emptyWith = Map.empty
    unionWith = Map.unionWith
newtype UnionWith f m = UnionWith { getUnionWith :: f m } 
    deriving (Eq,Ord,Show,Read,Functor,Monad)
instance (HasUnionWith f, Monoid m) => Monoid (UnionWith f m) where
    mempty = UnionWith emptyWith
    UnionWith a `mappend` UnionWith b = UnionWith (unionWith mappend a b)
instance (HasUnionWith f, Monoid m) => Reducer (f m) (UnionWith f m) where
    unit = UnionWith