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 :: forall a. Monoid a => Fold a a
monoid = Fold{ initial :: a
initial = forall a. Monoid a => a
mempty, step :: a -> a -> a
step = forall a. Semigroup a => a -> a -> a
(<>), extract :: a -> a
extract = forall a. a -> a
id }

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

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

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

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

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

{-| Numerically stable (population) standard deviation over the inputs -}
standardDeviation :: Floating a => Fold a a
standardDeviation :: forall a. Floating a => Fold a a
standardDeviation = forall a. Floating a => a -> a
sqrt forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Fractional a => Fold a a
variance

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

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