-- | Folds of other types trivially lifted into 'Shortcut'
module Fold.Shortcut.Examples.Boring
  (
    {- * Arithmetic folds -} sum, product, mean, variance, standardDeviation,
    {- * Counting inputs -} length,
    {- * Min/max -} maximum, minimum, maximumBy, minimumBy,
    {- * First/last -} first, last,
    {- * General folds -} magma, semigroup, monoid,
    {- * List folds -} list, reverseList,
  )
  where

import Data.Maybe (Maybe)
import Fold.Shortcut.Type (ShortcutFold)
import Data.Semigroup (Semigroup)
import Data.Ord (Ord, Ordering (GT), max, min)
import Data.Monoid (Monoid)
import Prelude (Floating, Fractional, Num)
import Numeric.Natural (Natural)

import qualified Fold.ShortcutNonempty.Examples.Interesting as ShortcutNonempty
import qualified Fold.Nonempty.Examples.Interesting as Nonempty
import qualified Fold.Pure.Examples.Interesting as Fold
import qualified Fold.Shortcut.Conversion as Convert

{-| The first input (tenacious) -}
first :: ShortcutFold a (Maybe a)
first :: forall a. ShortcutFold a (Maybe a)
first = forall a b. ShortcutNonemptyFold a b -> ShortcutFold a (Maybe b)
Convert.shortcutNonemptyFold forall a. ShortcutNonemptyFold a a
ShortcutNonempty.first

{-| Start with the first input, append each new input on the right
    with the given function (ambivalent) -}
magma :: (a -> a -> a) -> ShortcutFold a (Maybe a)
magma :: forall a. (a -> a -> a) -> ShortcutFold a (Maybe a)
magma a -> a -> a
step = forall a b. NonemptyFold a b -> ShortcutFold a (Maybe b)
Convert.nonemptyFold (forall a. (a -> a -> a) -> NonemptyFold a a
Nonempty.magma a -> a -> a
step)

{-| Append each new input on the right with '<>' (ambivalent) -}
semigroup :: Semigroup a => ShortcutFold a (Maybe a)
semigroup :: forall a. Semigroup a => ShortcutFold a (Maybe a)
semigroup = forall a b. NonemptyFold a b -> ShortcutFold a (Maybe b)
Convert.nonemptyFold forall a. Semigroup a => NonemptyFold a a
Nonempty.semigroup

{-| The last input (ambivalent) -}
last :: ShortcutFold a (Maybe a)
last :: forall a. ShortcutFold a (Maybe a)
last = forall a b. NonemptyFold a b -> ShortcutFold a (Maybe b)
Convert.nonemptyFold forall a. NonemptyFold a a
Nonempty.last

{-| The greatest input (ambivalent) -}
maximum :: Ord a => ShortcutFold a (Maybe a)
maximum :: forall a. Ord a => ShortcutFold a (Maybe a)
maximum = forall a. (a -> a -> a) -> ShortcutFold a (Maybe a)
magma forall a. Ord a => a -> a -> a
max

{-| The greatest input with respect to the given comparison function
    (ambivalent) -}
maximumBy :: (a -> a -> Ordering) -> ShortcutFold a (Maybe a)
maximumBy :: forall a. (a -> a -> Ordering) -> ShortcutFold a (Maybe a)
maximumBy a -> a -> Ordering
cmp = forall a. (a -> a -> a) -> ShortcutFold a (Maybe a)
magma (\a
x a
y -> case a -> a -> Ordering
cmp a
x a
y of { Ordering
GT -> a
x; Ordering
_ -> a
y })

{-| The least input (ambivalent) -}
minimum :: Ord a => ShortcutFold a (Maybe a)
minimum :: forall a. Ord a => ShortcutFold a (Maybe a)
minimum = forall a. (a -> a -> a) -> ShortcutFold a (Maybe a)
magma forall a. Ord a => a -> a -> a
min

{-| The least input with respect to the given comparison function
    (ambivalent) -}
minimumBy :: (a -> a -> Ordering) -> ShortcutFold a (Maybe a)
minimumBy :: forall a. (a -> a -> Ordering) -> ShortcutFold a (Maybe a)
minimumBy a -> a -> Ordering
cmp = forall a. (a -> a -> a) -> ShortcutFold a (Maybe a)
magma (\a
x a
y -> case a -> a -> Ordering
cmp a
x a
y of { Ordering
GT -> a
y; Ordering
_ -> a
x })

{-| All the inputs (ambivalent) -}
list :: ShortcutFold a [a]
list :: forall a. ShortcutFold a [a]
list = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Fold a [a]
Fold.list

{-| All the inputs in reverse order (ambivalent) -}
reverseList :: ShortcutFold a [a]
reverseList :: forall a. ShortcutFold a [a]
reverseList = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Fold a [a]
Fold.reverseList

{-| Start with 'mempty', append each input on the right with '<>'
    (ambivalent)-}
monoid :: Monoid a => ShortcutFold a a
monoid :: forall a. Monoid a => ShortcutFold a a
monoid = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Monoid a => Fold a a
Fold.monoid

{-| The number of inputs (ambivalent) -}
length :: ShortcutFold a Natural
length :: forall a. ShortcutFold a Natural
length = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Fold a Natural
Fold.length

{-| Adds the inputs (ambivalent) -}
sum :: Num a => ShortcutFold a a
sum :: forall a. Num a => ShortcutFold a a
sum = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Num a => Fold a a
Fold.sum

{-| Multiplies the inputs (ambivalent) -}
product :: Num a => ShortcutFold a a
product :: forall a. Num a => ShortcutFold a a
product = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Num a => Fold a a
Fold.product

{-| Numerically stable arithmetic mean of the inputs (ambivalent) -}
mean :: Fractional a => ShortcutFold a a
mean :: forall a. Fractional a => ShortcutFold a a
mean = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Fractional a => Fold a a
Fold.mean

{-| Numerically stable (population) variance over the
    inputs (ambivalent) -}
variance :: Fractional a => ShortcutFold a a
variance :: forall a. Fractional a => ShortcutFold a a
variance = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Fractional a => Fold a a
Fold.variance

{-| Numerically stable (population) standard deviation over the
    inputs (ambivalent) -}
standardDeviation :: Floating a => ShortcutFold a a
standardDeviation :: forall a. Floating a => ShortcutFold a a
standardDeviation = forall a b. Fold a b -> ShortcutFold a b
Convert.fold forall a. Floating a => Fold a a
Fold.standardDeviation