Control.Foldl

foldl-1.2.1: Composable, streaming, and efficient left folds

Safe Haskell | Trustworthy
Language | Haskell98

Control.Foldl

Contents

- Fold Types
- Folding
- Folds
- Generic Folds
- Container folds
- Utilities
- Re-exports

Description

This module provides efficient and streaming left folds that you can combine using `Applicative` style.

Import this module qualified to avoid clashing with the Prelude:

    >>> import qualified Control.Foldl as L

Use `fold` to apply a `Fold` to a list:

    >>> L.fold L.sum [1..100]
    5050

`Fold`s are `Applicative`s, so you can combine them using `Applicative` combinators:

    >>> import Control.Applicative
    >>> let average = (/) <$> L.sum <*> L.genericLength

Taking the sum, the sum of squares, ..., upto the sum of x^5

    >>> import Data.Traversable
    >>> let powerSums = sequenceA [L.premap (^n) L.sum | n <- [1..5]]
    >>> L.fold powerSums [1..10]
    [55,385,3025,25333,220825]

These combined folds will still traverse the list only once, streaming efficiently over the list in constant space without space leaks:

    >>> L.fold average [1..10000000]
    5000000.5
    >>> L.fold ((,) <$> L.minimum <*> L.maximum) [1..10000000]
    (Just 1,Just 10000000)

Synopsis

- data Fold a b = Fold (x -> a -> x) x (x -> b)
- data FoldM m a b = FoldM (x -> a -> m x) (m x) (x -> m b)
- fold :: Foldable f => Fold a b -> f a -> b
- foldM :: (Foldable f, Monad m) => FoldM m a b -> f a -> m b
- scan :: Fold a b -> [a] -> [b]
- mconcat :: Monoid a => Fold a a
- foldMap :: Monoid w => (a -> w) -> (w -> b) -> Fold a b
- head :: Fold a (Maybe a)
- last :: Fold a (Maybe a)
- lastDef :: a -> Fold a a
- lastN :: Int -> Fold a [a]
- null :: Fold a Bool
- length :: Fold a Int
- and :: Fold Bool Bool
- or :: Fold Bool Bool
- all :: (a -> Bool) -> Fold a Bool
- any :: (a -> Bool) -> Fold a Bool
- sum :: Num a => Fold a a
- product :: Num a => Fold a a
- maximum :: Ord a => Fold a (Maybe a)
- maximumBy :: (a -> a -> Ordering) -> Fold a (Maybe a)
- minimum :: Ord a => Fold a (Maybe a)
- minimumBy :: (a -> a -> Ordering) -> Fold a (Maybe a)
- elem :: Eq a => a -> Fold a Bool
- notElem :: Eq a => a -> Fold a Bool
- find :: (a -> Bool) -> Fold a (Maybe a)
- index :: Int -> Fold a (Maybe a)
- elemIndex :: Eq a => a -> Fold a (Maybe Int)
- findIndex :: (a -> Bool) -> Fold a (Maybe Int)
- random :: FoldM IO a (Maybe a)
- randomN :: Vector v a => Int -> FoldM IO a (Maybe (v a))
- mapM_ :: Monad m => (a -> m ()) -> FoldM m a ()
- sink :: (Monoid w, Monad m) => (a -> m w) -> FoldM m a w
- genericLength :: Num b => Fold a b
- genericIndex :: Integral i => i -> Fold a (Maybe a)
- list :: Fold a [a]
- revList :: Fold a [a]
- nub :: Ord a => Fold a [a]
- eqNub :: Eq a => Fold a [a]
- set :: Ord a => Fold a (Set a)
- vector :: (PrimMonad m, Vector v a) => FoldM m a (v a)
- purely :: (forall x. (x -> a -> x) -> x -> (x -> b) -> r) -> Fold a b -> r
- purely_ :: (forall x. (x -> a -> x) -> x -> x) -> Fold a b -> b
- impurely :: Monad m => (forall x. (x -> a -> m x) -> m x -> (x -> m b) -> r) -> FoldM m a b -> r
- impurely_ :: Monad m => (forall x. (x -> a -> m x) -> m x -> m x) -> FoldM m a b -> m b
- generalize :: Monad m => Fold a b -> FoldM m a b
- simplify :: FoldM Identity a b -> Fold a b
- hoists :: Monad m => (forall x. m x -> n x) -> FoldM m a b -> FoldM n a b
- duplicateM :: Applicative m => FoldM m a b -> FoldM m a (FoldM m a b)
- _Fold1 :: (a -> a -> a) -> Fold a (Maybe a)
- premap :: (a -> b) -> Fold b r -> Fold a r
- premapM :: (a -> b) -> FoldM m b r -> FoldM m a r
- type Handler a b = forall x. (b -> Const (Dual (Endo x)) b) -> a -> Const (Dual (Endo x)) a
- handles :: Handler a b -> Fold b r -> Fold a r
- newtype EndoM m a = EndoM {
  - appEndoM :: a -> m a
  }
