{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances, FlexibleInstances, TypeOperators #-}
module Numeric.Algebra.Commutative 
  ( Commutative
  , CommutativeAlgebra
  , CocommutativeCoalgebra
  , CommutativeBialgebra
  ) where

import Data.Functor.Representable.Trie
import Data.Int
import Data.IntSet (IntSet)
import Data.IntMap (IntMap)
import Data.Set (Set)
import Data.Map (Map)
import Data.Word
import Numeric.Additive.Class
import Numeric.Algebra.Class
import Numeric.Algebra.Unital
import Numeric.Natural
import Prelude (Bool, Ord, Integer)



-- | A commutative multiplicative semigroup
class Multiplicative r => Commutative r

instance Commutative () 
instance Commutative Bool
instance Commutative Integer
instance Commutative Int
instance Commutative Int8
instance Commutative Int16
instance Commutative Int32
instance Commutative Int64
instance Commutative Natural
instance Commutative Word
instance Commutative Word8
instance Commutative Word16
instance Commutative Word32
instance Commutative Word64

instance ( Commutative a
         , Commutative b
         ) => Commutative (a,b) 

instance ( Commutative a
         , Commutative b
         , Commutative c
         ) => Commutative (a,b,c) 

instance ( Commutative a
         , Commutative b
         , Commutative c
         , Commutative d
         ) => Commutative (a,b,c,d) 

instance ( Commutative a
         , Commutative b
         , Commutative c
         , Commutative d
         , Commutative e
         ) => Commutative (a,b,c,d,e)

instance CommutativeAlgebra r a => Commutative (a -> r)

instance ( HasTrie a
         , CommutativeAlgebra r a
         ) => Commutative (a :->: r) 



class Algebra r a => CommutativeAlgebra r a

instance ( Commutative r
         , Semiring r
         ) => CommutativeAlgebra r ()

instance ( CommutativeAlgebra r a
         , CommutativeAlgebra r b
         ) => CommutativeAlgebra r (a,b)

instance ( CommutativeAlgebra r a
         , CommutativeAlgebra r b
         , CommutativeAlgebra r c
         ) => CommutativeAlgebra r (a,b,c)

instance ( CommutativeAlgebra r a
         , CommutativeAlgebra r b
         , CommutativeAlgebra r c
         , CommutativeAlgebra r d
         ) => CommutativeAlgebra r (a,b,c,d)

instance ( CommutativeAlgebra r a
         , CommutativeAlgebra r b
         , CommutativeAlgebra r c
         , CommutativeAlgebra r d
         , CommutativeAlgebra r e
         ) => CommutativeAlgebra r (a,b,c,d,e)

instance ( Commutative r
         , Semiring r
         , Ord a
         ) => CommutativeAlgebra r (Set a)

instance (Commutative r
         , Semiring r
         ) => CommutativeAlgebra r IntSet

instance (Commutative r
         , Monoidal r
         , Semiring r
         , Ord a
         , Abelian b
         , Partitionable b
         ) => CommutativeAlgebra r (Map a b)

instance ( Commutative r
         , Monoidal r
         , Semiring r
         , Abelian b
         , Partitionable b
         ) => CommutativeAlgebra r (IntMap b)



class Coalgebra r c => CocommutativeCoalgebra r c

instance CommutativeAlgebra r m => CocommutativeCoalgebra r (m -> r)

instance ( HasTrie m
         , CommutativeAlgebra r m
         ) => CocommutativeCoalgebra r (m :->: r)

instance (Commutative r, Semiring r) => CocommutativeCoalgebra r ()

instance ( CocommutativeCoalgebra r a
         , CocommutativeCoalgebra r b
         ) => CocommutativeCoalgebra r (a,b)

instance ( CocommutativeCoalgebra r a
         , CocommutativeCoalgebra r b
         , CocommutativeCoalgebra r c
         ) => CocommutativeCoalgebra r (a,b,c)

instance ( CocommutativeCoalgebra r a
         , CocommutativeCoalgebra r b
         , CocommutativeCoalgebra r c
         , CocommutativeCoalgebra r d
         ) => CocommutativeCoalgebra r (a,b,c,d)

instance ( CocommutativeCoalgebra r a
         , CocommutativeCoalgebra r b
         , CocommutativeCoalgebra r c
         , CocommutativeCoalgebra r d
         , CocommutativeCoalgebra r e
         ) => CocommutativeCoalgebra r (a,b,c,d,e)

instance ( Commutative r
         , Semiring r
         , Ord a) => CocommutativeCoalgebra r (Set a)

instance ( Commutative r
         , Semiring r
         ) => CocommutativeCoalgebra r IntSet

instance ( Commutative r
         , Semiring r
         , Ord a
         , Abelian b
         ) => CocommutativeCoalgebra r (Map a b)

instance ( Commutative r
         , Semiring r
         , Abelian b
         ) => CocommutativeCoalgebra r (IntMap b)



class ( Bialgebra r h
      , CommutativeAlgebra r h
      , CocommutativeCoalgebra r h
      ) => CommutativeBialgebra r h

instance ( Bialgebra r h
         , CommutativeAlgebra r h
         , CocommutativeCoalgebra r h
         ) => CommutativeBialgebra r h