module Data.Semigroup.Means ( -- * Arithmetic mean AM , amWeight , amSum , am , am' , getAM -- * Geometric mean , GM , gmWeight , gmProduct , gm , getGM -- * Harmonic mean , HM , hmWeight , hmSum , hm , getHM -- * Quadratic mean , QM , qmWeight , qmSum , qm , getQM -- * Cubic mean , CM , cmWeight , cmSum , cm , getCM -- * Midrange mean , MM , mmMin , mmMax , mm , getMM ) where import Data.Semigroup -------------------------------------------------------------------------------- -- | semigroup for accumalting /Arithmetic mean/ data AM a = AM { amWeight :: {-# UNPACK #-} !Int , amSum :: a } deriving (Show, Eq) -- | 'AM' with weight 1. am :: Num a => a -> AM a am = AM 1 {-# INLINABLE am #-} -- | 'AM' with weight(weight is 'Int' with 1 as unit). am' :: Num a => Int -> a -> AM a am' w v = AM w (fromIntegral w * v) {-# INLINABLE am' #-} instance Num a => Semigroup (AM a) where AM c1 s1 <> AM c2 s2 = AM (c1 + c2) (s1 + s2) {-# INLINE (<>) #-} getAM :: Fractional a => AM a -> a getAM (AM c s) = s / fromIntegral c {-# INLINABLE getAM #-} -------------------------------------------------------------------------------- -- | semigroup for accumalting /Geometric mean/ data GM a = GM { gmWeight :: {-# UNPACK #-} !Int , gmProduct :: a } deriving (Show, Eq) gm :: Num a => a -> GM a gm = GM 1 {-# INLINABLE gm #-} instance Num a => Semigroup (GM a) where GM c1 s1 <> GM c2 s2 = GM (c1 + c2) (s1 * s2) {-# INLINE (<>) #-} getGM :: Floating a => GM a -> a getGM (GM c p) = p ** (1 / fromIntegral c) {-# INLINABLE getGM #-} -------------------------------------------------------------------------------- -- | semigroup for accumalting /Harmonic mean/ data HM a = HM { hmWeight :: {-# UNPACK #-} !Int , hmSum :: a } deriving (Show, Eq) hm :: Fractional a => a -> HM a hm x = HM 1 (1 / x) {-# INLINABLE hm #-} instance Num a => Semigroup (HM a) where HM c1 s1 <> HM c2 s2 = HM (c1 + c2) (s1 + s2) {-# INLINE (<>) #-} getHM :: Fractional a => HM a -> a getHM (HM c s) = fromIntegral c / s {-# INLINABLE getHM #-} -------------------------------------------------------------------------------- -- | semigroup for accumalting /Quadratic mean/ data QM a = QM { qmWeight :: {-# UNPACK #-} !Int , qmSum :: a } deriving (Show, Eq) qm :: Fractional a => a -> QM a qm x = QM 1 (x ^ (2 :: Int)) {-# INLINABLE qm #-} instance Num a => Semigroup (QM a) where QM c1 s1 <> QM c2 s2 = QM (c1 + c2) (s1 + s2) {-# INLINE (<>) #-} getQM :: Floating a => QM a -> a getQM (QM c s) = sqrt (s / fromIntegral c) {-# INLINABLE getQM #-} -------------------------------------------------------------------------------- -- | semigroup for accumalting /Cubic mean/ data CM a = CM { cmWeight :: {-# UNPACK #-} !Int , cmSum :: a } deriving (Show, Eq) cm :: Fractional a => a -> CM a cm x = CM 1 (x ^ (3 :: Int)) {-# INLINABLE cm #-} instance Num a => Semigroup (CM a) where CM c1 s1 <> CM c2 s2 = CM (c1 + c2) (s1 + s2) {-# INLINE (<>) #-} getCM :: Floating a => CM a -> a getCM (CM c s) = (s / fromIntegral c) ** (1/3) {-# INLINABLE getCM #-} -------------------------------------------------------------------------------- -- | semigroup for accumalting /Midrange mean/ data MM a = MM { mmMin :: a , mmMax :: a } deriving (Show, Eq) mm :: a -> MM a mm x = MM x x {-# INLINABLE mm #-} instance Ord a => Semigroup (MM a) where MM min1 max1 <> MM min2 max2 = let min' = min min1 min2 max' = max max1 max2 in MM min' max' {-# INLINE (<>) #-} getMM :: Fractional a => MM a -> a getMM (MM min' max') = (max' + min') / 2 {-# INLINABLE getMM #-} --------------------------------------------------------------------------------