-- | Folds from "Fold.Pure.Examples" trivially lifted into 'EffectfulFold'
module Fold.Effectful.Pure
  (
    {- * Monoid -} monoid,
    {- * Length -} null, length,
    {- * Boolean -} and, or, all, any,
    {- * Numeric -} sum, product, mean, variance, standardDeviation,
    {- * Search -} element, notElement, find, lookup,
    {- * Index -} index, findIndex, elementIndex,
    {- * List -} list, reverseList,
  )
  where

import Control.Monad (Monad)
import Data.Bool (Bool)
import Data.Eq (Eq)
import Data.Maybe (Maybe)
import Data.Monoid (Monoid)
import Fold.Effectful.Conversion (fold)
import Fold.Effectful.Type (EffectfulFold)
import Numeric.Natural (Natural)
import Prelude (Floating, Fractional, Num)

import qualified Fold.Pure.Examples as Pure

{-| Start with 'mempty', append each input on the right with ('<>') -}
monoid :: Monoid a => Monad m => EffectfulFold m a a
monoid :: forall a (m :: * -> *). (Monoid a, Monad m) => EffectfulFold m a a
monoid = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Monoid a => Fold a a
Pure.monoid

{-| 'True' if the input contains no inputs -}
null :: Monad m => EffectfulFold m a Bool
null :: forall (m :: * -> *) a. Monad m => EffectfulFold m a Bool
null = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fold a Bool
Pure.null

{-| The number of inputs -}
length :: Monad m => EffectfulFold m a Natural
length :: forall (m :: * -> *) a. Monad m => EffectfulFold m a Natural
length = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fold a Natural
Pure.length

{-| 'True' if all inputs are 'True' -}
and :: Monad m => EffectfulFold m Bool Bool
and :: forall (m :: * -> *). Monad m => EffectfulFold m Bool Bool
and = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold Fold Bool Bool
Pure.and

{-| 'True' if any input is 'True' -}
or :: Monad m => EffectfulFold m Bool Bool
or :: forall (m :: * -> *). Monad m => EffectfulFold m Bool Bool
or = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold Fold Bool Bool
Pure.or

{-| 'True' if all inputs satisfy the predicate -}
all :: Monad m => (a -> Bool) -> EffectfulFold m a Bool
all :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> EffectfulFold m a Bool
all a -> Bool
predicate = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. (a -> Bool) -> Fold a Bool
Pure.all a -> Bool
predicate)

{-| 'True' if any input satisfies the predicate -}
any :: Monad m => (a -> Bool) -> EffectfulFold m a Bool
any :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> EffectfulFold m a Bool
any a -> Bool
predicate = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. (a -> Bool) -> Fold a Bool
Pure.any a -> Bool
predicate)

{-| Adds the inputs -}
sum :: Num a => Monad m => EffectfulFold m a a
sum :: forall a (m :: * -> *). (Num a, Monad m) => EffectfulFold m a a
sum = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Num a => Fold a a
Pure.sum

{-| Multiplies the inputs -}
product :: Num a => Monad m => EffectfulFold m a a
product :: forall a (m :: * -> *). (Num a, Monad m) => EffectfulFold m a a
product = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Num a => Fold a a
Pure.product

{-| Numerically stable arithmetic mean of the inputs -}
mean :: Fractional a => Monad m => EffectfulFold m a a
mean :: forall a (m :: * -> *).
(Fractional a, Monad m) =>
EffectfulFold m a a
mean = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fractional a => Fold a a
Pure.mean

{-| Numerically stable (population) variance over the inputs -}
variance :: Fractional a => Monad m => EffectfulFold m a a
variance :: forall a (m :: * -> *).
(Fractional a, Monad m) =>
EffectfulFold m a a
variance = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fractional a => Fold a a
Pure.variance

{-| Numerically stable (population) standard deviation over the inputs -}
standardDeviation :: Floating a => Monad m => EffectfulFold m a a
standardDeviation :: forall a (m :: * -> *).
(Floating a, Monad m) =>
EffectfulFold m a a
standardDeviation = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Floating a => Fold a a
Pure.standardDeviation

{-| 'True' if any input is equal to the given value -}
element :: Eq a => Monad m => a -> EffectfulFold m a Bool
element :: forall a (m :: * -> *).
(Eq a, Monad m) =>
a -> EffectfulFold m a Bool
element a
a = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. Eq a => a -> Fold a Bool
Pure.element a
a)

{-| 'False' if any input is equal to the given value -}
notElement :: Eq a => Monad m => a -> EffectfulFold m a Bool
notElement :: forall a (m :: * -> *).
(Eq a, Monad m) =>
a -> EffectfulFold m a Bool
notElement a
a = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. Eq a => a -> Fold a Bool
Pure.notElement a
a)

{-| The first input that satisfies the predicate, if any -}
find :: Monad m => (a -> Bool) -> EffectfulFold m a (Maybe a)
find :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> EffectfulFold m a (Maybe a)
find a -> Bool
ok = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. (a -> Bool) -> Fold a (Maybe a)
Pure.find a -> Bool
ok)

{-| The /n/th input, where n=0 is the first input, if the index is in bounds -}
index :: Monad m => Natural -> EffectfulFold m a (Maybe a)
index :: forall (m :: * -> *) a.
Monad m =>
Natural -> EffectfulFold m a (Maybe a)
index Natural
i = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. Natural -> Fold a (Maybe a)
Pure.index Natural
i)

{-| The index of the first input that matches the given value, if any -}
elementIndex :: Eq a => Monad m => a -> EffectfulFold m a (Maybe Natural)
elementIndex :: forall a (m :: * -> *).
(Eq a, Monad m) =>
a -> EffectfulFold m a (Maybe Natural)
elementIndex a
a = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. Eq a => a -> Fold a (Maybe Natural)
Pure.elementIndex a
a)

{-| The index of the first input that satisfies the predicate, if any -}
findIndex :: Monad m => (a -> Bool) -> EffectfulFold m a (Maybe Natural)
findIndex :: forall (m :: * -> *) a.
Monad m =>
(a -> Bool) -> EffectfulFold m a (Maybe Natural)
findIndex a -> Bool
ok = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a. (a -> Bool) -> Fold a (Maybe Natural)
Pure.findIndex a -> Bool
ok)

{-| The @b@ from the first tuple where @a@ equals the given value, if any -}
lookup :: Eq a => Monad m => a -> EffectfulFold m (a, b) (Maybe b)
lookup :: forall a (m :: * -> *) b.
(Eq a, Monad m) =>
a -> EffectfulFold m (a, b) (Maybe b)
lookup a
a = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold (forall a b. Eq a => a -> Fold (a, b) (Maybe b)
Pure.lookup a
a)

{-| All the inputs -}
list :: Monad m => EffectfulFold m a [a]
list :: forall (m :: * -> *) a. Monad m => EffectfulFold m a [a]
list = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fold a [a]
Pure.list

{-| All the inputs in reverse order -}
reverseList :: Monad m => EffectfulFold m a [a]
reverseList :: forall (m :: * -> *) a. Monad m => EffectfulFold m a [a]
reverseList = forall (m :: * -> *) a b.
Monad m =>
Fold a b -> EffectfulFold m a b
fold forall a. Fold a [a]
Pure.reverseList