```-- | Basic bounded statistics.  In the following, a bound @n@ is given stating
-- the number of periods over which to compute the statistic (@n == 1@ computes
-- it only over the current period).

module Language.Copilot.Libs.Statistics
(max, min, sum, mean, meanNow) where

import Prelude (Int, (\$), foldl1, fromIntegral, foldl, error, length)
--import qualified Prelude as P

import qualified Language.Atom as A

import Language.Copilot.Libs.ErrorChks (nOneChk)
import Language.Copilot.Core
import Language.Copilot.Language

foldDrops :: (Streamable a) => Int -> (Spec a -> Spec a -> Spec a) -> Spec a -> Spec a
foldDrops n f s = foldl1 f [drop x s | x <- [0..(n-1)]]

-- | Summation.
sum :: (Streamable a, A.NumE a) => Int -> Spec a -> Spec a
sum n s =
nOneChk "sum" n \$ foldDrops n (+) s

-- | Maximum value.
max :: (Streamable a, A.NumE a) => Int -> Spec a -> Spec a
max n s =
nOneChk "max" n \$ foldDrops n largest s
where largest = \ x y -> mux (x <= y) y x

-- | Minimum value.
min :: (Streamable a, A.NumE a) => Int -> Spec a -> Spec a
min n s =
nOneChk "max" n \$ foldDrops n smallest s
where smallest = \ x y -> mux (x <= y) x y

-- | Mean value.  @n@ must not overflow
-- for word size @a@ for streams over which computation is peformed.
mean :: (Streamable a, Fractional a, A.NumE a) => Int -> Spec a -> Spec a
mean n s =
nOneChk "mean" n \$ (sum n s) / (fromIntegral n)

-- | Mean value over the current set of specs passed in.
meanNow :: (Streamable a, A.IntegralE a) => [Spec a] -> Spec a
meanNow [] = error
"Error in majority: list of arguments must be nonempty."
meanNow ls =
(foldl (+) 0 ls) `div` (fromIntegral \$ length ls)

```