packages feed

gambler-0.1.0.0: source/Fold/Pure/Examples/Interesting.hs

module Fold.Pure.Examples.Interesting
  (
    {- * Monoid -} monoid,
    {- * Length -} length,
    {- * Numeric -} sum, product, mean, variance, standardDeviation,
    {- * List -} list, reverseList,
  )
  where

import Fold.Pure.Type

import Data.Function (id, ($), (.))
import Data.Functor ((<$>))
import Data.Monoid (Monoid, mempty)
import Data.Semigroup ((<>))
import Numeric.Natural (Natural)
import Prelude (Floating, Fractional, Num, sqrt, (*), (+), (-), (/))

import qualified Strict

{-| Start with 'mempty', append each input on the right with ('<>') -}
monoid :: Monoid a => Fold a a
monoid = Fold{ initial = mempty, step = (<>), extract = id }

{-| The number of inputs -}
length :: Fold a Natural
length = Fold{ initial = 0, step = \n _ -> n + 1, extract = id }

{-| Adds the inputs -}
sum :: Num a => Fold a a
sum = Fold{ initial = 0, step = (+), extract = id }

{-| Multiplies the inputs -}
product :: Num a => Fold a a
product = Fold{ initial = 1, step = (*), extract = id }

{-| Numerically stable arithmetic mean of the inputs -}
mean :: Fractional a => Fold a a
mean = Fold
    { initial = Strict.Tuple2 0 0
    , step = \(Strict.Tuple2 x n) y ->
        let n' = n + 1 in
        Strict.Tuple2 (x + (y - x) / n') n'
    , extract = \(Strict.Tuple2 x _) -> x
    }

{-| Numerically stable (population) variance over the inputs -}
variance :: Fractional a => Fold a a
variance = Fold
    { initial = Strict.Tuple3 0 0 0
    , step = \(Strict.Tuple3 n mean_ m2) x ->
        let
          n'     = n + 1
          mean'  = (n * mean_ + x) / (n + 1)
          delta  = x - mean_
          m2'    = m2 + delta * delta * n / (n + 1)
        in
          Strict.Tuple3 n' mean' m2'
    , extract = \(Strict.Tuple3 n _ m2) -> m2 / n
    }

{-| Numerically stable (population) standard deviation over the inputs -}
standardDeviation :: Floating a => Fold a a
standardDeviation = sqrt <$> variance

{-| All the inputs -}
list :: Fold a [a]
list = Fold{ initial = id, step = \x a -> x . (a :), extract = ($ []) }

{-| All the inputs in reverse order -}
reverseList :: Fold a [a]
reverseList = Fold{ initial = [], step = \x a -> a : x, extract = id }