- type HandlerM m a b = forall x. (b -> Const (Dual (EndoM m x)) b) -> a -> Const (Dual (EndoM m x)) a
- handlesM :: Monad m => HandlerM m a b -> FoldM m b r -> FoldM m a r
- folded :: (Contravariant f, Applicative f, Foldable t) => (a -> f a) -> t a -> f (t a)
- filtered :: Monoid m => (a -> Bool) -> (a -> m) -> a -> m
- module Control.Monad.Primitive
- module Data.Foldable
- module Data.Vector.Generic

# Fold Types

data Fold a b #

Efficient representation of a left fold that preserves the fold's step function, initial accumulator, and extraction function

This allows the `Applicative` instance to assemble derived folds that traverse the container only once

A '`Fold` a b' processes elements of type a and results in a value of type b.

Constructors

Fold (x -> a -> x) x (x -> b) | `Fold` `step` `initial` `extract`

Instances

Profunctor Fold # |
Methods dimap :: (a -> b) -> (c -> d) -> Fold b c -> Fold a d # lmap :: (a -> b) -> Fold b c -> Fold a c # rmap :: (b -> c) -> Fold a b -> Fold a c # (#.) :: Coercible * c b => (b -> c) -> Fold a b -> Fold a c # (.#) :: Coercible * b a => Fold b c -> (a -> b) -> Fold a c #
Functor (Fold a) # |
Methods fmap :: (a -> b) -> Fold a a -> Fold a b # (<$) :: a -> Fold a b -> Fold a a #
Applicative (Fold a) # |
Methods pure :: a -> Fold a a # (<*>) :: Fold a (a -> b) -> Fold a a -> Fold a b # (*>) :: Fold a a -> Fold a b -> Fold a b # (<*) :: Fold a a -> Fold a b -> Fold a a #
Comonad (Fold a) # |
Methods extract :: Fold a a -> a # duplicate :: Fold a a -> Fold a (Fold a a) # extend :: (Fold a a -> b) -> Fold a a -> Fold a b #
Floating b => Floating (Fold a b) # |
Methods pi :: Fold a b # exp :: Fold a b -> Fold a b # log :: Fold a b -> Fold a b # sqrt :: Fold a b -> Fold a b # (**) :: Fold a b -> Fold a b -> Fold a b # logBase :: Fold a b -> Fold a b -> Fold a b # sin :: Fold a b -> Fold a b # cos :: Fold a b -> Fold a b # tan :: Fold a b -> Fold a b # asin :: Fold a b -> Fold a b # acos :: Fold a b -> Fold a b # atan :: Fold a b -> Fold a b # sinh :: Fold a b -> Fold a b # cosh :: Fold a b -> Fold a b # tanh :: Fold a b -> Fold a b # asinh :: Fold a b -> Fold a b # acosh :: Fold a b -> Fold a b # atanh :: Fold a b -> Fold a b # log1p :: Fold a b -> Fold a b # expm1 :: Fold a b -> Fold a b # log1pexp :: Fold a b -> Fold a b # log1mexp :: Fold a b -> Fold a b #
Fractional b => Fractional (Fold a b) # |
Methods (/) :: Fold a b -> Fold a b -> Fold a b # recip :: Fold a b -> Fold a b # fromRational :: Rational -> Fold a b #
Num b => Num (Fold a b) # |
Methods (+) :: Fold a b -> Fold a b -> Fold a b # (-) :: Fold a b -> Fold a b -> Fold a b # (*) :: Fold a b -> Fold a b -> Fold a b # negate :: Fold a b -> Fold a b # abs :: Fold a b -> Fold a b # signum :: Fold a b -> Fold a b # fromInteger :: Integer -> Fold a b #
Monoid b => Monoid (Fold a b) # |
Methods mempty :: Fold a b # mappend :: Fold a b -> Fold a b -> Fold a b # mconcat :: [Fold a b] -> Fold a b #

