{-# 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 = scaleEnum scaleEnum :: (Enum n, IsNatural n, Additive a) => n -> a -> a scaleEnum 0 _ = azero scaleEnum 1 a = a scaleEnum 2 a = a + a scaleEnum n a = a + scaleEnum (pred n) a -- TODO optimise. define by group of 2. infixl 6 + instance Additive Integer where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive Int where azero = 0 (I# a) + (I# b) = I# (a +# b) scale = scaleNum instance Additive Int8 where azero = 0 (I8# a) + (I8# b) = I8# (narrow8Int# (a +# b)) scale = scaleNum instance Additive Int16 where azero = 0 (I16# a) + (I16# b) = I16# (narrow16Int# (a +# b)) scale = scaleNum instance Additive Int32 where azero = 0 (I32# a) + (I32# b) = I32# (narrow32Int# (a +# b)) scale = scaleNum instance Additive Int64 where azero = 0 #if WORD_SIZE_IN_BITS == 64 (I64# a) + (I64# b) = I64# (a +# b) #else (I64# a) + (I64# b) = I64# (a `plusInt64#` b) #endif scale = scaleNum instance Additive Word where azero = 0 (W# a) + (W# b) = W# (a `plusWord#` b) scale = scaleNum instance Additive Natural where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive Word8 where azero = 0 (W8# a) + (W8# b) = W8# (narrow8Word# (a `plusWord#` b)) scale = scaleNum instance Additive Word16 where azero = 0 (W16# a) + (W16# b) = W16# (narrow16Word# (a `plusWord#` b)) scale = scaleNum instance Additive Word32 where azero = 0 (W32# a) + (W32# b) = W32# (narrow32Word# (a `plusWord#` b)) scale = scaleNum instance Additive Word64 where azero = 0 #if WORD_SIZE_IN_BITS == 64 (W64# a) + (W64# b) = W64# (a `plusWord#` b) #else (W64# a) + (W64# b) = W64# (int64ToWord64# (word64ToInt64# a `plusInt64#` word64ToInt64# b)) #endif scale = scaleNum instance Additive Word128 where azero = 0 (+) = (Word128.+) scale = scaleNum instance Additive Word256 where azero = 0 (+) = (Word256.+) scale = scaleNum instance Additive Prelude.Float where azero = 0.0 (F# a) + (F# b) = F# (a `plusFloat#` b) scale = scaleNum instance Additive Prelude.Double where azero = 0.0 (D# a) + (D# b) = D# (a +## b) scale = scaleNum instance (KnownNat n, NatWithinBound Word64 n) => Additive (Zn64 n) where azero = zn64 0 (+) = (Prelude.+) scale = scaleNum instance KnownNat n => Additive (Zn n) where azero = zn 0 (+) = (Prelude.+) scale = scaleNum instance Additive CChar where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CSChar where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUChar where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CShort where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUShort where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CInt where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUInt where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CLong where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CULong where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CPtrdiff where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CSize where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CWchar where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CSigAtomic where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CLLong where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CULLong where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CIntPtr where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUIntPtr where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CIntMax where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUIntMax where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CClock where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CTime where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CUSeconds where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CSUSeconds where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive COff where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CFloat where azero = 0 (+) = (Prelude.+) scale = scaleNum instance Additive CDouble where azero = 0 (+) = (Prelude.+) scale = scaleNum scaleNum :: (Prelude.Num a, IsNatural n) => n -> a -> a scaleNum n a = (Prelude.fromIntegral $ toNatural n) Prelude.* a