    {-# LANGUAGE CPP #-}
    {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE UndecidableInstances #-}
    #if __GLASGOW_HASKELL__ >= 704
    {-# LANGUAGE Safe #-}
    #else
    {-# LANGUAGE Trustworthy #-}
    #endif
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Semigroup.Generic
    -- Copyright   :  (C) 2014-2015 Edward Kmett, Eric Mertens
    -- License     :  BSD-style (see the file LICENSE)
    --
    -- Maintainer  :  Edward Kmett <ekmett@gmail.com>
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- This module provides generic deriving tools for monoids and semigroups for
    -- product-like structures.
    --
    ----------------------------------------------------------------------------
    module Data.Semigroup.Generic
      ( -- * Generic method implementations
        gmappend, gmempty

        -- * Adapter newtype
      , GenericSemigroupMonoid(..)

        -- * Internal classes
      , GSemigroup, GMonoid
      ) where

    #if !(MIN_VERSION_base(4,8,0))
    import Data.Monoid (Monoid(..))
    #endif
    #if !(MIN_VERSION_base(4,11,0))
    import Data.Semigroup (Semigroup(..))
    #endif
    import GHC.Generics

    -- | Generically generate a 'Semigroup' ('<>') operation for any type
    -- implementing 'Generic'. This operation will append two values
    -- by point-wise appending their component fields. It is only defined
    -- for product types.
    --
    -- @
    -- 'gmappend' a ('gmappend' b c) = 'gmappend' ('gmappend' a b) c
    -- @
    gmappend :: (Generic a, GSemigroup (Rep a)) => a -> a -> a
    gmappend :: a -> a -> a
    gmappend x :: a
    x y :: a
    y = Rep a Any -> a
    forall a x. Generic a => Rep a x -> a
    to (Rep a Any -> Rep a Any -> Rep a Any
    forall (f :: * -> *) p. GSemigroup f => f p -> f p -> f p
    gmappend' (a -> Rep a Any
    forall a x. Generic a => a -> Rep a x
    from a
    x) (a -> Rep a Any
    forall a x. Generic a => a -> Rep a x
    from a
    y))

    class GSemigroup f where
      gmappend' :: f p -> f p -> f p

    instance GSemigroup U1 where
      gmappend' :: U1 p -> U1 p -> U1 p
    gmappend' _ _ = U1 p
    forall k (p :: k). U1 p
    U1

    instance GSemigroup V1 where
      gmappend' :: V1 p -> V1 p -> V1 p
    gmappend' x :: V1 p
    x y :: V1 p
    y = V1 p
    x V1 p -> V1 p -> V1 p
    forall a b. a -> b -> b
    `seq` V1 p
    y V1 p -> V1 p -> V1 p
    forall a b. a -> b -> b
    `seq` [Char] -> V1 p
    forall a. HasCallStack => [Char] -> a
    error "GSemigroup.V1: gmappend'"

    instance Semigroup a => GSemigroup (K1 i a) where
      gmappend' :: K1 i a p -> K1 i a p -> K1 i a p
    gmappend' (K1 x :: a
    x) (K1 y :: a
    y) = a -> K1 i a p
    forall k i c (p :: k). c -> K1 i c p
    K1 (a
    x a -> a -> a
    forall a. Semigroup a => a -> a -> a
    <> a
    y)

    instance GSemigroup f => GSemigroup (M1 i c f) where
      gmappend' :: M1 i c f p -> M1 i c f p -> M1 i c f p
    gmappend' (M1 x :: f p
    x) (M1 y :: f p
    y) = f p -> M1 i c f p
    forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
    M1 (f p -> f p -> f p
    forall (f :: * -> *) p. GSemigroup f => f p -> f p -> f p
    gmappend' f p
    x f p
    y)

    instance (GSemigroup f, GSemigroup g) => GSemigroup (f :*: g) where
      gmappend' :: (:*:) f g p -> (:*:) f g p -> (:*:) f g p
    gmappend' (x1 :: f p
    x1 :*: x2 :: g p
    x2) (y1 :: f p
    y1 :*: y2 :: g p
    y2) = f p -> f p -> f p
    forall (f :: * -> *) p. GSemigroup f => f p -> f p -> f p
    gmappend' f p
    x1 f p
    y1 f p -> g p -> (:*:) f g p
    forall k (f :: k -> *) (g :: k -> *) (p :: k).
    f p -> g p -> (:*:) f g p
    :*: g p -> g p -> g p
    forall (f :: * -> *) p. GSemigroup f => f p -> f p -> f p
    gmappend' g p
    x2 g p
    y2

    -- | Generically generate a 'Monoid' 'mempty' for any product-like type
    -- implementing 'Generic'.
    --
    -- It is only defined for product types.
    --
    -- @
    -- 'gmappend' 'gmempty' a = a = 'gmappend' a 'gmempty'
    -- @

    gmempty :: (Generic a, GMonoid (Rep a)) => a
    gmempty :: a
    gmempty = Rep a Any -> a
    forall a x. Generic a => Rep a x -> a
    to Rep a Any
    forall (f :: * -> *) p. GMonoid f => f p
    gmempty'

    class GSemigroup f => GMonoid f where
      gmempty' :: f p

    instance GMonoid U1 where
      gmempty' :: U1 p
    gmempty' = U1 p
    forall k (p :: k). U1 p
    U1

    instance (Semigroup a, Monoid a) => GMonoid (K1 i a) where
      gmempty' :: K1 i a p
    gmempty' = a -> K1 i a p
    forall k i c (p :: k). c -> K1 i c p
    K1 a
    forall a. Monoid a => a
    mempty

    instance GMonoid f => GMonoid (M1 i c f) where
      gmempty' :: M1 i c f p
    gmempty' = f p -> M1 i c f p
    forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
    M1 f p
    forall (f :: * -> *) p. GMonoid f => f p
    gmempty'

    instance (GMonoid f, GMonoid g) => GMonoid (f :*: g) where
      gmempty' :: (:*:) f g p
    gmempty' = f p
    forall (f :: * -> *) p. GMonoid f => f p
    gmempty' f p -> g p -> (:*:) f g p
    forall k (f :: k -> *) (g :: k -> *) (p :: k).
    f p -> g p -> (:*:) f g p
    :*: g p
    forall (f :: * -> *) p. GMonoid f => f p
    gmempty'

    -- | An adapter newtype, suitable for @DerivingVia@. Its 'Semigroup' and
    -- 'Monoid' instances leverage the 'Generic'-based defaults defined by
    -- 'gmappend' and 'gmempty'. Here is an example of how to use it:
    --
    -- @
    -- &#123;-&#35; LANGUAGE DerivingVia &#35;-&#125;
    -- import "Data.Semigroup.Generic"
    --
    -- data Pair a = MkPair a a
    --   deriving ('Semigroup', 'Monoid') via ('GenericSemigroupMonoid' (Pair a))
    -- @
    newtype GenericSemigroupMonoid a =
      GenericSemigroupMonoid { GenericSemigroupMonoid a -> a
    getGenericSemigroupMonoid :: a }

    instance (Generic a, GSemigroup (Rep a)) => Semigroup (GenericSemigroupMonoid a) where
      GenericSemigroupMonoid x :: a
    x <> :: GenericSemigroupMonoid a
    -> GenericSemigroupMonoid a -> GenericSemigroupMonoid a
    <> GenericSemigroupMonoid y :: a
    y =
        a -> GenericSemigroupMonoid a
    forall a. a -> GenericSemigroupMonoid a
    GenericSemigroupMonoid (a -> a -> a
    forall a. (Generic a, GSemigroup (Rep a)) => a -> a -> a
    gmappend a
    x a
    y)
    instance (Generic a, GMonoid (Rep a)) => Monoid (GenericSemigroupMonoid a) where
      mempty :: GenericSemigroupMonoid a
    mempty = a -> GenericSemigroupMonoid a
    forall a. a -> GenericSemigroupMonoid a
    GenericSemigroupMonoid a
    forall a. (Generic a, GMonoid (Rep a)) => a
    gmempty
    #if !(MIN_VERSION_base(4,11,0))
      mappend = (<>)
    #endif