{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeOperators #-} #if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE Safe #-} #endif #if __GLASGOW_HASKELL__ >= 705 {-# LANGUAGE PolyKinds #-} #endif {- | This module provides two main features: 1. 'GMonoid', a generic version of the 'Monoid' type class, including instances of the types from "Data.Monoid" 2. Default generic definitions for the 'Monoid' methods 'mempty' and 'mappend' The generic defaults only work for types without alternatives (i.e. they have only one constructor). We cannot in general know how to deal with different constructors. -} module Generics.Deriving.Monoid ( -- * GMonoid type class GMonoid(..), -- * Default definitions -- ** GMonoid gmemptydefault, gmappenddefault, -- * Internal auxiliary class for GMonoid GMonoid'(..), -- ** Monoid {- | These functions can be used in a 'Monoid' instance. For example: @ -- LANGUAGE DeriveGeneric import Generics.Deriving.Base (Generic) import Generics.Deriving.Monoid data T a = C a (Maybe a) deriving Generic instance Monoid a => Monoid (T a) where mempty = memptydefault mappend = mappenddefault @ -} memptydefault, mappenddefault, -- * Internal auxiliary class for Monoid Monoid'(..), -- * The Monoid module -- | This is exported for convenient access to the various wrapper types. module Data.Monoid, ) where -------------------------------------------------------------------------------- import Control.Applicative import Data.Monoid import Generics.Deriving.Base #if MIN_VERSION_base(4,7,0) import Data.Proxy (Proxy) #endif #if MIN_VERSION_base(4,8,0) import Data.Functor.Identity (Identity) #endif #if MIN_VERSION_base(4,9,0) import Data.Semigroup (WrappedMonoid) #endif -------------------------------------------------------------------------------- class GMonoid' f where gmempty' :: f x gmappend' :: f x -> f x -> f x instance GMonoid' U1 where gmempty' = U1 gmappend' U1 U1 = U1 instance GMonoid a => GMonoid' (K1 i a) where gmempty' = K1 gmempty gmappend' (K1 x) (K1 y) = K1 (x `gmappend` y) instance GMonoid' f => GMonoid' (M1 i c f) where gmempty' = M1 gmempty' gmappend' (M1 x) (M1 y) = M1 (x `gmappend'` y) instance (GMonoid' f, GMonoid' h) => GMonoid' (f :*: h) where gmempty' = gmempty' :*: gmempty' gmappend' (x1 :*: y1) (x2 :*: y2) = gmappend' x1 x2 :*: gmappend' y1 y2 -------------------------------------------------------------------------------- gmemptydefault :: (Generic a, GMonoid' (Rep a)) => a gmemptydefault = to gmempty' gmappenddefault :: (Generic a, GMonoid' (Rep a)) => a -> a -> a gmappenddefault x y = to (gmappend' (from x) (from y)) -------------------------------------------------------------------------------- class Monoid' f where mempty' :: f x mappend' :: f x -> f x -> f x instance Monoid' U1 where mempty' = U1 mappend' U1 U1 = U1 instance Monoid a => Monoid' (K1 i a) where mempty' = K1 mempty mappend' (K1 x) (K1 y) = K1 (x `mappend` y) instance Monoid' f => Monoid' (M1 i c f) where mempty' = M1 mempty' mappend' (M1 x) (M1 y) = M1 (x `mappend'` y) instance (Monoid' f, Monoid' h) => Monoid' (f :*: h) where mempty' = mempty' :*: mempty' mappend' (x1 :*: y1) (x2 :*: y2) = mappend' x1 x2 :*: mappend' y1 y2 -------------------------------------------------------------------------------- memptydefault :: (Generic a, Monoid' (Rep a)) => a memptydefault = to mempty' mappenddefault :: (Generic a, Monoid' (Rep a)) => a -> a -> a mappenddefault x y = to (mappend' (from x) (from y)) -------------------------------------------------------------------------------- class GMonoid a where -- | Generic 'mempty' gmempty :: a -- | Generic 'mappend' gmappend :: a -> a -> a -- | Generic 'mconcat' gmconcat :: [a] -> a gmconcat = foldr gmappend gmempty #if __GLASGOW_HASKELL__ >= 701 default gmempty :: (Generic a, GMonoid' (Rep a)) => a gmempty = to gmempty' default gmappend :: (Generic a, GMonoid' (Rep a)) => a -> a -> a gmappend x y = to (gmappend' (from x) (from y)) #endif -------------------------------------------------------------------------------- -- Instances that reuse Monoid instance GMonoid Ordering where gmempty = mempty gmappend = mappend instance GMonoid () where gmempty = mempty gmappend = mappend instance GMonoid Any where gmempty = mempty gmappend = mappend instance GMonoid All where gmempty = mempty gmappend = mappend instance GMonoid (First a) where gmempty = mempty gmappend = mappend instance GMonoid (Last a) where gmempty = mempty gmappend = mappend instance Num a => GMonoid (Sum a) where gmempty = mempty gmappend = mappend instance Num a => GMonoid (Product a) where gmempty = mempty gmappend = mappend instance GMonoid [a] where gmempty = mempty gmappend = mappend instance GMonoid (Endo a) where gmempty = mempty gmappend = mappend #if MIN_VERSION_base(4,8,0) instance Alternative f => GMonoid (Alt f a) where gmempty = mempty gmappend = mappend #endif -- Handwritten instances instance GMonoid a => GMonoid (Dual a) where gmempty = Dual gmempty gmappend (Dual x) (Dual y) = Dual (gmappend y x) instance GMonoid a => GMonoid (Maybe a) where gmempty = Nothing gmappend Nothing x = x gmappend x Nothing = x gmappend (Just x) (Just y) = Just (gmappend x y) instance GMonoid b => GMonoid (a -> b) where gmempty _ = gmempty gmappend f g x = gmappend (f x) (g x) instance GMonoid a => GMonoid (Const a b) where gmempty = gmemptydefault gmappend = gmappenddefault #if MIN_VERSION_base(4,7,0) instance GMonoid # if MIN_VERSION_base(4,9,0) (Proxy s) # else (Proxy (s :: *)) # endif where gmempty = memptydefault gmappend = mappenddefault #endif #if MIN_VERSION_base(4,8,0) instance GMonoid a => GMonoid (Identity a) where gmempty = gmemptydefault gmappend = gmappenddefault #endif #if MIN_VERSION_base(4,9,0) instance GMonoid m => GMonoid (WrappedMonoid m) where gmempty = gmemptydefault gmappend = gmappenddefault #endif -- Tuple instances instance (GMonoid a,GMonoid b) => GMonoid (a,b) where gmempty = (gmempty,gmempty) gmappend (a1,b1) (a2,b2) = (gmappend a1 a2,gmappend b1 b2) instance (GMonoid a,GMonoid b,GMonoid c) => GMonoid (a,b,c) where gmempty = (gmempty,gmempty,gmempty) gmappend (a1,b1,c1) (a2,b2,c2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2) instance (GMonoid a,GMonoid b,GMonoid c,GMonoid d) => GMonoid (a,b,c,d) where gmempty = (gmempty,gmempty,gmempty,gmempty) gmappend (a1,b1,c1,d1) (a2,b2,c2,d2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2,gmappend d1 d2) instance (GMonoid a,GMonoid b,GMonoid c,GMonoid d,GMonoid e) => GMonoid (a,b,c,d,e) where gmempty = (gmempty,gmempty,gmempty,gmempty,gmempty) gmappend (a1,b1,c1,d1,e1) (a2,b2,c2,d2,e2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2,gmappend d1 d2,gmappend e1 e2) instance (GMonoid a,GMonoid b,GMonoid c,GMonoid d,GMonoid e,GMonoid f) => GMonoid (a,b,c,d,e,f) where gmempty = (gmempty,gmempty,gmempty,gmempty,gmempty,gmempty) gmappend (a1,b1,c1,d1,e1,f1) (a2,b2,c2,d2,e2,f2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2,gmappend d1 d2,gmappend e1 e2,gmappend f1 f2) instance (GMonoid a,GMonoid b,GMonoid c,GMonoid d,GMonoid e,GMonoid f,GMonoid g) => GMonoid (a,b,c,d,e,f,g) where gmempty = (gmempty,gmempty,gmempty,gmempty,gmempty,gmempty,gmempty) gmappend (a1,b1,c1,d1,e1,f1,g1) (a2,b2,c2,d2,e2,f2,g2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2,gmappend d1 d2,gmappend e1 e2,gmappend f1 f2,gmappend g1 g2) instance (GMonoid a,GMonoid b,GMonoid c,GMonoid d,GMonoid e,GMonoid f,GMonoid g,GMonoid h) => GMonoid (a,b,c,d,e,f,g,h) where gmempty = (gmempty,gmempty,gmempty,gmempty,gmempty,gmempty,gmempty,gmempty) gmappend (a1,b1,c1,d1,e1,f1,g1,h1) (a2,b2,c2,d2,e2,f2,g2,h2) = (gmappend a1 a2,gmappend b1 b2,gmappend c1 c2,gmappend d1 d2,gmappend e1 e2,gmappend f1 f2,gmappend g1 g2,gmappend h1 h2)