    {-# LANGUAGE CPP               #-}
    {-# LANGUAGE MagicHash         #-}
    {-# LANGUAGE UndecidableInstances #-}
    {-# LANGUAGE DefaultSignatures #-}
    {-# OPTIONS_GHC -fno-prof-auto #-}
    module Basement.Numerical.Additive
        ( Additive(..)
        ) where

    #include "MachDeps.h"

    import           Basement.Compat.Base
    import           Basement.Compat.C.Types
    import           Basement.Compat.Natural
    import           Basement.Numerical.Number
    import qualified Prelude
    import           GHC.Types
    import           GHC.Prim
    import           GHC.Int
    import           GHC.Word
    import           Basement.Bounded
    import           Basement.Nat
    import           Basement.Types.Word128 (Word128)
    import           Basement.Types.Word256 (Word256)
    import qualified Basement.Types.Word128 as Word128
    import qualified Basement.Types.Word256 as Word256

    #if WORD_SIZE_IN_BITS < 64
    import           GHC.IntWord64
    #endif

    -- | Represent class of things that can be added together,
    -- contains a neutral element and is commutative.
    --
    -- > x + azero = x
    -- > azero + x = x
    -- > x + y = y + x
    --
    class Additive a where
        {-# MINIMAL azero, (+) #-}
        azero :: a           -- the identity element over addition
        (+)   :: a -> a -> a -- the addition

        scale :: IsNatural n => n -> a -> a -- scale: repeated addition
        default scale :: (Enum n, IsNatural n) => n -> a -> a
        scale = n -> a -> a
    forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
    scaleEnum

    scaleEnum :: (Enum n, IsNatural n, Additive a) => n -> a -> a
    scaleEnum :: n -> a -> a
    scaleEnum 0 _ = a
    forall a. Additive a => a
    azero
    scaleEnum 1 a :: a
    a = a
    a
    scaleEnum 2 a :: a
    a = a
    a a -> a -> a
    forall a. Additive a => a -> a -> a
    + a
    a
    scaleEnum n :: n
    n a :: a
    a = a
    a a -> a -> a
    forall a. Additive a => a -> a -> a
    + n -> a -> a
    forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
    scaleEnum (n -> n
    forall a. Enum a => a -> a
    pred n
    n) a
    a -- TODO optimise. define by group of 2.

    infixl 6 +

    instance Additive Integer where
        azero :: Integer
    azero = 0
        + :: Integer -> Integer -> Integer
    (+) = Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> Integer -> Integer
    scale = n -> Integer -> Integer
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Int where
        azero :: Int
    azero = 0
        (I# a :: Int#
    a) + :: Int -> Int -> Int
    + (I# b :: Int#
    b) = Int# -> Int
    I# (Int#
    a Int# -> Int# -> Int#
    +# Int#
    b)
        scale :: n -> Int -> Int
    scale = n -> Int -> Int
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Int8 where
        azero :: Int8
    azero = 0
        (I8# a :: Int#
    a) + :: Int8 -> Int8 -> Int8
    + (I8# b :: Int#
    b) = Int# -> Int8
    I8# (Int# -> Int#
    narrow8Int# (Int#
    a Int# -> Int# -> Int#
    +# Int#
    b))
        scale :: n -> Int8 -> Int8
    scale = n -> Int8 -> Int8
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Int16 where
        azero :: Int16
    azero = 0
        (I16# a :: Int#
    a) + :: Int16 -> Int16 -> Int16
    + (I16# b :: Int#
    b) = Int# -> Int16
    I16# (Int# -> Int#
    narrow16Int# (Int#
    a Int# -> Int# -> Int#
    +# Int#
    b))
        scale :: n -> Int16 -> Int16
    scale = n -> Int16 -> Int16
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Int32 where
        azero :: Int32
    azero = 0
        (I32# a :: Int#
    a) + :: Int32 -> Int32 -> Int32
    + (I32# b :: Int#
    b) = Int# -> Int32
    I32# (Int# -> Int#
    narrow32Int# (Int#
    a Int# -> Int# -> Int#
    +# Int#
    b))
        scale :: n -> Int32 -> Int32
    scale = n -> Int32 -> Int32
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Int64 where
        azero :: Int64
    azero = 0
    #if WORD_SIZE_IN_BITS == 64
        (I64# a :: Int#
    a) + :: Int64 -> Int64 -> Int64
    + (I64# b :: Int#
    b) = Int# -> Int64
    I64# (Int#
    a Int# -> Int# -> Int#
    +# Int#
    b)
    #else
        (I64# a) + (I64# b) = I64# (a `plusInt64#` b)
    #endif
        scale :: n -> Int64 -> Int64
    scale = n -> Int64 -> Int64
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word where
        azero :: Word
    azero = 0
        (W# a :: Word#
    a) + :: Word -> Word -> Word
    + (W# b :: Word#
    b) = Word# -> Word
    W# (Word#
    a Word# -> Word# -> Word#
    `plusWord#` Word#
    b)
        scale :: n -> Word -> Word
    scale = n -> Word -> Word
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Natural where
        azero :: Natural
    azero = 0
        + :: Natural -> Natural -> Natural
    (+) = Natural -> Natural -> Natural
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> Natural -> Natural
    scale = n -> Natural -> Natural
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word8 where
        azero :: Word8
    azero = 0
        (W8# a :: Word#
    a) + :: Word8 -> Word8 -> Word8
    + (W8# b :: Word#
    b) = Word# -> Word8
    W8# (Word# -> Word#
    narrow8Word# (Word#
    a Word# -> Word# -> Word#
    `plusWord#` Word#
    b))
        scale :: n -> Word8 -> Word8
    scale = n -> Word8 -> Word8
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word16 where
        azero :: Word16
    azero = 0
        (W16# a :: Word#
    a) + :: Word16 -> Word16 -> Word16
    + (W16# b :: Word#
    b) = Word# -> Word16
    W16# (Word# -> Word#
    narrow16Word# (Word#
    a Word# -> Word# -> Word#
    `plusWord#` Word#
    b))
        scale :: n -> Word16 -> Word16
    scale = n -> Word16 -> Word16
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word32 where
        azero :: Word32
    azero = 0
        (W32# a :: Word#
    a) + :: Word32 -> Word32 -> Word32
    + (W32# b :: Word#
    b) = Word# -> Word32
    W32# (Word# -> Word#
    narrow32Word# (Word#
    a Word# -> Word# -> Word#
    `plusWord#` Word#
    b))
        scale :: n -> Word32 -> Word32
    scale = n -> Word32 -> Word32
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word64 where
        azero :: Word64
    azero = 0
    #if WORD_SIZE_IN_BITS == 64
        (W64# a :: Word#
    a) + :: Word64 -> Word64 -> Word64
    + (W64# b :: Word#
    b) = Word# -> Word64
    W64# (Word#
    a Word# -> Word# -> Word#
    `plusWord#` Word#
    b)
    #else
        (W64# a) + (W64# b) = W64# (int64ToWord64# (word64ToInt64# a `plusInt64#` word64ToInt64# b))
    #endif
        scale :: n -> Word64 -> Word64
    scale = n -> Word64 -> Word64
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word128 where
        azero :: Word128
    azero = 0
        + :: Word128 -> Word128 -> Word128
    (+) = Word128 -> Word128 -> Word128
    (Word128.+)
        scale :: n -> Word128 -> Word128
    scale = n -> Word128 -> Word128
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Word256 where
        azero :: Word256
    azero = 0
        + :: Word256 -> Word256 -> Word256
    (+) = Word256 -> Word256 -> Word256
    (Word256.+)
        scale :: n -> Word256 -> Word256
    scale = n -> Word256 -> Word256
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Prelude.Float where
        azero :: Float
    azero = 0.0
        (F# a :: Float#
    a) + :: Float -> Float -> Float
    + (F# b :: Float#
    b) = Float# -> Float
    F# (Float#
    a Float# -> Float# -> Float#
    `plusFloat#` Float#
    b)
        scale :: n -> Float -> Float
    scale = n -> Float -> Float
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive Prelude.Double where
        azero :: Double
    azero = 0.0
        (D# a :: Double#
    a) + :: Double -> Double -> Double
    + (D# b :: Double#
    b) = Double# -> Double
    D# (Double#
    a Double# -> Double# -> Double#
    +## Double#
    b)
        scale :: n -> Double -> Double
    scale = n -> Double -> Double
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum

    instance (KnownNat n, NatWithinBound Word64 n) => Additive (Zn64 n) where
        azero :: Zn64 n
    azero = Word64 -> Zn64 n
    forall (n :: Nat).
    (KnownNat n, NatWithinBound Word64 n) =>
    Word64 -> Zn64 n
    zn64 0
        + :: Zn64 n -> Zn64 n -> Zn64 n
    (+) = Zn64 n -> Zn64 n -> Zn64 n
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> Zn64 n -> Zn64 n
    scale = n -> Zn64 n -> Zn64 n
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance KnownNat n => Additive (Zn n) where
        azero :: Zn n
    azero = Natural -> Zn n
    forall (n :: Nat). KnownNat n => Natural -> Zn n
    zn 0
        + :: Zn n -> Zn n -> Zn n
    (+) = Zn n -> Zn n -> Zn n
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> Zn n -> Zn n
    scale = n -> Zn n -> Zn n
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum

    instance Additive CChar where
        azero :: CChar
    azero = 0
        + :: CChar -> CChar -> CChar
    (+) = CChar -> CChar -> CChar
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CChar -> CChar
    scale = n -> CChar -> CChar
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CSChar where
        azero :: CSChar
    azero = 0
        + :: CSChar -> CSChar -> CSChar
    (+) = CSChar -> CSChar -> CSChar
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CSChar -> CSChar
    scale = n -> CSChar -> CSChar
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUChar where
        azero :: CUChar
    azero = 0
        + :: CUChar -> CUChar -> CUChar
    (+) = CUChar -> CUChar -> CUChar
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUChar -> CUChar
    scale = n -> CUChar -> CUChar
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CShort where
        azero :: CShort
    azero = 0
        + :: CShort -> CShort -> CShort
    (+) = CShort -> CShort -> CShort
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CShort -> CShort
    scale = n -> CShort -> CShort
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUShort where
        azero :: CUShort
    azero = 0
        + :: CUShort -> CUShort -> CUShort
    (+) = CUShort -> CUShort -> CUShort
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUShort -> CUShort
    scale = n -> CUShort -> CUShort
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CInt where
        azero :: CInt
    azero = 0
        + :: CInt -> CInt -> CInt
    (+) = CInt -> CInt -> CInt
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CInt -> CInt
    scale = n -> CInt -> CInt
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUInt where
        azero :: CUInt
    azero = 0
        + :: CUInt -> CUInt -> CUInt
    (+) = CUInt -> CUInt -> CUInt
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUInt -> CUInt
    scale = n -> CUInt -> CUInt
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CLong where
        azero :: CLong
    azero = 0
        + :: CLong -> CLong -> CLong
    (+) = CLong -> CLong -> CLong
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CLong -> CLong
    scale = n -> CLong -> CLong
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CULong where
        azero :: CULong
    azero = 0
        + :: CULong -> CULong -> CULong
    (+) = CULong -> CULong -> CULong
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CULong -> CULong
    scale = n -> CULong -> CULong
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CPtrdiff where
        azero :: CPtrdiff
    azero = 0
        + :: CPtrdiff -> CPtrdiff -> CPtrdiff
    (+) = CPtrdiff -> CPtrdiff -> CPtrdiff
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CPtrdiff -> CPtrdiff
    scale = n -> CPtrdiff -> CPtrdiff
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CSize where
        azero :: CSize
    azero = 0
        + :: CSize -> CSize -> CSize
    (+) = CSize -> CSize -> CSize
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CSize -> CSize
    scale = n -> CSize -> CSize
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CWchar where
        azero :: CWchar
    azero = 0
        + :: CWchar -> CWchar -> CWchar
    (+) = CWchar -> CWchar -> CWchar
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CWchar -> CWchar
    scale = n -> CWchar -> CWchar
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CSigAtomic where
        azero :: CSigAtomic
    azero = 0
        + :: CSigAtomic -> CSigAtomic -> CSigAtomic
    (+) = CSigAtomic -> CSigAtomic -> CSigAtomic
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CSigAtomic -> CSigAtomic
    scale = n -> CSigAtomic -> CSigAtomic
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CLLong where
        azero :: CLLong
    azero = 0
        + :: CLLong -> CLLong -> CLLong
    (+) = CLLong -> CLLong -> CLLong
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CLLong -> CLLong
    scale = n -> CLLong -> CLLong
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CULLong where
        azero :: CULLong
    azero = 0
        + :: CULLong -> CULLong -> CULLong
    (+) = CULLong -> CULLong -> CULLong
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CULLong -> CULLong
    scale = n -> CULLong -> CULLong
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CIntPtr where
        azero :: CIntPtr
    azero = 0
        + :: CIntPtr -> CIntPtr -> CIntPtr
    (+) = CIntPtr -> CIntPtr -> CIntPtr
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CIntPtr -> CIntPtr
    scale = n -> CIntPtr -> CIntPtr
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUIntPtr where
        azero :: CUIntPtr
    azero = 0
        + :: CUIntPtr -> CUIntPtr -> CUIntPtr
    (+) = CUIntPtr -> CUIntPtr -> CUIntPtr
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUIntPtr -> CUIntPtr
    scale = n -> CUIntPtr -> CUIntPtr
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CIntMax where
        azero :: CIntMax
    azero = 0
        + :: CIntMax -> CIntMax -> CIntMax
    (+) = CIntMax -> CIntMax -> CIntMax
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CIntMax -> CIntMax
    scale = n -> CIntMax -> CIntMax
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUIntMax where
        azero :: CUIntMax
    azero = 0
        + :: CUIntMax -> CUIntMax -> CUIntMax
    (+) = CUIntMax -> CUIntMax -> CUIntMax
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUIntMax -> CUIntMax
    scale = n -> CUIntMax -> CUIntMax
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CClock where
        azero :: CClock
    azero = 0
        + :: CClock -> CClock -> CClock
    (+) = CClock -> CClock -> CClock
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CClock -> CClock
    scale = n -> CClock -> CClock
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CTime where
        azero :: CTime
    azero = 0
        + :: CTime -> CTime -> CTime
    (+) = CTime -> CTime -> CTime
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CTime -> CTime
    scale = n -> CTime -> CTime
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CUSeconds where
        azero :: CUSeconds
    azero = 0
        + :: CUSeconds -> CUSeconds -> CUSeconds
    (+) = CUSeconds -> CUSeconds -> CUSeconds
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CUSeconds -> CUSeconds
    scale = n -> CUSeconds -> CUSeconds
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CSUSeconds where
        azero :: CSUSeconds
    azero = 0
        + :: CSUSeconds -> CSUSeconds -> CSUSeconds
    (+) = CSUSeconds -> CSUSeconds -> CSUSeconds
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CSUSeconds -> CSUSeconds
    scale = n -> CSUSeconds -> CSUSeconds
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive COff where
        azero :: COff
    azero = 0
        + :: COff -> COff -> COff
    (+) = COff -> COff -> COff
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> COff -> COff
    scale = n -> COff -> COff
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum

    instance Additive CFloat where
        azero :: CFloat
    azero = 0
        + :: CFloat -> CFloat -> CFloat
    (+) = CFloat -> CFloat -> CFloat
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CFloat -> CFloat
    scale = n -> CFloat -> CFloat
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum
    instance Additive CDouble where
        azero :: CDouble
    azero = 0
        + :: CDouble -> CDouble -> CDouble
    (+) = CDouble -> CDouble -> CDouble
    forall a. Num a => a -> a -> a
    (Prelude.+)
        scale :: n -> CDouble -> CDouble
    scale = n -> CDouble -> CDouble
    forall a n. (Num a, IsNatural n) => n -> a -> a
    scaleNum

    scaleNum :: (Prelude.Num a, IsNatural n) => n -> a -> a
    scaleNum :: n -> a -> a
    scaleNum n :: n
    n a :: a
    a = (Natural -> a
    forall a b. (Integral a, Num b) => a -> b
    Prelude.fromIntegral (Natural -> a) -> Natural -> a
    forall a b. (a -> b) -> a -> b
    $ n -> Natural
    forall a. IsNatural a => a -> Natural
    toNatural n
    n) a -> a -> a
    forall a. Num a => a -> a -> a
    Prelude.* a
    a