module Fold.Nonempty.Examples.Interesting
  (
    {- * General -} magma, semigroup,
    {- * Endpoints -} last,
    {- * Extrema -} maximum, minimum, maximumBy, minimumBy,
    {- * Numeric -} sum, product,
    {- * List -} list, reverseList,
  )
  where

import Fold.Nonempty.Type

import Data.Function (id, const, flip, (.))
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Ord (Ord, Ordering (GT), max, min)
import Data.Semigroup (Semigroup, (<>))
import Prelude (Num, (+), (*))

import qualified Strict

{-| Start with the first input, append each new input on the right
    with the given function -}
magma :: (a -> a -> a) -> NonemptyFold a a
magma :: forall a. (a -> a -> a) -> NonemptyFold a a
magma a -> a -> a
step = NonemptyFold{ initial :: a -> a
initial = forall a. a -> a
id, a -> a -> a
step :: a -> a -> a
step :: a -> a -> a
step, extract :: a -> a
extract = forall a. a -> a
id }

{-| Append each new input on the right with ('<>') -}
semigroup :: Semigroup a => NonemptyFold a a
semigroup :: forall a. Semigroup a => NonemptyFold a a
semigroup = forall a. (a -> a -> a) -> NonemptyFold a a
magma forall a. Semigroup a => a -> a -> a
(<>)

{-| The last input -}
last :: NonemptyFold a a
last :: forall a. NonemptyFold a a
last = forall a. (a -> a -> a) -> NonemptyFold a a
magma (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. a -> b -> a
const)

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

{-| The greatest input with respect to the given comparison function -}
maximumBy :: (a -> a -> Ordering) -> NonemptyFold a a
maximumBy :: forall a. (a -> a -> Ordering) -> NonemptyFold a a
maximumBy a -> a -> Ordering
cmp = forall a. (a -> a -> a) -> NonemptyFold a 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 -}
minimum :: Ord a => NonemptyFold a a
minimum :: forall a. Ord a => NonemptyFold a a
minimum = forall a. (a -> a -> a) -> NonemptyFold a a
magma forall a. Ord a => a -> a -> a
min

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

{-| Adds the inputs -}
sum :: Num a => NonemptyFold a a
sum :: forall a. Num a => NonemptyFold a a
sum = forall a. (a -> a -> a) -> NonemptyFold a a
magma forall a. Num a => a -> a -> a
(+)

{-| Multiplies the inputs -}
product :: Num a => NonemptyFold a a
product :: forall a. Num a => NonemptyFold a a
product = forall a. (a -> a -> a) -> NonemptyFold a a
magma forall a. Num a => a -> a -> a
(*)

{-| All the inputs -}
list :: NonemptyFold a (NonEmpty a)
list :: forall a. NonemptyFold a (NonEmpty a)
list = NonemptyFold
    { initial :: a -> Tuple2 a ([a] -> [a])
initial = \a
a -> forall a b. a -> b -> Tuple2 a b
Strict.Tuple2 a
a forall a. a -> a
id
    , step :: Tuple2 a ([a] -> [a]) -> a -> Tuple2 a ([a] -> [a])
step = \(Strict.Tuple2 a
a0 [a] -> [a]
x) a
a -> forall a b. a -> b -> Tuple2 a b
Strict.Tuple2 a
a0 ([a] -> [a]
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a
a :))
    , extract :: Tuple2 a ([a] -> [a]) -> NonEmpty a
extract = \(Strict.Tuple2 a
a0 [a] -> [a]
x) -> a
a0 forall a. a -> [a] -> NonEmpty a
:| ([a] -> [a]
x [])
    }

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