data FoldM m a b #

Like `Fold`, but monadic.

A '`FoldM` m a b' processes elements of type a and results in a monadic value of type m b.

Constructors

FoldM (x -> a -> m x) (m x) (x -> m b) | `FoldM` `step` `initial` `extract`

Instances

Monad m => Profunctor (FoldM m) # |
Methods dimap :: (a -> b) -> (c -> d) -> FoldM m b c -> FoldM m a d # lmap :: (a -> b) -> FoldM m b c -> FoldM m a c # rmap :: (b -> c) -> FoldM m a b -> FoldM m a c # (#.) :: Coercible * c b => (b -> c) -> FoldM m a b -> FoldM m a c # (.#) :: Coercible * b a => FoldM m b c -> (a -> b) -> FoldM m a c #
Monad m => Functor (FoldM m a) # |
Methods fmap :: (a -> b) -> FoldM m a a -> FoldM m a b # (<$) :: a -> FoldM m a b -> FoldM m a a #
Monad m => Applicative (FoldM m a) # |
Methods pure :: a -> FoldM m a a # (<*>) :: FoldM m a (a -> b) -> FoldM m a a -> FoldM m a b # (*>) :: FoldM m a a -> FoldM m a b -> FoldM m a b # (<*) :: FoldM m a a -> FoldM m a b -> FoldM m a a #
(Monad m, Floating b) => Floating (FoldM m a b) # |
Methods pi :: FoldM m a b # exp :: FoldM m a b -> FoldM m a b # log :: FoldM m a b -> FoldM m a b # sqrt :: FoldM m a b -> FoldM m a b # (**) :: FoldM m a b -> FoldM m a b -> FoldM m a b # logBase :: FoldM m a b -> FoldM m a b -> FoldM m a b # sin :: FoldM m a b -> FoldM m a b # cos :: FoldM m a b -> FoldM m a b # tan :: FoldM m a b -> FoldM m a b # asin :: FoldM m a b -> FoldM m a b # acos :: FoldM m a b -> FoldM m a b # atan :: FoldM m a b -> FoldM m a b # sinh :: FoldM m a b -> FoldM m a b # cosh :: FoldM m a b -> FoldM m a b # tanh :: FoldM m a b -> FoldM m a b # asinh :: FoldM m a b -> FoldM m a b # acosh :: FoldM m a b -> FoldM m a b # atanh :: FoldM m a b -> FoldM m a b # log1p :: FoldM m a b -> FoldM m a b # expm1 :: FoldM m a b -> FoldM m a b # log1pexp :: FoldM m a b -> FoldM m a b # log1mexp :: FoldM m a b -> FoldM m a b #
(Monad m, Fractional b) => Fractional (FoldM m a b) # |
Methods (/) :: FoldM m a b -> FoldM m a b -> FoldM m a b # recip :: FoldM m a b -> FoldM m a b # fromRational :: Rational -> FoldM m a b #
(Monad m, Num b) => Num (FoldM m a b) # |
Methods (+) :: FoldM m a b -> FoldM m a b -> FoldM m a b # (-) :: FoldM m a b -> FoldM m a b -> FoldM m a b # (*) :: FoldM m a b -> FoldM m a b -> FoldM m a b # negate :: FoldM m a b -> FoldM m a b # abs :: FoldM m a b -> FoldM m a b # signum :: FoldM m a b -> FoldM m a b # fromInteger :: Integer -> FoldM m a b #
(Monoid b, Monad m) => Monoid (FoldM m a b) # |
Methods mempty :: FoldM m a b # mappend :: FoldM m a b -> FoldM m a b -> FoldM m a b # mconcat :: [FoldM m a b] -> FoldM m a b #

# Folding

fold :: Foldable f => Fold a b -> f a -> b #

