    {-# LANGUAGE CPP #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE KindSignatures #-}
    {-# LANGUAGE TypeOperators #-}

    #if __GLASGOW_HASKELL__ >= 701
    {-# LANGUAGE DefaultSignatures #-}
    #endif

    #if __GLASGOW_HASKELL__ >= 705
    {-# LANGUAGE PolyKinds #-}
    #endif

    #if __GLASGOW_HASKELL__ >= 710
    {-# LANGUAGE Safe #-}
    #elif __GLASGOW_HASKELL__ >= 701
    {-# LANGUAGE Trustworthy #-}
    #endif

    module Generics.Deriving.Semigroup.Internal (
      -- * Generic semigroup class
        GSemigroup(..)

      -- * Default definition
      , gsappenddefault

      -- * Internal semigroup class
      , GSemigroup'(..)

      ) where

    import Control.Applicative
    import Data.Monoid as Monoid
    #if MIN_VERSION_base(4,5,0)
      hiding ((<>))
    #endif
    import Generics.Deriving.Base

    #if MIN_VERSION_base(4,6,0)
    import Data.Ord (Down)
    #else
    import GHC.Exts (Down)
    #endif

    #if MIN_VERSION_base(4,7,0)
    import Data.Proxy (Proxy)
    #endif

    #if MIN_VERSION_base(4,8,0)
    import Data.Functor.Identity (Identity)
    import Data.Void (Void)
    #endif

    #if MIN_VERSION_base(4,9,0)
    import Data.List.NonEmpty (NonEmpty(..))
    import Data.Semigroup as Semigroup
    #endif

    -------------------------------------------------------------------------------

    infixr 6 `gsappend'`
    class GSemigroup' f where
      gsappend' :: f x -> f x -> f x

    instance GSemigroup' U1 where
      gsappend' :: U1 x -> U1 x -> U1 x
    gsappend' U1 U1 = U1 x
    forall k (p :: k). U1 p
    U1

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

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

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

    -------------------------------------------------------------------------------

    infixr 6 `gsappend`
    class GSemigroup a where
      gsappend :: a -> a -> a
    #if __GLASGOW_HASKELL__ >= 701
      default gsappend :: (Generic a, GSemigroup' (Rep a)) => a -> a -> a
      gsappend = a -> a -> a
    forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault
    #endif

      gstimes :: Integral b => b -> a -> a
      gstimes y0 :: b
    y0 x0 :: a
    x0
        | b
    y0 b -> b -> Bool
    forall a. Ord a => a -> a -> Bool
    <= 0   = [Char] -> a
    forall a. HasCallStack => [Char] -> a
    error "gstimes: positive multiplier expected"
        | Bool
    otherwise = a -> b -> a
    forall a a. (Integral a, GSemigroup a) => a -> a -> a
    f a
    x0 b
    y0
        where
          f :: a -> a -> a
    f x :: a
    x y :: a
    y
            | a -> Bool
    forall a. Integral a => a -> Bool
    even a
    y = a -> a -> a
    f (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    x) (a
    y a -> a -> a
    forall a. Integral a => a -> a -> a
    `quot` 2)
            | a
    y a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == 1 = a
    x
            | Bool
    otherwise = a -> a -> a -> a
    forall a a. (Integral a, GSemigroup a) => a -> a -> a -> a
    g (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    x) (a -> a
    forall a. Enum a => a -> a
    pred a
    y  a -> a -> a
    forall a. Integral a => a -> a -> a
    `quot` 2) a
    x
          g :: a -> a -> a -> a
    g x :: a
    x y :: a
    y z :: a
    z
            | a -> Bool
    forall a. Integral a => a -> Bool
    even a
    y = a -> a -> a -> a
    g (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    x) (a
    y a -> a -> a
    forall a. Integral a => a -> a -> a
    `quot` 2) a
    z
            | a
    y a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == 1 = a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    z
            | Bool
    otherwise = a -> a -> a -> a
    g (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    x) (a -> a
    forall a. Enum a => a -> a
    pred a
    y a -> a -> a
    forall a. Integral a => a -> a -> a
    `quot` 2) (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    z)

    #if MIN_VERSION_base(4,9,0)
      -- | Only available with @base-4.9@ or later
      gsconcat :: NonEmpty a -> a
      gsconcat (a :: a
    a :| as :: [a]
    as) = a -> [a] -> a
    forall t. GSemigroup t => t -> [t] -> t
    go a
    a [a]
    as where
        go :: t -> [t] -> t
    go b :: t
    b (c :: t
    c:cs :: [t]
    cs) = t -> t -> t
    forall a. GSemigroup a => a -> a -> a
    gsappend t
    b (t -> [t] -> t
    go t
    c [t]
    cs)
        go b :: t
    b []     = t
    b
    #endif

    infixr 6 `gsappenddefault`
    gsappenddefault :: (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault :: a -> a -> a
    gsappenddefault 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 k (f :: k -> *) (x :: k). GSemigroup' f => f x -> f x -> f x
    gsappend' (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))

    -------------------------------------------------------------------------------

    -- Instances that reuse Monoid
    instance GSemigroup Ordering where
      gsappend :: Ordering -> Ordering -> Ordering
    gsappend = Ordering -> Ordering -> Ordering
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup () where
      gsappend :: () -> () -> ()
    gsappend = () -> () -> ()
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup Any where
      gsappend :: Any -> Any -> Any
    gsappend = Any -> Any -> Any
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup All where
      gsappend :: All -> All -> All
    gsappend = All -> All -> All
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup (Monoid.First a) where
      gsappend :: First a -> First a -> First a
    gsappend = First a -> First a -> First a
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup (Monoid.Last a) where
      gsappend :: Last a -> Last a -> Last a
    gsappend = Last a -> Last a -> Last a
    forall a. Monoid a => a -> a -> a
    mappend
    instance Num a => GSemigroup (Sum a) where
      gsappend :: Sum a -> Sum a -> Sum a
    gsappend = Sum a -> Sum a -> Sum a
    forall a. Monoid a => a -> a -> a
    mappend
    instance Num a => GSemigroup (Product a) where
      gsappend :: Product a -> Product a -> Product a
    gsappend = Product a -> Product a -> Product a
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup [a] where
      gsappend :: [a] -> [a] -> [a]
    gsappend = [a] -> [a] -> [a]
    forall a. Monoid a => a -> a -> a
    mappend
    instance GSemigroup (Endo a) where
      gsappend :: Endo a -> Endo a -> Endo a
    gsappend = Endo a -> Endo a -> Endo a
    forall a. Monoid a => a -> a -> a
    mappend
    #if MIN_VERSION_base(4,8,0)
    instance Alternative f => GSemigroup (Alt f a) where
      gsappend :: Alt f a -> Alt f a -> Alt f a
    gsappend = Alt f a -> Alt f a -> Alt f a
    forall a. Monoid a => a -> a -> a
    mappend
    #endif

    -- Handwritten instances
    instance GSemigroup a => GSemigroup (Dual a) where
      gsappend :: Dual a -> Dual a -> Dual a
    gsappend (Dual x :: a
    x) (Dual y :: a
    y) = a -> Dual a
    forall a. a -> Dual a
    Dual (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    y a
    x)
    instance GSemigroup a => GSemigroup (Maybe a) where
      gsappend :: Maybe a -> Maybe a -> Maybe a
    gsappend Nothing  x :: Maybe a
    x        = Maybe a
    x
      gsappend x :: Maybe a
    x        Nothing  = Maybe a
    x
      gsappend (Just x :: a
    x) (Just y :: a
    y) = a -> Maybe a
    forall a. a -> Maybe a
    Just (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    x a
    y)
    instance GSemigroup b => GSemigroup (a -> b) where
      gsappend :: (a -> b) -> (a -> b) -> a -> b
    gsappend f :: a -> b
    f g :: a -> b
    g x :: a
    x = b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend (a -> b
    f a
    x) (a -> b
    g a
    x)
    instance GSemigroup a => GSemigroup (Const a b) where
      gsappend :: Const a b -> Const a b -> Const a b
    gsappend = Const a b -> Const a b -> Const a b
    forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault
    instance GSemigroup a => GSemigroup (Down a) where
      gsappend :: Down a -> Down a -> Down a
    gsappend = Down a -> Down a -> Down a
    forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault
    instance GSemigroup (Either a b) where
      gsappend :: Either a b -> Either a b -> Either a b
    gsappend Left{} b :: Either a b
    b = Either a b
    b
      gsappend a :: Either a b
    a      _ = Either a b
    a

    #if MIN_VERSION_base(4,7,0)
    instance GSemigroup
    # if MIN_VERSION_base(4,9,0)
                     (Proxy s)
    # else
                     (Proxy (s :: *))
    # endif
                     where
      gsappend :: Proxy s -> Proxy s -> Proxy s
    gsappend    = Proxy s -> Proxy s -> Proxy s
    forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault
    #endif

    #if MIN_VERSION_base(4,8,0)
    instance GSemigroup a => GSemigroup (Identity a) where
      gsappend :: Identity a -> Identity a -> Identity a
    gsappend = Identity a -> Identity a -> Identity a
    forall a. (Generic a, GSemigroup' (Rep a)) => a -> a -> a
    gsappenddefault

    instance GSemigroup Void where
      gsappend :: Void -> Void -> Void
    gsappend a :: Void
    a _ = Void
    a
    #endif

    #if MIN_VERSION_base(4,9,0)
    instance GSemigroup (Semigroup.First a) where
      gsappend :: First a -> First a -> First a
    gsappend = First a -> First a -> First a
    forall a. Semigroup a => a -> a -> a
    (<>)

    instance GSemigroup (Semigroup.Last a) where
      gsappend :: Last a -> Last a -> Last a
    gsappend = Last a -> Last a -> Last a
    forall a. Semigroup a => a -> a -> a
    (<>)

    instance Ord a => GSemigroup (Max a) where
      gsappend :: Max a -> Max a -> Max a
    gsappend = Max a -> Max a -> Max a
    forall a. Semigroup a => a -> a -> a
    (<>)

    instance Ord a => GSemigroup (Min a) where
      gsappend :: Min a -> Min a -> Min a
    gsappend = Min a -> Min a -> Min a
    forall a. Semigroup a => a -> a -> a
    (<>)

    instance GSemigroup (NonEmpty a) where
      gsappend :: NonEmpty a -> NonEmpty a -> NonEmpty a
    gsappend = NonEmpty a -> NonEmpty a -> NonEmpty a
    forall a. Semigroup a => a -> a -> a
    (<>)

    instance GSemigroup a => GSemigroup (Option a) where
      gsappend :: Option a -> Option a -> Option a
    gsappend (Option a :: Maybe a
    a) (Option b :: Maybe a
    b) = Maybe a -> Option a
    forall a. Maybe a -> Option a
    Option (Maybe a -> Maybe a -> Maybe a
    forall a. GSemigroup a => a -> a -> a
    gsappend Maybe a
    a Maybe a
    b)
    #endif

    -- Tuple instances
    instance (GSemigroup a,GSemigroup b) => GSemigroup (a,b) where
      gsappend :: (a, b) -> (a, b) -> (a, b)
    gsappend (a1 :: a
    a1,b1 :: b
    b1) (a2 :: a
    a2,b2 :: b
    b2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c) => GSemigroup (a,b,c) where
      gsappend :: (a, b, c) -> (a, b, c) -> (a, b, c)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c,GSemigroup d) => GSemigroup (a,b,c,d) where
      gsappend :: (a, b, c, d) -> (a, b, c, d) -> (a, b, c, d)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1,d1 :: d
    d1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2,d2 :: d
    d2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2,d -> d -> d
    forall a. GSemigroup a => a -> a -> a
    gsappend d
    d1 d
    d2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c,GSemigroup d,GSemigroup e) => GSemigroup (a,b,c,d,e) where
      gsappend :: (a, b, c, d, e) -> (a, b, c, d, e) -> (a, b, c, d, e)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1,d1 :: d
    d1,e1 :: e
    e1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2,d2 :: d
    d2,e2 :: e
    e2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2,d -> d -> d
    forall a. GSemigroup a => a -> a -> a
    gsappend d
    d1 d
    d2,e -> e -> e
    forall a. GSemigroup a => a -> a -> a
    gsappend e
    e1 e
    e2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c,GSemigroup d,GSemigroup e,GSemigroup f) => GSemigroup (a,b,c,d,e,f) where
      gsappend :: (a, b, c, d, e, f) -> (a, b, c, d, e, f) -> (a, b, c, d, e, f)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1,d1 :: d
    d1,e1 :: e
    e1,f1 :: f
    f1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2,d2 :: d
    d2,e2 :: e
    e2,f2 :: f
    f2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2,d -> d -> d
    forall a. GSemigroup a => a -> a -> a
    gsappend d
    d1 d
    d2,e -> e -> e
    forall a. GSemigroup a => a -> a -> a
    gsappend e
    e1 e
    e2,f -> f -> f
    forall a. GSemigroup a => a -> a -> a
    gsappend f
    f1 f
    f2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c,GSemigroup d,GSemigroup e,GSemigroup f,GSemigroup g) => GSemigroup (a,b,c,d,e,f,g) where
      gsappend :: (a, b, c, d, e, f, g)
    -> (a, b, c, d, e, f, g) -> (a, b, c, d, e, f, g)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1,d1 :: d
    d1,e1 :: e
    e1,f1 :: f
    f1,g1 :: g
    g1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2,d2 :: d
    d2,e2 :: e
    e2,f2 :: f
    f2,g2 :: g
    g2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2,d -> d -> d
    forall a. GSemigroup a => a -> a -> a
    gsappend d
    d1 d
    d2,e -> e -> e
    forall a. GSemigroup a => a -> a -> a
    gsappend e
    e1 e
    e2,f -> f -> f
    forall a. GSemigroup a => a -> a -> a
    gsappend f
    f1 f
    f2,g -> g -> g
    forall a. GSemigroup a => a -> a -> a
    gsappend g
    g1 g
    g2)
    instance (GSemigroup a,GSemigroup b,GSemigroup c,GSemigroup d,GSemigroup e,GSemigroup f,GSemigroup g,GSemigroup h) => GSemigroup (a,b,c,d,e,f,g,h) where
      gsappend :: (a, b, c, d, e, f, g, h)
    -> (a, b, c, d, e, f, g, h) -> (a, b, c, d, e, f, g, h)
    gsappend (a1 :: a
    a1,b1 :: b
    b1,c1 :: c
    c1,d1 :: d
    d1,e1 :: e
    e1,f1 :: f
    f1,g1 :: g
    g1,h1 :: h
    h1) (a2 :: a
    a2,b2 :: b
    b2,c2 :: c
    c2,d2 :: d
    d2,e2 :: e
    e2,f2 :: f
    f2,g2 :: g
    g2,h2 :: h
    h2) =
        (a -> a -> a
    forall a. GSemigroup a => a -> a -> a
    gsappend a
    a1 a
    a2,b -> b -> b
    forall a. GSemigroup a => a -> a -> a
    gsappend b
    b1 b
    b2,c -> c -> c
    forall a. GSemigroup a => a -> a -> a
    gsappend c
    c1 c
    c2,d -> d -> d
    forall a. GSemigroup a => a -> a -> a
    gsappend d
    d1 d
    d2,e -> e -> e
    forall a. GSemigroup a => a -> a -> a
    gsappend e
    e1 e
    e2,f -> f -> f
    forall a. GSemigroup a => a -> a -> a
    gsappend f
    f1 f
    f2,g -> g -> g
    forall a. GSemigroup a => a -> a -> a
    gsappend g
    g1 g
    g2,h -> h -> h
    forall a. GSemigroup a => a -> a -> a
    gsappend h
    h1 h
    h2)