deferred-folds-0.9.11: library/DeferredFolds/Types.hs
module DeferredFolds.Types
where
import DeferredFolds.Prelude
{-|
A projection on data, which only knows how to execute a strict left-fold.
It is a monad and a monoid, and is very useful for
efficiently aggregating the projections on data intended for left-folding,
since its concatenation (`<>`) has complexity of @O(1)@.
[Intuition]
The intuition for this abstraction can be derived from lists.
Let's consider the `Data.List.foldl'` function for lists:
>foldl' :: (b -> a -> b) -> b -> [a] -> b
If we reverse its parameters we get
>foldl' :: [a] -> (b -> a -> b) -> b -> b
Which in Haskell is essentially the same as
>foldl' :: [a] -> (forall b. (b -> a -> b) -> b -> b)
We can isolate that part into an abstraction:
>newtype Unfoldl a = Unfoldl (forall b. (b -> a -> b) -> b -> b)
Then we get to this simple morphism:
>list :: [a] -> Unfoldl a
>list list = Unfoldl (\ step init -> foldl' step init list)
We can do the same with say "Data.Text.Text":
>text :: Text -> Unfoldl Char
>text text = Unfoldl (\ step init -> Data.Text.foldl' step init text)
And then we can use those both to concatenate with just an @O(1)@ cost:
>abcdef :: Unfoldl Char
>abcdef = list ['a', 'b', 'c'] <> text "def"
Please notice that up until this moment no actual data materialization has happened and
hence no traversals have appeared.
All that we've done is just composed a function,
which only specifies which parts of data structures to traverse to perform a left-fold.
Only at the moment where the actual folding will happen will we actually traverse the source data.
E.g., using the "fold" function:
>abcdefLength :: Int
>abcdefLength = fold Control.Foldl.length abcdef
-}
newtype Unfoldl a = Unfoldl (forall x. (x -> a -> x) -> x -> x)
{-|
A monadic variation of "DeferredFolds.Unfoldl"
-}
newtype UnfoldlM m a = UnfoldlM (forall x. (x -> a -> m x) -> x -> m x)
{-|
A projection on data, which only knows how to execute a right-fold.
It is a monad and a monoid, and is very useful for
efficiently aggregating the projections on data intended for right-folding,
since its concatenation (`<>`) has complexity of @O(1)@.
[Intuition]
The intuition of what this abstraction is all about can be derived from lists.
Let's consider the `Data.List.foldr` function for lists:
>foldr :: (a -> b -> b) -> b -> [a] -> b
If we reverse its parameters we get
>foldr :: [a] -> (a -> b -> b) -> b -> b
Which in Haskell is essentially the same as
>foldr :: [a] -> (forall b. (a -> b -> b) -> b -> b)
We can isolate that part into an abstraction:
>newtype Unfoldr a = Unfoldr (forall b. (a -> b -> b) -> b -> b)
Then we get to this simple morphism:
>list :: [a] -> Unfoldr a
>list list = Unfoldr (\ step init -> foldr step init list)
We can do the same with say "Data.Text.Text":
>text :: Text -> Unfoldr Char
>text text = Unfoldr (\ step init -> Data.Text.foldr step init text)
And then we can use those both to concatenate with just an @O(1)@ cost:
>abcdef :: Unfoldr Char
>abcdef = list ['a', 'b', 'c'] <> text "def"
Please notice that up until this moment no actual data materialization has happened and
hence no traversals have appeared.
All that we've done is just composed a function,
which only specifies which parts of data structures to traverse to perform a right-fold.
Only at the moment where the actual folding will happen will we actually traverse the source data.
E.g., using the "fold" function:
>abcdefLength :: Int
>abcdefLength = fold Control.Foldl.length abcdef
-}
newtype Unfoldr a = Unfoldr (forall x. (a -> x -> x) -> x -> x)
newtype UnfoldrM m a = UnfoldrM (forall x. (a -> x -> m x) -> x -> m x)