Apply a strict left `Fold` to a `Foldable` container

foldM :: (Foldable f, Monad m) => FoldM m a b -> f a -> m b #

Like `fold`, but monadic

scan :: Fold a b -> [a] -> [b] #

Convert a strict left `Fold` into a scan

# Folds

mconcat :: Monoid a => Fold a a #

Fold all values within a container using `mappend` and `mempty`

foldMap :: Monoid w => (a -> w) -> (w -> b) -> Fold a b #

Convert a "`foldMap`" to a `Fold`

head :: Fold a (Maybe a) #

Get the first element of a container or return `Nothing` if the container is empty

last :: Fold a (Maybe a) #

Get the last element of a container or return `Nothing` if the container is empty

lastDef :: a -> Fold a a #

Get the last element of a container or return a default value if the container is empty

lastN :: Int -> Fold a [a] #

Return the last N elements

null :: Fold a Bool #

Returns `True` if the container is empty, `False` otherwise

length :: Fold a Int #

Return the length of the container

and :: Fold Bool Bool #

Returns `True` if all elements are `True`, `False` otherwise

or :: Fold Bool Bool #

Returns `True` if any element is `True`, `False` otherwise

all :: (a -> Bool) -> Fold a Bool #

`(all predicate)` returns `True` if all elements satisfy the predicate, `False` otherwise

any :: (a -> Bool) -> Fold a Bool #

`(any predicate)` returns `True` if any element satisfies the predicate, `False` otherwise

sum :: Num a => Fold a a #

Computes the sum of all elements

product :: Num a => Fold a a #

Computes the product all elements

maximum :: Ord a => Fold a (Maybe a) #

Computes the maximum element

maximumBy :: (a -> a -> Ordering) -> Fold a (Maybe a) #

Computes the maximum element with respect to the given comparison function

minimum :: Ord a => Fold a (Maybe a) #

Computes the minimum element

minimumBy :: (a -> a -> Ordering) -> Fold a (Maybe a) #

Computes the minimum element with respect to the given comparison function

elem :: Eq a => a -> Fold a Bool #

`(elem a)` returns `True` if the container has an element equal to `a`, `False` otherwise

notElem :: Eq a => a -> Fold a Bool #

`(notElem a)` returns `False` if the container has an element equal to `a`, `True` otherwise

find :: (a -> Bool) -> Fold a (Maybe a) #

`(find predicate)` returns the first element that satisfies the predicate or `Nothing` if no element satisfies the predicate

index :: Int -> Fold a (Maybe a) #

`(index n)` returns the `n`th element of the container, or `Nothing` if the container has an insufficient number of elements

elemIndex :: Eq a => a -> Fold a (Maybe Int) #

`(elemIndex a)` returns the index of the first element that equals `a`, or `Nothing` if no element matches

findIndex :: (a -> Bool) -> Fold a (Maybe Int) #

`(findIndex predicate)` returns the index of the first element that satisfies the predicate, or `Nothing` if no element satisfies the predicate

random :: FoldM IO a (Maybe a) #

Pick a random element, using reservoir sampling

randomN :: Vector v a => Int -> FoldM IO a (Maybe (v a)) #

Pick several random elements, using reservoir sampling

mapM_ :: Monad m => (a -> m ()) -> FoldM m a () #

Converts an effectful function to a fold. Specialized version of `sink`.

sink :: (Monoid w, Monad m) => (a -> m w) -> FoldM m a w #

Converts an effectful function to a fold

    sink (f <> g) = sink f <> sink g -- if `(<>)` is commutative
    sink mempty = mempty

# Generic Folds

genericLength :: Num b => Fold a b #

Like `length`, except with a more general `Num` return value

genericIndex :: Integral i => i -> Fold a (Maybe a) #

Like `index`, except with a more general `Integral` argument

# Container folds

list :: Fold a [a] #

Fold all values into a list

revList :: Fold a [a] #

Fold all values into a list, in reverse order

nub :: Ord a => Fold a [a] #

O(n log n). Fold values into a list with duplicates removed, while preserving their first occurrences

eqNub :: Eq a => Fold a [a] #

O(n^2). Fold values into a list with duplicates removed, while preserving their first occurrences

