    {-# LANGUAGE CPP                  #-}
    {-# LANGUAGE FlexibleContexts     #-}
    {-# LANGUAGE StandaloneDeriving   #-}
    {-# LANGUAGE UndecidableInstances #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Monoid.Endomorphism
    -- Copyright   :  (c) 2013-2015 diagrams-core team (see LICENSE)
    -- License     :  BSD-style (see LICENSE)
    -- Maintainer  :  diagrams-discuss@googlegroups.com
    --
    -- The monoid of endomorphisms over any 'Category'.
    --
    -----------------------------------------------------------------------------

    module Data.Monoid.Endomorphism
        ( Endomorphism(..)
        )
        where

    import           Control.Category
    import           Data.Group
    import           Data.Groupoid
    import           Data.Monoid       (Monoid(..))
    import           Data.Semigroup    (Semigroup(..))
    import           Data.Semigroupoid
    import           Prelude           (Show)

    -- | An 'Endomorphism' in a given 'Category' is a morphism from some
    --   object to itself.  The set of endomorphisms for a particular
    --   object form a monoid, with composition as the combining operation
    --   and the identity morphism as the identity element.
    newtype Endomorphism k a = Endomorphism {forall (k :: * -> * -> *) a. Endomorphism k a -> k a a
    getEndomorphism :: k a a}

    deriving instance Show (k a a) => Show (Endomorphism k a)

    instance Semigroupoid k => Semigroup (Endomorphism k a) where
      Endomorphism k a a
    a <> :: Endomorphism k a -> Endomorphism k a -> Endomorphism k a
    <> Endomorphism k a a
    b = k a a -> Endomorphism k a
    forall (k :: * -> * -> *) a. k a a -> Endomorphism k a
    Endomorphism (k a a
    a k a a -> k a a -> k a a
    forall j k1 i. k j k1 -> k i j -> k i k1
    forall {k} (c :: k -> k -> *) (j :: k) (k1 :: k) (i :: k).
    Semigroupoid c =>
    c j k1 -> c i j -> c i k1
    `o` k a a
    b)

    instance (Semigroupoid k, Category k) => Monoid (Endomorphism k a) where
      mempty :: Endomorphism k a
    mempty = k a a -> Endomorphism k a
    forall (k :: * -> * -> *) a. k a a -> Endomorphism k a
    Endomorphism k a a
    forall a. k a a
    forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    id
    #if !MIN_VERSION_base(4,11,0)
      Endomorphism a `mappend` Endomorphism b = Endomorphism (a . b)
    #endif

    instance (Category k, Groupoid k) => Group (Endomorphism k a) where
      invert :: Endomorphism k a -> Endomorphism k a
    invert (Endomorphism k a a
    a) = k a a -> Endomorphism k a
    forall (k :: * -> * -> *) a. k a a -> Endomorphism k a
    Endomorphism (k a a -> k a a
    forall a b. k a b -> k b a
    forall {k} (k1 :: k -> k -> *) (a :: k) (b :: k).
    Groupoid k1 =>
    k1 a b -> k1 b a
    inv k a a
    a)