{-# LANGUAGE CPP               #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash         #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# 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.Compat.Primitive
import           Basement.Numerical.Number
import qualified Prelude
import           GHC.Types (Float(..), Double(..))
import           GHC.Prim (plusWord#, plusFloat#, (+#), (+##))
import qualified 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 = forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum

scaleEnum :: (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum :: forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum n
0 a
_ = forall a. Additive a => a
azero
scaleEnum n
1 a
a = a
a
scaleEnum n
2 a
a = a
a forall a. Additive a => a -> a -> a
+ a
a
scaleEnum n
n a
a = a
a forall a. Additive a => a -> a -> a
+ forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum (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 = Integer
0
    + :: Integer -> Integer -> Integer
(+) = forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: forall n. IsNatural n => n -> Integer -> Integer
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int where
    azero :: Int
azero = Int
0
    (I# Int#
a) + :: Int -> Int -> Int
+ (I# Int#
b) = Int# -> Int
I# (Int#
a Int# -> Int# -> Int#
+# Int#
b)
    scale :: forall n. IsNatural n => n -> Int -> Int
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int8 where
    azero :: Int8
azero = Int8
0
    (I8# Int8#
a) + :: Int8 -> Int8 -> Int8
+ (I8# Int8#
b) = Int8# -> Int8
I8# (Int8#
a Int8# -> Int8# -> Int8#
`plusInt8#` Int8#
b)
    scale :: forall n. IsNatural n => n -> Int8 -> Int8
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int16 where
    azero :: Int16
azero = Int16
0
    (I16# Int16#
a) + :: Int16 -> Int16 -> Int16
+ (I16# Int16#
b) = Int16# -> Int16
I16# (Int16#
a Int16# -> Int16# -> Int16#
`plusInt16#` Int16#
b)
    scale :: forall n. IsNatural n => n -> Int16 -> Int16
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int32 where
    azero :: Int32
azero = Int32
0
    (I32# Int32#
a) + :: Int32 -> Int32 -> Int32
+ (I32# Int32#
b) = Int32# -> Int32
I32# (Int32#
a Int32# -> Int32# -> Int32#
`plusInt32#` Int32#
b)
    scale :: forall n. IsNatural n => n -> Int32 -> Int32
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int64 where
    azero :: Int64
azero = Int64
0
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
    (I64# a) + (I64# b) = I64# (GHC.Prim.intToInt64# (GHC.Prim.int64ToInt# a +# GHC.Prim.int64ToInt# b))

#else
    (I64# Int#
a) + :: Int64 -> Int64 -> Int64
+ (I64# Int#
b) = Int# -> Int64
I64# (Int#
a Int# -> Int# -> Int#
+# Int#
b)

#endif
#else
    (I64# a) + (I64# b) = I64# (a `plusInt64#` b)
#endif
    scale :: forall n. IsNatural n => n -> Int64 -> Int64
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word where
    azero :: Word
azero = Word
0
    (W# Word#
a) + :: Word -> Word -> Word
+ (W# Word#
b) = Word# -> Word
W# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b)
    scale :: forall n. IsNatural n => n -> Word -> Word
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Natural where
    azero :: Natural
azero = Natural
0
    + :: Natural -> Natural -> Natural
(+) = forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: forall n. IsNatural n => n -> Natural -> Natural
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word8 where
    azero :: Word8
azero = Word8
0
    (W8# Word8#
a) + :: Word8 -> Word8 -> Word8
+ (W8# Word8#
b) = Word8# -> Word8
W8# (Word8#
a Word8# -> Word8# -> Word8#
`plusWord8#` Word8#
b)
    scale :: forall n. IsNatural n => n -> Word8 -> Word8
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word16 where
    azero :: Word16
azero = Word16
0
    (W16# Word16#
a) + :: Word16 -> Word16 -> Word16
+ (W16# Word16#
b) = Word16# -> Word16
W16# (Word16#
a Word16# -> Word16# -> Word16#
`plusWord16#` Word16#
b)
    scale :: forall n. IsNatural n => n -> Word16 -> Word16
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word32 where
    azero :: Word32
azero = Word32
0
    (W32# Word32#
a) + :: Word32 -> Word32 -> Word32
+ (W32# Word32#
b) = Word32# -> Word32
W32# (Word32#
a Word32# -> Word32# -> Word32#
`plusWord32#` Word32#
b)
    scale :: forall n. IsNatural n => n -> Word32 -> Word32
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word64 where
    azero :: Word64
azero = Word64
0
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
    (W64# a) + (W64# b) = W64# (GHC.Prim.wordToWord64# (GHC.Prim.word64ToWord# a `plusWord#` GHC.Prim.word64ToWord# b))

#else
    (W64# Word#
a) + :: Word64 -> Word64 -> Word64
+ (W64# Word#
b) = Word# -> Word64
W64# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b)

#endif
#else
    (W64# a) + (W64# b) = W64# (int64ToWord64# (word64ToInt64# a `plusInt64#` word64ToInt64# b))
#endif
    scale :: forall n. IsNatural n => n -> Word64 -> Word64
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word128 where
    azero :: Word128
azero = Word128
0
    + :: Word128 -> Word128 -> Word128
(+) = Word128 -> Word128 -> Word128
(Word128.+)
    scale :: forall n. IsNatural n => n -> Word128 -> Word128
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word256 where
    azero :: Word256
azero = Word256
0
    + :: Word256 -> Word256 -> Word256
(+) = Word256 -> Word256 -> Word256
(Word256.+)
    scale :: forall n. IsNatural n => n -> Word256 -> Word256
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

instance Additive Prelude.Float where
    azero :: Float
azero = Float
0.0
    (F# Float#
a) + :: Float -> Float -> Float
+ (F# Float#
b) = Float# -> Float
F# (Float#
a Float# -> Float# -> Float#
`plusFloat#` Float#
b)
    scale :: forall n. IsNatural n => n -> Float -> Float
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Prelude.Double where
    azero :: Double
azero = Double
0.0
    (D# Double#
a) + :: Double -> Double -> Double
+ (D# Double#
b) = Double# -> Double
D# (Double#
a Double# -> Double# -> Double#
+## Double#
b)
    scale :: forall n. IsNatural n => n -> Double -> Double
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Prelude.Rational where
    azero :: Rational
azero = Rational
0.0
    + :: Rational -> Rational -> Rational
(+) = forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: forall n. IsNatural n => n -> Rational -> Rational
scale = 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 = forall (n :: Natural).
(KnownNat n, NatWithinBound Word64 n) =>
Word64 -> Zn64 n
zn64 Word64
0
    + :: Zn64 n -> Zn64 n -> Zn64 n
(+) = forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: forall n. IsNatural n => n -> Zn64 n -> Zn64 n
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance KnownNat n => Additive (Zn n) where
    azero :: Zn n
azero = forall (n :: Natural). KnownNat n => Natural -> Zn n
zn Natural
0
    + :: Zn n -> Zn n -> Zn n
(+) = forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: forall n. IsNatural n => n -> Zn n -> Zn n
scale = forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

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

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

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