{-# LANGUAGE ExistentialQuantification #-}

-- | A pure moving average module. The interface is agnostic to the scale of time
-- that the average is tracking. It is up to the specific moving average module to
-- handle that functionality.
module Data.Metrics.MovingAverage where

-- | This type encapsulates the interface
-- of the different moving average implementations in such a way that they
-- can be reused without plumbing the types through the other components that
-- use moving averages. Most people won't ever need to use record fields of
-- this type.
data MovingAverage = forall s. MovingAverage
  { ()
movingAverageClear :: !(s -> s)
  -- ^ clear the internal state of the moving average
  , ()
movingAverageUpdate :: !(Double -> s -> s)
  -- ^ add a new sample to the moving average
  , ()
movingAverageTick :: !(s -> s)
  -- ^ perform any modifications of the internal state associated with the passage of a predefined interval of time.
  , ()
movingAverageRate :: !(s -> Double)
  -- ^ get the current rate of the moving average.
  , ()
movingAverageState :: !s
  -- ^ the internal implementation state of the moving average
  }

instance Show MovingAverage where
  show :: MovingAverage -> String
show (MovingAverage s -> s
_ Double -> s -> s
_ s -> s
_ s -> Double
r s
s) = String
"MovingAverage {movingAverageRate = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Double -> String
forall a. Show a => a -> String
show (s -> Double
r s
s) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"}"

-- | Reset a moving average back to a starting state.
clear :: MovingAverage -> MovingAverage
clear :: MovingAverage -> MovingAverage
clear (MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r s
s) = (s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
forall s.
(s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r (s -> s
c s
s)
{-# INLINEABLE clear #-}

-- | Get the current rate of the moving average.
rate :: MovingAverage -> Double
rate :: MovingAverage -> Double
rate (MovingAverage s -> s
_ Double -> s -> s
_ s -> s
_ s -> Double
r s
s) = s -> Double
r s
s
{-# INLINEABLE rate #-}

-- | Update the average based upon an interval specified by the
-- moving average implementation.
tick :: MovingAverage -> MovingAverage
tick :: MovingAverage -> MovingAverage
tick (MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r s
s) = (s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
forall s.
(s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r (s -> s
t s
s)
{-# INLINEABLE tick #-}

-- | Update the average with the specified value.
update :: Double -> MovingAverage -> MovingAverage
update :: Double -> MovingAverage -> MovingAverage
update Double
x (MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r s
s) = (s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
forall s.
(s -> s)
-> (Double -> s -> s)
-> (s -> s)
-> (s -> Double)
-> s
-> MovingAverage
MovingAverage s -> s
c Double -> s -> s
u s -> s
t s -> Double
r (Double -> s -> s
u Double
x s
s)
{-# INLINEABLE update #-}