{-# LANGUAGE CPP #-}
{-# LANGUAGE ViewPatterns #-}

-- | Provides the 'AMonoid' typeclass.
--
-- @since 0.1
module Numeric.Algebra.Additive.AMonoid
  ( AMonoid (..),
    pattern Zero,
    pattern NonZero,
  )
where

import Data.Complex (Complex)
import Data.Fixed (Fixed, HasResolution)
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Kind (Constraint, Type)
import Data.Ratio (Ratio)
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.Natural (Natural)
import Numeric.Algebra.Additive.ASemigroup (ASemigroup)

-- | Defines a monoid over an additive semigroup.
--
-- @since 0.1
type AMonoid :: Type -> Constraint
class (ASemigroup m) => AMonoid m where
  -- | Should satisfy:
  --
  -- @
  -- -- identity
  -- x .+. zero = x = zero .+. x
  -- @since 0.1
  zero :: m

-- | Pattern synonym for 'zero'.
--
-- @since 0.1
pattern Zero :: (AMonoid m, Eq m) => m
pattern $mZero :: forall {r} {m}.
(AMonoid m, Eq m) =>
m -> ((# #) -> r) -> ((# #) -> r) -> r
$bZero :: forall m. (AMonoid m, Eq m) => m
Zero <- ((== zero) -> True)
  where
    Zero = m
forall m. AMonoid m => m
zero

-- | Pattern synonym for @x /= 'zero'@.
--
-- @since 0.1
pattern NonZero :: (AMonoid m, Eq m) => m -> m
pattern $mNonZero :: forall {r} {m}.
(AMonoid m, Eq m) =>
m -> (m -> r) -> ((# #) -> r) -> r
NonZero y <- (\m
x -> (m
x m -> m -> Bool
forall a. Eq a => a -> a -> Bool
== m
forall m. AMonoid m => m
zero, m
x) -> (False, y))

-- NOTE: [Pattern Synonym COMPLETE]
--
-- Such COMPLETE pragmas not supported in GHC < 9.2:
--
-- - https://gitlab.haskell.org/ghc/ghc/-/issues/19160
-- - https://gitlab.haskell.org/ghc/ghc/-/issues/14422

#if MIN_VERSION_base(4, 16, 0)
{-# COMPLETE Zero, NonZero #-}
#endif

-- | @since 0.1
instance AMonoid Double where
  zero :: Double
zero = Double
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Float where
  zero :: Float
zero = Float
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Int where
  zero :: Int
zero = Int
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Int8 where
  zero :: Int8
zero = Int8
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Int16 where
  zero :: Int16
zero = Int16
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Int32 where
  zero :: Int32
zero = Int32
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Int64 where
  zero :: Int64
zero = Int64
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Integer where
  zero :: Integer
zero = Integer
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Word where
  zero :: Word
zero = Word
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Word8 where
  zero :: Word8
zero = Word8
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Word16 where
  zero :: Word16
zero = Word16
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Word32 where
  zero :: Word32
zero = Word32
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Word64 where
  zero :: Word64
zero = Word64
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid Natural where
  zero :: Natural
zero = Natural
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid (Ratio Integer) where
  zero :: Ratio Integer
zero = Ratio Integer
0
  {-# INLINE zero #-}

-- | @since 0.1
instance AMonoid (Ratio Natural) where
  zero :: Ratio Natural
zero = Ratio Natural
0
  {-# INLINE zero #-}

-- | @since 0.1
instance (RealFloat a) => AMonoid (Complex a) where
  zero :: Complex a
zero = Complex a
0
  {-# INLINE zero #-}

-- | @since 0.1
instance (HasResolution k) => AMonoid (Fixed k) where
  zero :: Fixed k
zero = Fixed k
0
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a) where
  zero :: (a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a) where
  zero :: (a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a) where
  zero :: (a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a, a) where
  zero :: (a, a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a, a, a) where
  zero :: (a, a, a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a, a, a, a) where
  zero :: (a, a, a, a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a, a, a, a, a) where
  zero :: (a, a, a, a, a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}

-- | @since 0.1
instance (AMonoid a) => AMonoid (a, a, a, a, a, a, a, a, a) where
  zero :: (a, a, a, a, a, a, a, a, a)
zero = (a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero, a
forall m. AMonoid m => m
zero)
  {-# INLINE zero #-}