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 rearrange 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 rearrange 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)