foldl-transduce 0.1.0.1 → 0.1.2.0
raw patch · 5 files changed
+129/−10 lines, 5 filesdep +bifunctorsPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: bifunctors
API changes (from Hackage documentation)
+ Control.Foldl.Transduce: groups' :: Splitter i -> Fold u v -> Transduction' i a u -> Transduction' i a v
+ Control.Foldl.Transduce: groupsM' :: Monad m => Splitter i -> FoldM m u v -> TransductionM' m i a u -> TransductionM' m i a v
+ Control.Foldl.Transduce: type Transduction' a b r = forall x. Fold b x -> Fold a (r, x)
+ Control.Foldl.Transduce: type TransductionM' m a b r = forall x. FoldM m b x -> FoldM m a (r, x)
+ Control.Foldl.Transduce.Internal: Trio :: !a -> !b -> !c -> Trio a b c
+ Control.Foldl.Transduce.Internal: data Trio a b c
- Control.Foldl.Transduce: transduce' :: Transducer i o x -> Fold o y -> Fold i (x, y)
+ Control.Foldl.Transduce: transduce' :: Transducer i o x -> Transduction' i o x
- Control.Foldl.Transduce: transduceM' :: Monad m => TransducerM m i o x -> FoldM m o y -> FoldM m i (x, y)
+ Control.Foldl.Transduce: transduceM' :: Monad m => TransducerM m i o x -> TransductionM' m i o x
Files
- CHANGELOG +7/−2
- README.md +33/−3
- foldl-transduce.cabal +3/−2
- src/Control/Foldl/Transduce.hs +83/−3
- src/Control/Foldl/Transduce/Internal.hs +3/−0
CHANGELOG view
@@ -1,5 +1,10 @@-0.1.1.0-=======+# 0.1.2.0+- Added explicit bifunctors dependency.+- Added Transduce', TransduceM' type synonyms.+- Added groups', groupsM'.+++# 0.1.1.0 - Changed signatures of transduce' and transduceM'. - generalize' -> generalizeTransducer
README.md view
@@ -1,3 +1,33 @@-Stateful transducers and streaming-preserving grouping operations for the folds-in Gabriel Gonzalez's [foldl](http://hackage.haskell.org/package/foldl)-package.+## What's in this library?++Stateful transducers and streaming-preserving group operations for the folds in+Gabriel Gonzalez's [foldl](http://hackage.haskell.org/package/foldl) package.++## When to use this library?++- When you want to wrap a stateful decoder over a **Fold**. An example is+decoding UTF-8: the decoder must be stateful because a multi-byte character may+have been split across two blocks of bytes.++- When you want to tweak the stream of data that arrives into a **Fold**, but+only at certain positions. Stripping whitespace at the beginning of a text+stream, for example.++- When you want to perform group operations without breaking "streaminess",+similar to what [pipes-group](http://hackage.haskell.org/package/pipes-group)+does.++## Why use this library for grouping instead of **pipes-group**?++Grouping fold-side instead of producer-side has the advantage that, since the+results are still **Fold**s, you can combine them using **Applicative**.++Also, **Fold**s can work with sources other than **Producer**s from pipes.++Grouping fold-side has limitations as well:++- You can't perform bracketing operations like "withFile" that span the folding+of an entire group. You can do that in pipes-group.++- You have more flexibility in pipes-group to decide how to fold a group based+on previous results.
foldl-transduce.cabal view
@@ -1,5 +1,5 @@ Name: foldl-transduce-Version: 0.1.0.1+Version: 0.1.2.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -8,7 +8,7 @@ Author: Daniel Diaz Maintainer: diaz_carrete@yahoo.com Bug-Reports: https://github.com/danidiaz/foldl-transduce/issues-Synopsis: Transducers for folds from foldl.+Synopsis: Transducers for foldl folds. Description: Stateful transducers and streaming-preserving grouping operations for the folds in the foldl package. Category: Control @@ -28,6 +28,7 @@ text >= 0.11.2.0 && < 1.3 , transformers >= 0.2.0.0 && < 0.5 , containers < 0.6 ,+ bifunctors == 5.* , semigroupoids >= 5.0 , foldl >= 1.1 && < 2 , comonad == 4.*
src/Control/Foldl/Transduce.hs view
@@ -10,8 +10,10 @@ module Control.Foldl.Transduce ( -- * Transducer types Transduction + , Transduction' , Transducer(..) , TransductionM+ , TransductionM' , TransducerM(..) -- * Applying transducers , transduce@@ -34,7 +36,9 @@ , Splitter(..) -- * Working with groups , groups+ , groups' , groupsM+ , groupsM' , folds , foldsM -- * Splitters@@ -54,12 +58,13 @@ import Control.Comonad import Control.Foldl (Fold(..),FoldM(..)) import qualified Control.Foldl as L-import Control.Foldl.Transduce.Internal(Pair(..))+import Control.Foldl.Transduce.Internal (Pair(..),Trio(..)) {- $setup >>> import qualified Control.Foldl as L >>> import Control.Foldl.Transduce+>>> import Control.Applicative -} @@ -93,6 +98,12 @@ type Transduction a b = forall x. Fold b x -> Fold a x +{-| A more general from of 'Transduction' that adds new information to the+ return value of the 'Fold'.++-}+type Transduction' a b r = forall x. Fold b x -> Fold a (r,x)+ {-| Representation of a stateful 'Transduction' with step function, an initial accumulator, and a extraction function that returns a summary value of type @r@. Both the step function and the extraction function may send output@@ -112,6 +123,8 @@ type TransductionM m a b = forall x. Monad m => FoldM m b x -> FoldM m a x +type TransductionM' m a b r = forall x. FoldM m b x -> FoldM m a (r,x)+ {-| Like 'Transducer', but monadic. -}@@ -146,7 +159,7 @@ >>> L.fold (transduce' (Transducer (\_ i -> ((),[i])) () (\_ -> ('r',[]))) L.list) [1..7] ('r',[1,2,3,4,5,6,7]) -}-transduce' :: Transducer i o x -> Fold o y -> Fold i (x,y)+transduce' :: Transducer i o x -> Transduction' i o x transduce' (Transducer wstep wstate wdone) (Fold fstep fstate fdone) = Fold step (Pair wstate fstate) done where@@ -163,7 +176,7 @@ transduceM :: Monad m => TransducerM m i o r -> TransductionM m i o transduceM t = fmap snd . (transduceM' t) -transduceM' :: Monad m => TransducerM m i o x -> FoldM m o y -> FoldM m i (x,y)+transduceM' :: Monad m => TransducerM m i o x -> TransductionM' m i o x transduceM' (TransducerM wstep wstate wdone) (FoldM fstep fstate fdone) = FoldM step (liftM2 Pair wstate fstate) done where@@ -306,6 +319,8 @@ {-| Applies a 'Transduction' to all groups detected by a 'Splitter', returning a 'Transduction' that works over the undivided stream of inputs. +>>> L.fold (groups (chunksOf 2) (transduce (surround "<" ">")) L.list) "aabbccdd"+"<aa><bb><cc><dd>" -} groups :: Splitter i -> Transduction i b -> Transduction i b groups (Splitter sstep sbegin sdone) t f =@@ -323,6 +338,42 @@ done (Pair ss (Fold fstep fstate fdone)) = extract (fdone (foldl' fstep fstate (sdone ss))) +{-| Generalized version of 'groups' that obtains a summary value for each+ group, aggregates them into a summary value for the whole stream, and puts+ that information in the final result. ++ In practice, this function behaves like a combinaton of 'groups' and+ 'folds' that works in a single pass.++>>> L.fold (groups' (chunksOf 2) L.list (\f -> transduce (surround "<" ">") (liftA2 (,) L.list f)) L.list) "aabbccdd"+(["<aa>","<bb>","<cc>","<dd>"],"<aa><bb><cc><dd>")+-}+groups' :: Splitter i + -> Fold u v -- ^ for aggregating the @u@ values produced for each group+ -> Transduction' i a u + -> Transduction' i a v -- ^ the resulting 'Fold' will return a summary @v@ of the stream+groups' (Splitter sstep sbegin sdone) summarizer t f =+ Fold step (Trio sbegin summarizer (t (duplicated f))) done + where + step (Trio ss summarizer' fs) i = + let + (ss', oldSplit, newSplits) = sstep ss i+ (summarizer'',fs') = foldl' + (\(summarizer_,fs_) split_ -> + let (u, renewed) = reset fs_+ in (L.fold (duplicated summarizer_) [u], step' renewed split_))+ (summarizer', step' fs oldSplit) + newSplits+ in+ Trio ss' summarizer'' fs'+ step' = L.fold . duplicated+ reset (Fold _ fstate fdone) = + let (u,x) = fdone fstate+ in (u,t (duplicated x))+ done (Trio ss summarizer' (Fold fstep fstate fdone)) = + let (u,extract -> x) = fdone (foldl' fstep fstate (sdone ss))+ in (L.fold summarizer' [u],x)+ groupsM :: Monad m => Splitter i -> TransductionM m i b -> TransductionM m i b groupsM (Splitter sstep sbegin sdone) t f = FoldM step (return (Pair sbegin (t (duplicated f)))) done @@ -340,6 +391,35 @@ done (Pair ss (FoldM fstep fstate fdone)) = do finalf <- fdone =<< flip (foldlM fstep) (sdone ss) =<< fstate L.foldM finalf [] ++groupsM' :: Monad m => Splitter i -> FoldM m u v -> TransductionM' m i a u -> TransductionM' m i a v +groupsM' (Splitter sstep sbegin sdone) summarizer t f =+ FoldM step (return (Trio sbegin summarizer (t (duplicated f)))) done + where+ step (Trio ss summarizer' fs) i = do+ let + (ss', oldSplit, newSplits) = sstep ss i+ fs' <- step' fs oldSplit+ (summarizer'',fs'') <- foldlM step'' (summarizer',fs') newSplits+ return $! Trio ss' summarizer'' fs''++ step' = L.foldM . duplicated++ step'' = \(summarizer_, fs) is -> do+ (u,fs') <- reset fs + u' <- L.foldM (duplicated summarizer_) [u]+ fs'' <- step' fs' is+ return $! (u',fs'') ++ reset (FoldM _ fstate fdone) = do+ (u,x) <- fdone =<< fstate + return (u, t . duplicated $ x)++ done (Trio ss summarizer' (FoldM fstep fstate fdone)) = do+ (u,finalf) <- fdone =<< flip (foldlM fstep) (sdone ss) =<< fstate+ v <- L.foldM summarizer' [u]+ r <- L.foldM finalf []+ return (v,r) {-| Summarizes each group detected by a 'Splitter' using a 'Fold', returning a 'Transduction' that allows a 'Fold' to accept the original ungrouped input.
src/Control/Foldl/Transduce/Internal.hs view
@@ -1,7 +1,10 @@ module Control.Foldl.Transduce.Internal ( -- * Strict datatypes Pair(..)+ , Trio(..) ) where data Pair a b = Pair !a !b++data Trio a b c = Trio !a !b !c