{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Monoid.Generic
( genericMappend
, genericMempty
, GenericSemigroup(..)
, GenericMonoid(..)
) where
import Data.Semigroup.Generic
import GHC.Generics
import GHC.TypeLits
newtype GenericMonoid a = GenericMonoid a
deriving Show
instance Semigroup a => Semigroup (GenericMonoid a) where
GenericMonoid a <> GenericMonoid b = GenericMonoid $ a <> b
instance
(Semigroup a, Generic a, MemptyProduct (Rep a))
=> Monoid (GenericMonoid a) where
mempty = GenericMonoid genericMempty
genericMempty :: (Generic a, MemptyProduct (Rep a)) => a
genericMempty = to genericMempty'
class MemptyProduct f where
genericMempty' :: f k
instance MemptyProduct c => MemptyProduct (D1 md c) where
genericMempty' = M1 genericMempty'
instance MemptyProduct s => MemptyProduct (C1 md s) where
genericMempty' = M1 genericMempty'
instance
(TypeError (Text "You can't use `genericMempty` for sum types"))
=> MemptyProduct (a :+: b) where
genericMempty' = undefined
instance (MemptyProduct a, MemptyProduct b) => MemptyProduct (a :*: b) where
genericMempty' = genericMempty' :*: genericMempty'
instance Monoid t => MemptyProduct (S1 m (Rec0 t)) where
genericMempty' = M1 (K1 mempty)