foldl-1.4.13: src/Control/Foldl/NonEmpty.hs
{-| This module provides a `Fold1` type that is a \"non-empty\" analog of the
`Fold` type, meaning that it requires at least one input element in order to
produce a result
This module does not provide all of the same utilities as the
"Control.Foldl" module. Instead, this module only provides the utilities
which can make use of the non-empty input guarantee (e.g. `head`). For
all other utilities you can convert them from the equivalent `Fold` using
`fromFold`.
-}
module Control.Foldl.NonEmpty where
import Control.Applicative (liftA2)
import Control.Foldl (Fold(..))
import Data.List.NonEmpty (NonEmpty(..))
import Data.Profunctor (Profunctor(..))
import Prelude hiding (head, last, minimum, maximum)
import qualified Control.Foldl as Foldl
{-| A `Fold1` is like a `Fold` except that it consumes at least one input
element
-}
data Fold1 a b = Fold1 (a -> Fold a b)
instance Functor (Fold1 a) where
fmap f (Fold1 k) = Fold1 (fmap (fmap f) k)
{-# INLINE fmap #-}
instance Profunctor Fold1 where
lmap f (Fold1 k) = Fold1 k'
where
k' a = lmap f (k (f a))
{-# INLINE lmap #-}
rmap = fmap
{-# INLINE rmap #-}
instance Applicative (Fold1 a) where
pure b = Fold1 (pure (pure b))
{-# INLINE pure #-}
Fold1 l <*> Fold1 r = Fold1 (liftA2 (<*>) l r)
{-# INLINE (<*>) #-}
instance Semigroup b => Semigroup (Fold1 a b) where
(<>) = liftA2 (<>)
{-# INLINE (<>) #-}
instance Monoid b => Monoid (Fold1 a b) where
mempty = pure mempty
{-# INLINE mempty #-}
mappend = liftA2 mappend
{-# INLINE mappend #-}
instance Num b => Num (Fold1 a b) where
fromInteger = pure . fromInteger
{-# INLINE fromInteger #-}
negate = fmap negate
{-# INLINE negate #-}
abs = fmap abs
{-# INLINE abs #-}
signum = fmap signum
{-# INLINE signum #-}
(+) = liftA2 (+)
{-# INLINE (+) #-}
(*) = liftA2 (*)
{-# INLINE (*) #-}
(-) = liftA2 (-)
{-# INLINE (-) #-}
instance Fractional b => Fractional (Fold1 a b) where
fromRational = pure . fromRational
{-# INLINE fromRational #-}
recip = fmap recip
{-# INLINE recip #-}
(/) = liftA2 (/)
{-# INLINE (/) #-}
instance Floating b => Floating (Fold1 a b) where
pi = pure pi
{-# INLINE pi #-}
exp = fmap exp
{-# INLINE exp #-}
sqrt = fmap sqrt
{-# INLINE sqrt #-}
log = fmap log
{-# INLINE log #-}
sin = fmap sin
{-# INLINE sin #-}
tan = fmap tan
{-# INLINE tan #-}
cos = fmap cos
{-# INLINE cos #-}
asin = fmap asin
{-# INLINE asin #-}
atan = fmap atan
{-# INLINE atan #-}
acos = fmap acos
{-# INLINE acos #-}
sinh = fmap sinh
{-# INLINE sinh #-}
tanh = fmap tanh
{-# INLINE tanh #-}
cosh = fmap cosh
{-# INLINE cosh #-}
asinh = fmap asinh
{-# INLINE asinh #-}
atanh = fmap atanh
{-# INLINE atanh #-}
acosh = fmap acosh
{-# INLINE acosh #-}
(**) = liftA2 (**)
{-# INLINE (**) #-}
logBase = liftA2 logBase
{-# INLINE logBase #-}
-- | Apply a strict left `Fold1` to a `NonEmpty` list
fold1 :: Fold1 a b -> NonEmpty a -> b
fold1 (Fold1 k) (a :| as) = Foldl.fold (k a) as
{-# INLINABLE fold1 #-}
-- | Promote any `Fold` to an equivalent `Fold1`
fromFold :: Fold a b -> Fold1 a b
fromFold (Fold step begin done) = Fold1 (\a -> Fold step (step begin a) done)
{-# INLINABLE fromFold #-}
-- | Fold all values within a non-empty container using (`<>`)
sconcat :: Semigroup a => Fold1 a a
sconcat = Fold1 (\begin -> Fold (<>) begin id)
{-# INLINABLE sconcat #-}
-- | Get the first element of a non-empty container
head :: Fold1 a a
head = Fold1 (\begin -> Fold step begin id)
where
step a _ = a
{-# INLINABLE head #-}
-- | Get the last element of a non-empty container
last :: Fold1 a a
last = Fold1 (\begin -> Fold step begin id)
where
step _ a = a
{-# INLINABLE last #-}
-- | Computes the maximum element
maximum :: Ord a => Fold1 a a
maximum = Fold1 (\begin -> Fold max begin id)
{-# INLINABLE maximum #-}
-- | Computes the maximum element with respect to the given comparison function
maximumBy :: (a -> a -> Ordering) -> Fold1 a a
maximumBy cmp = Fold1 (\begin -> Fold max' begin id)
where
max' x y = case cmp x y of
GT -> x
_ -> y
{-# INLINABLE maximumBy #-}
-- | Computes the minimum element
minimum :: Ord a => Fold1 a a
minimum = Fold1 (\begin -> Fold min begin id)
{-# INLINABLE minimum #-}
-- | Computes the minimum element with respect to the given comparison function
minimumBy :: (a -> a -> Ordering) -> Fold1 a a
minimumBy cmp = Fold1 (\begin -> Fold min' begin id)
where
min' x y = case cmp x y of
GT -> y
_ -> x
{-# INLINABLE minimumBy #-}