set :: Ord a => Fold a (Set a) #

Fold values into a set

vector :: (PrimMonad m, Vector v a) => FoldM m a (v a) #

Fold all values into a vector

# Utilities

`purely` and `impurely` allow you to write folds compatible with the `foldl` library without incurring a `foldl` dependency. Write your fold to accept three parameters corresponding to the step function, initial accumulator, and extraction function and then users can upgrade your function to accept a `Fold` or `FoldM` using the `purely` or `impurely` combinators.

For example, the `pipes` library implements `fold` and `foldM` functions in `Pipes.Prelude` with the following type:

    Pipes.Prelude.fold
        :: Monad m
        -> (x -> a -> x) -> x -> (x -> b) -> Producer a m () -> m b

    Pipes.Prelude.foldM
        :: Monad m
        => (x -> a -> m x) -> m x -> (x -> m b) -> Producer a m () -> m b

Both `fold` and `foldM` is set up so that you can wrap them with either `purely` or `impurely` to accept a `Fold` or `FoldM`, respectively:

    purely Pipes.Prelude.fold
        :: Monad m => Fold a b -> Producer a m () -> m b

    impurely Pipes.Prelude.foldM
        :: Monad m => FoldM m a b -> Producer a m () -> m b

Similarly the `ofoldlUnwrap` and `ofoldMUnwrap` functions from the `monotraversable` package are written to interoperate with this library:

    ofoldlUnwrap
        :: MonoFoldable mono
        => (x -> Element mono -> x) -> x -> (x -> b) -> mono -> b

    ofoldMUnwrap
        :: (Monad m, MonoFoldable mono)
        => (x -> Element mono -> m x) -> m x -> (x -> m b) -> mono -> m b

You can wrap these to accept `Fold` or `FoldM`, too:

    purely ofoldlUnwrap
        :: MonoFoldable mono
        => Fold (Element mono) b -> mono -> b

    impurely ofoldMUnwrap
        :: MonoFoldable mono
        => FoldM m (Element mono) b -> mono -> m b

purely :: (forall x. (x -> a -> x) -> x -> (x -> b) -> r) -> Fold a b -> r #

Upgrade a fold to accept the `Fold` type

purely_ :: (forall x. (x -> a -> x) -> x -> x) -> Fold a b -> b #

Upgrade a more traditional fold to accept the `Fold` type

impurely :: Monad m => (forall x. (x -> a -> m x) -> m x -> (x -> m b) -> r) -> FoldM m a b -> r #

Upgrade a monadic fold to accept the `FoldM` type

impurely_ :: Monad m => (forall x. (x -> a -> m x) -> m x -> m x) -> FoldM m a b -> m b #

Upgrade a more traditional monadic fold to accept the `FoldM` type

generalize :: Monad m => Fold a b -> FoldM m a b #

Generalize a `Fold` to a `FoldM`

    generalize (pure r) = pure r

    generalize (f <*> x) = generalize f <*> generalize x

simplify :: FoldM Identity a b -> Fold a b #

Simplify a pure `FoldM` to a `Fold`

    simplify (pure r) = pure r

    simplify (f <*> x) = simplify f <*> simplify x

hoists :: Monad m => (forall x. m x -> n x) -> FoldM m a b -> FoldM n a b #

Shift a `FoldM` from one monad to another with a morphism such as `lift` or `liftIO`; the effect is the same as `hoist`.

duplicateM :: Applicative m => FoldM m a b -> FoldM m a (FoldM m a b) #

Allows to continue feeding a `FoldM` even after passing it to a function that closes it.

For pure `Fold`s, this is provided by the `Comonad` instance.

_Fold1 :: (a -> a -> a) -> Fold a (Maybe a) #

`_Fold1 step` returns a new `Fold` using just a step function that has the same type for the accumulator and the element. The result type is the accumulator type wrapped in `Maybe`. The initial accumulator is retrieved from the `Foldable`, the result is `None` for empty containers.

premap :: (a -> b) -> Fold b r -> Fold a r #

