content: {-# LANGUAGE
      CPP,
      DataKinds,
      PolyKinds,
      TypeFamilies,
      TypeOperators,
      UndecidableInstances #-}
  
  -- | Semigroups and monoids.
  module Fcf.Class.Monoid
    ( -- * Pure type families
      -- | Nicer to use when applied explicitly.
      type (<>)
    , MEmpty
  
      -- * First-class families
      -- | Can be composed and passed to higher-order functions.
    , type (.<>)
    , MEmpty_
    ) where
  
  import Fcf.Core (Exp, Eval)
  import Data.Monoid (All(..), Any(..))
  import Data.Type.Bool (type (&&), type (||))
  
  #if __GLASGOW_HASKELL__ >= 802
  import GHC.TypeLits (AppendSymbol)
  #endif
  
  -- $setup
  -- >>> import GHC.TypeLits (Nat)
  -- >>> import Numeric.Natural (Natural)
  
  -- | Type-level semigroup composition @('Data.Semigroup.<>')@.
  --
  -- This is the fcf-encoding of @('<>')@.
  -- To define a new semigroup, add type instances to @('<>')@.
  data (.<>) :: a -> a -> Exp a
  type instance Eval (x .<> y) = x <> y
  
  -- | Type-level semigroup composition @('Data.Semigroup.<>')@.
  type family (<>) (x :: a) (y :: a) :: a
  
  -- (,)
  type instance (<>) '(a1, a2) '(b1, b2) = '(a1 <> b1, a2 <> b2)
  
  -- (,,)
  type instance (<>) '(a1, a2, a3) '(b1, b2, b3) = '(a1 <> b1, a2 <> b2, a3 <> b3)
  
  -- List
  type instance (<>) '[] ys = ys
  type instance (<>) (x ': xs) ys = x ': (<>) xs ys
  
  -- Maybe
  type instance (<>) 'Nothing b = b
  type instance (<>) a 'Nothing = a
  type instance (<>) ('Just a) ('Just b) = 'Just (a <> b)
  
  -- Ordering
  type instance (<>) 'EQ b = b
  type instance (<>) a 'EQ = a
  type instance (<>) 'LT _b = 'LT
  type instance (<>) 'GT _b = 'GT
  
  -- ()
  type instance (<>) _a _b = '()
  
  -- All
  type instance (<>) ('All a) ('All b) = 'All (a && b)
  
  -- Any
  type instance (<>) ('Any a) ('Any b) = 'Any (a || b)
  
  #if __GLASGOW_HASKELL__ >= 802
  -- Symbol
  -- | With /base >= 4.10.0.0/.
  type instance (<>) x y = AppendSymbol x y
  #endif
  
  -- | Type-level monoid identity 'Data.Monoid.mempty'.
  --
  -- This is the fcf-encoding of 'MEmpty'.
  data MEmpty_ :: Exp a
  type instance Eval MEmpty_ = MEmpty
  
  -- | Type-level monoid identity 'Data.Monoid.mempty'.
  --
  -- === __Examples__
  --
  -- >>> :kind! LT <> MEmpty
  -- LT <> MEmpty :: Ordering
  -- = LT
  --
  -- >>> :kind! MEmpty <> '(EQ, [1, 2])
  -- MEmpty <> '(EQ, [1, 2]) :: (Ordering, [Natural])
  -- = '(EQ, [1, 2])
  --
  -- >>> :kind! '(GT, Just '()) <> MEmpty
  -- '(GT, Just '()) <> MEmpty :: (Ordering, Maybe ())
  -- = '(GT, Just '())
  type family MEmpty :: a
  
  -- (,)
  type instance MEmpty = '(MEmpty, MEmpty)
  
  -- (,,)
  type instance MEmpty = '(MEmpty, MEmpty, MEmpty)
  
  -- List
  type instance MEmpty = '[]
  
  -- Maybe
  type instance MEmpty = 'Nothing
  
  -- Ordering
  type instance MEmpty = 'EQ
  
  -- ()
  type instance MEmpty = '()
  
  -- All
  type instance MEmpty = 'All 'True
  
  -- Any
  type instance MEmpty = 'Any 'False
  
  -- Symbol
  type instance MEmpty = ""
  