`(premap f folder)` returns a new `Fold` where f is applied at each step

    fold (premap f folder) list = fold folder (map f list)

    >>> fold (premap Sum mconcat) [1..10]
    Sum {getSum = 55}

    >>> fold mconcat (map Sum [1..10])
    Sum {getSum = 55}

    premap id = id

    premap (f . g) = premap g . premap f

    premap k (pure r) = pure r

    premap k (f <*> x) = premap k f <*> premap k x

premapM :: (a -> b) -> FoldM m b r -> FoldM m a r #

`(premapM f folder)` returns a new `FoldM` where f is applied to each input element

    foldM (premapM f folder) list = foldM folder (map f list)

    premapM id = id

    premapM (f . g) = premap g . premap f

    premapM k (pure r) = pure r

    premapM k (f <*> x) = premapM k f <*> premapM k x

type Handler a b = forall x. (b -> Const (Dual (Endo x)) b) -> a -> Const (Dual (Endo x)) a #

A handler for the upstream input of a `Fold`

Any lens, traversal, or prism will type-check as a `Handler`

handles :: Handler a b -> Fold b r -> Fold a r #

`(handles t folder)` transforms the input of a `Fold` using a lens, traversal, or prism:

    handles _1       :: Fold a r -> Fold (a, b) r
    handles _Left    :: Fold a r -> Fold (Either a b) r
    handles traverse :: Traversable t => Fold a r -> Fold (t a) r
    handles folded   :: Foldable    t => Fold a r -> Fold (t a) r

    >>> fold (handles traverse sum) [[1..5],[6..10]]
    55

    >>> fold (handles (traverse.traverse) sum) [[Nothing, Just 2, Just 7],[Just 13, Nothing, Just 20]]
    42

    >>> fold (handles (filtered even) sum) [1..10]
    30

    >>> fold (handles _2 mconcat) [(1,"Hello "),(2,"World"),(3,"!")]
    "Hello World!"

    handles id = id

    handles (f . g) = handles f . handles g

    handles t (pure r) = pure r

    handles t (f <*> x) = handles t f <*> handles t x

newtype EndoM m a #

    instance Monad m => Monoid (EndoM m a) where
        mempty = EndoM return
        mappend (EndoM f) (EndoM g) = EndoM (f <=< g)

Constructors

EndoM |
Fields appEndoM :: a -> m a

Instances

Monad m => Monoid (EndoM m a) # |
Methods mempty :: EndoM m a # mappend :: EndoM m a -> EndoM m a -> EndoM m a # mconcat :: [EndoM m a] -> EndoM m a #

type HandlerM m a b = forall x. (b -> Const (Dual (EndoM m x)) b) -> a -> Const (Dual (EndoM m x)) a #

A Handler for the upstream input of `FoldM`

Any lens, traversal, or prism will type-check as a `HandlerM`

handlesM :: Monad m => HandlerM m a b -> FoldM m b r -> FoldM m a r #

`(handlesM t folder)` transforms the input of a `FoldM` using a lens, traversal, or prism:

    handlesM _1       :: FoldM m a r -> FoldM (a, b) r
    handlesM _Left    :: FoldM m a r -> FoldM (Either a b) r
    handlesM traverse :: Traversable t => FoldM m a r -> FoldM m (t a) r
    handlesM folded   :: Foldable    t => FoldM m a r -> FoldM m (t a) r

`handlesM` obeys these laws:

    handlesM id = id

    handlesM (f . g) = handlesM f . handlesM g

    handlesM t (pure r) = pure r

    handlesM t (f <*> x) = handlesM t f <*> handlesM t x

folded :: (Contravariant f, Applicative f, Foldable t) => (a -> f a) -> t a -> f (t a) #

    folded :: Foldable t => Fold (t a) a

    handles folded :: Foldable t => Fold a r -> Fold (t a) r

filtered :: Monoid m => (a -> Bool) -> (a -> m) -> a -> m #

    >>> fold (handles (filtered even) sum) [1..10]
    30

    >>> foldM (handlesM (filtered even) (mapM_ print)) [1..10]
    2
    4
    6
    8
    10

# Re-exports

`Control.Monad.Primitive` re-exports the `PrimMonad` type class

`Data.Foldable` re-exports the `Foldable` type class

`Data.Vector.Generic` re-exports the `Vector` type class

module Control.Monad.Primitive

module Data.Foldable

module Data.Vector.Generic