packages feed

foldl-transduce 0.2.0.0 → 0.2.1.0

raw patch · 6 files changed

+255/−89 lines, 6 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Control.Foldl.Transduce.Internal: fstOf3 :: (a, b, c) -> a
+ Control.Foldl.Transduce: drop :: Int -> Transducer a a ()
+ Control.Foldl.Transduce: dropWhile :: (a -> Bool) -> Transducer a a ()
+ Control.Foldl.Transduce: instance Comonad (Transducer i o)
+ Control.Foldl.Transduce: instance Extend (Transducer i o)
+ Control.Foldl.Transduce: instance Monad m => Extend (TransducerM m i o)
+ Control.Foldl.Transduce: take :: Int -> Transducer a a ()
+ Control.Foldl.Transduce: takeWhile :: (a -> Bool) -> Transducer a a ()
+ Control.Foldl.Transduce.Internal: _1of3 :: (a, b, c) -> a
+ Control.Foldl.Transduce.Text: words :: Transducer Text Text ()
- Control.Foldl.Transduce: _generalize :: Monad m => Transducer i o r -> TransducerM m i o r
+ Control.Foldl.Transduce: _generalize :: Monad m => Transducer i o s -> TransducerM m i o s
- Control.Foldl.Transduce: _simplify :: TransducerM Identity i o r -> Transducer i o r
+ Control.Foldl.Transduce: _simplify :: TransducerM Identity i o s -> Transducer i o s
- Control.Foldl.Transduce: foldify :: Transducer i o r -> Fold i r
+ Control.Foldl.Transduce: foldify :: Transducer i o s -> Fold i s
- Control.Foldl.Transduce: foldifyM :: Functor m => TransducerM m i o r -> FoldM m i r
+ Control.Foldl.Transduce: foldifyM :: Functor m => TransducerM m i o s -> FoldM m i s
- Control.Foldl.Transduce: folds :: Transducer i i' r -> Fold i' b -> Transduction i b
+ Control.Foldl.Transduce: folds :: Transducer a b s -> Fold b c -> Transduction a c
- Control.Foldl.Transduce: folds' :: Transducer i i' s -> Fold i' b -> Transduction' i b s
+ Control.Foldl.Transduce: folds' :: Transducer a b s -> Fold b c -> Transduction' a c s
- Control.Foldl.Transduce: foldsM :: (Applicative m, Monad m) => TransducerM m i i' r -> FoldM m i' b -> TransductionM m i b
+ Control.Foldl.Transduce: foldsM :: (Applicative m, Monad m) => TransducerM m a b s -> FoldM m b c -> TransductionM m a c
- Control.Foldl.Transduce: foldsM' :: (Applicative m, Monad m) => TransducerM m i i' s -> FoldM m i' b -> TransductionM' m i b s
+ Control.Foldl.Transduce: foldsM' :: (Applicative m, Monad m) => TransducerM m a b s -> FoldM m b c -> TransductionM' m a c s
- Control.Foldl.Transduce: groups :: Transducer i i' r -> Transduction i' b -> Transduction i b
+ Control.Foldl.Transduce: groups :: Transducer a b s -> Transduction b c -> Transduction a c
- Control.Foldl.Transduce: groups' :: Transducer i i' s -> Fold u v -> Transduction' i' a u -> Transduction' i a (s, v)
+ Control.Foldl.Transduce: groups' :: Transducer a b s -> Fold u v -> Transduction' b c u -> Transduction' a c (s, v)
- Control.Foldl.Transduce: groupsM :: Monad m => TransducerM m i i' s -> TransductionM m i' b -> TransductionM m i b
+ Control.Foldl.Transduce: groupsM :: Monad m => TransducerM m a b s -> TransductionM m b c -> TransductionM m a c
- Control.Foldl.Transduce: groupsM' :: Monad m => TransducerM m i i' s -> FoldM m u v -> TransductionM' m i' a u -> TransductionM' m i a (s, v)
+ Control.Foldl.Transduce: groupsM' :: Monad m => TransducerM m a b s -> FoldM m u v -> TransductionM' m b c u -> TransductionM' m a c (s, v)
- Control.Foldl.Transduce: hoistTransducer :: Monad m => (forall a. m a -> n a) -> TransducerM m i o r -> TransducerM n i o r
+ Control.Foldl.Transduce: hoistTransducer :: Monad m => (forall a. m a -> n a) -> TransducerM m i o s -> TransducerM n i o s
- Control.Foldl.Transduce: transduce :: Transducer i o r -> Transduction i o
+ Control.Foldl.Transduce: transduce :: Transducer i o s -> Transduction i o
- Control.Foldl.Transduce: transduce' :: Transducer i o x -> Transduction' i o x
+ Control.Foldl.Transduce: transduce' :: Transducer i o s -> Transduction' i o s
- Control.Foldl.Transduce: transduceM :: Monad m => TransducerM m i o r -> TransductionM m i o
+ Control.Foldl.Transduce: transduceM :: Monad m => TransducerM m i o s -> TransductionM m i o
- Control.Foldl.Transduce: transduceM' :: Monad m => TransducerM m i o x -> TransductionM' m i o x
+ Control.Foldl.Transduce: transduceM' :: Monad m => TransducerM m i o s -> TransductionM' m i o s

Files

CHANGELOG view
@@ -1,4 +1,11 @@+# 0.2.1.0++- Comonad and Extend instances for Transducer +- Added words splitter+- Added take, drop, takeWhile, dropWhile transducers+ # 0.2.0.0+ - Removed the Spliiter type. Now it's transducers for everything! - generalizeTransducer -> _generalize - simplifyTransducer -> _simplify@@ -6,6 +13,7 @@   # 0.1.2.0+ - Added explicit bifunctors dependency. - Added Transduce', TransduceM' type synonyms. - Added groups', groupsM'.
README.md view
@@ -27,7 +27,10 @@ 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.+  of an entire group. pipes-group allows them. +- There doesn't seem to be a way to just take the first N groups in a stream+  and afterwards rejoin them.+ - You have more flexibility in pipes-group to decide how to fold a group based-on previous results.+  on previous results.
foldl-transduce.cabal view
@@ -1,5 +1,5 @@ Name: foldl-transduce-Version: 0.2.0.0+Version: 0.2.1.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3
src/Control/Foldl/Transduce.hs view
@@ -30,6 +30,10 @@     ,   foldsM     ,   foldsM'         -- * Transducers+    ,   take+    ,   takeWhile+    ,   drop+    ,   dropWhile     ,   surround     ,   surroundIO         -- * Splitters@@ -47,6 +51,8 @@     ,   module Control.Foldl     ) where +import Prelude hiding (take,drop,takeWhile,dropWhile)+ import Data.Bifunctor import Data.Monoid import Data.Functor.Identity@@ -58,13 +64,14 @@ import Control.Comonad import Control.Foldl (Fold(..),FoldM(..)) import qualified Control.Foldl as L-import Control.Foldl.Transduce.Internal (Pair(..),Trio(..),fstOf3)+import Control.Foldl.Transduce.Internal (Pair(..),Trio(..),_1of3)  {- $setup  >>> import qualified Control.Foldl as L >>> import Control.Foldl.Transduce >>> import Control.Applicative+>>> import Prelude hiding (take,drop,takeWhile,dropWhile)  -} @@ -112,11 +119,11 @@     The step function returns a triplet of:      * The new internal state.-    * Outputs that continues the last segment detected in the previous step.+    * Outputs that continue the last segment detected in the previous step.     * A list of lists containing outputs for segments detected in the current-    step. If the list is empty, that means no splitting has taken place in the-    current step. 'Transducer's that do not perform grouping never return anything-    other than @[]@ here. In effect, they treat the whole stream as a single group.+      step. If the list is empty, that means no splitting has taken place in the+      current step. 'Transducer's that do not perform grouping never return anything+      other than @[]@ here. In effect, they treat the whole stream as a single group.      The extraction function returns the 'Transducer's own result value, as     well as any pending outputs.@@ -124,6 +131,17 @@ data Transducer i o r      = forall x. Transducer (x -> i -> (x,[o],[[o]])) x (x -> (r,[o])) +instance Comonad (Transducer i o) where+    extract (Transducer _ begin done) = fst (done begin)+    {-# INLINABLE extract #-}++    duplicate (Transducer step begin done) = Transducer step begin (\x -> (Transducer step x done,[]))+    {-# INLINABLE duplicate #-}++instance Extend (Transducer i o) where+    duplicated f = duplicate f+    {-# INLINABLE duplicated #-}+ instance Functor (Transducer i o) where     fmap f (Transducer step begin done) = Transducer step begin (first f . done) @@ -161,13 +179,18 @@         TransducerM (fmap (fmap (\(x,xs,xss) -> (x,map f xs, map (map f) xss))) . step) begin (fmap (fmap (fmap f)) . done)     second f w = fmap f w +instance Monad m => Extend (TransducerM m i o) where+    duplicated (TransducerM step begin done) = +        TransducerM step begin (\x -> return $! (TransducerM step (return x) done,[]))+    {-# INLINABLE duplicated #-}+ {-| Apply a 'Transducer' to a 'Fold', discarding the return value of the     'Transducer'.		  >>> L.fold (transduce (Transducer (\_ i -> ((),[i],[])) () (\_ -> ('r',[]))) L.list) [1..7] [1,2,3,4,5,6,7] -}-transduce :: Transducer i o r -> Transduction i o +transduce :: Transducer i o s -> Transduction i o  transduce t = fmap snd . (transduce' t)  {-| Generalized version of 'transduce' that preserves the return value of@@ -176,7 +199,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 -> Transduction' i o x+transduce' :: Transducer i o s -> Transduction' i o s transduce' (Transducer wstep wstate wdone) (Fold fstep fstate fdone) =     Fold step (Pair wstate fstate) done          where@@ -193,13 +216,13 @@ {-| Like 'transduce', but works on monadic 'Fold's.		  -}-transduceM :: Monad m => TransducerM m i o r -> TransductionM m i o +transduceM :: Monad m => TransducerM m i o s -> TransductionM m i o  transduceM t = fmap snd . (transduceM' t)  {-| Like 'transduce'', but works on monadic 'Fold's.		  -}-transduceM' :: Monad m => TransducerM m i o x -> TransductionM' m i o x+transduceM' :: Monad m => TransducerM m i o s -> TransductionM' m i o s transduceM' (TransducerM wstep wstate wdone) (FoldM fstep fstate fdone) =     FoldM step (liftM2 Pair wstate fstate) done          where@@ -214,6 +237,78 @@  ------------------------------------------------------------------------------ +{-| Pass the first @n@ inputs to the 'Fold', and ignore the rest.		++>>> L.fold (transduce (take 2) L.list) [1..5]+[1,2]++>>> L.fold (transduce (take 0) L.list) [1..5]+[]+-}+take :: Int -> Transducer a a ()+take howmany = +    Transducer step howmany done +    where+        step howmanypending i +            | howmanypending == 0 = +                (0,[],[])+            | otherwise = +                (pred howmanypending,[i],[]) +        done = const ((),[])++{-| 		++>>> L.fold (transduce (takeWhile (<3)) L.list) [1..5]+[1,2]+-}+takeWhile :: (a -> Bool) -> Transducer a a ()+takeWhile predicate = +    Transducer step False done +    where+        step False i = +            if predicate i +               then (False,[i],[])+               else (True,[],[])+        step True _ = +               (True,[],[])+        done = const ((),[])++{-| Ignore the firs @n@ inputs, pass all subsequent inputs to the 'Fold'.		++>>> L.fold (transduce (drop 2) L.list) [1..5]+[3,4,5]++>>> L.fold (transduce (drop 0) L.list) [1..5]+[1,2,3,4,5]+-}+drop :: Int -> Transducer a a ()+drop howmany = +    Transducer step howmany done +    where+        step howmanypending i +            | howmanypending == 0 = +                (0,[i],[]) +            | otherwise = +                (pred howmanypending,[],[])+        done = const ((),[])++{-| 		++>>> L.fold (transduce (dropWhile (<3)) L.list) [1..5]+[3,4,5]+-}+dropWhile :: (a -> Bool) -> Transducer a a ()+dropWhile predicate = +    Transducer step False done +    where+        step False i = +            if predicate i +               then (False,[],[])+               else (True,[i],[])+        step True i = +               (True,[i],[])+        done = const ((),[])+ data SurroundState = PrefixAdded | PrefixPending  {-| Adds a prefix and a suffix to the stream arriving into a 'Fold'.		@@ -229,8 +324,10 @@             (PrefixAdded, ps ++ [a],[])         step PrefixAdded a =              (PrefixAdded, [a],[])-        done PrefixPending = ((), ps ++ ss)-        done PrefixAdded = ((), ss)+        done PrefixPending = +            ((), ps ++ ss)+        done PrefixAdded = +            ((), ss)  {-| Like 'surround', but the prefix and suffix are obtained using a 'IO'     action.@@ -263,7 +360,7 @@ {-| Generalize a 'Transducer' to a 'TransducerM'.		  -}-_generalize :: Monad m => Transducer i o r -> TransducerM m i o r+_generalize :: Monad m => Transducer i o s -> TransducerM m i o s _generalize (Transducer step begin done) = TransducerM step' begin' done'     where     step' x a = return (step x a)@@ -273,7 +370,7 @@ {-| Simplify a pure 'TransducerM' to a 'Transducer'.		  -}-_simplify :: TransducerM Identity i o r -> Transducer i o r+_simplify :: TransducerM Identity i o s -> Transducer i o s _simplify (TransducerM step begin done) = Transducer step' begin' done'      where     step' x a = runIdentity (step x a)@@ -285,29 +382,29 @@     downstream.		  -}-foldify :: Transducer i o r -> Fold i r+foldify :: Transducer i o s -> Fold i s foldify (Transducer step begin done) =-    Fold (\x i -> fstOf3 (step x i)) begin (\x -> fst (done x))+    Fold (\x i -> _1of3 (step x i)) begin (\x -> fst (done x))  {-| Monadic version of 'foldify'.		  -}-foldifyM :: Functor m => TransducerM m i o r -> FoldM m i r+foldifyM :: Functor m => TransducerM m i o s -> FoldM m i s foldifyM (TransducerM step begin done) =-    FoldM (\x i -> fmap fstOf3 (step x i)) begin (\x -> fmap fst (done x))+    FoldM (\x i -> fmap _1of3 (step x i)) begin (\x -> fmap fst (done x))  {-| Transforms a 'Fold' into a 'Transducer' that sends the return value of the     'Fold' downstream when upstream closes.		  -}-chokepoint :: Fold i b -> Transducer i b ()+chokepoint :: Fold a r -> Transducer a r () chokepoint (Fold fstep fstate fdone) =     (Transducer wstep fstate wdone)     where         wstep = \fstate' i -> (fstep fstate' i,[],[])         wdone = \fstate' -> ((),[fdone fstate']) -chokepointM :: Applicative m => FoldM m i b -> TransducerM m i b ()+chokepointM :: Applicative m => FoldM m a r -> TransducerM m a r () chokepointM (FoldM fstep fstate fdone) =      (TransducerM wstep fstate wdone)     where@@ -318,7 +415,7 @@ {-| Changes the base monad used by a 'TransducerM'.		  -}-hoistTransducer :: Monad m => (forall a. m a -> n a) -> TransducerM m i o r -> TransducerM n i o r +hoistTransducer :: Monad m => (forall a. m a -> n a) -> TransducerM m i o s -> TransducerM n i o s  hoistTransducer g (TransducerM step begin done) = TransducerM (\s i -> g (step s i)) (g begin) (g . done)  {-| Changes the base monad used by a 'FoldM'.		@@ -331,13 +428,14 @@  {-| Repeatedly applies a 'Transduction' to process each of the groups     demarcated by a 'Transducer', returning a 'Fold' what works over the-    undivided stream of inputs. The return value of the 'Transducer' is-    discarded.+    undivided stream of inputs. +    +    The return value of the 'Transducer' is discarded.  >>> L.fold (groups (chunksOf 2) (transduce (surround "<" ">")) L.list) "aabbccdd" "<aa><bb><cc><dd>" -}-groups :: Transducer i i' r -> Transduction i' b -> Transduction i b +groups :: Transducer a b s -> Transduction b c -> Transduction a c  groups splitter transduction oldfold =      let transduction' = fmap ((,) ()) . transduction         newfold = groups' splitter L.mconcat transduction' oldfold @@ -353,38 +451,37 @@ >>> 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' :: Transducer i i' s+groups' :: Transducer a b s         -> Fold u v -- ^ auxiliary 'Fold' that aggregates the @u@ values produced for each group-        -> Transduction' i' a u -- ^ repeatedly applied for processing each group-        -> Transduction' i a (s,v) -groups' (Transducer sstep sbegin sdone) summarizer t f =-    Fold step (Trio sbegin summarizer (t (duplicated f))) done +        -> Transduction' b c u -- ^ repeatedly applied for processing each group+        -> Transduction' a c (s,v) +groups' (Transducer sstep sbegin sdone) somesummarizer t somefold =+    Fold step (Trio sbegin somesummarizer (t (duplicated somefold))) done        where -        step (Trio ss summarizer' fs) i = +        step (Trio sstate summarizer innerfold) 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) +               (sstate', oldSplit, newSplits) = sstep sstate i+               (summarizer',innerfold') = +                   foldl' +                   (\(summarizer_,innerfold_) somesplit -> +                       let (u,resetted) = reset innerfold_+                       in  (L.fold (duplicated summarizer_) [u], feed resetted somesplit))+                   (summarizer, feed innerfold 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)) = +           Trio sstate' summarizer' innerfold'+        feed = L.fold . duplicated+        reset (Fold _ fstate fdone) = fmap (t . duplicated) (fdone fstate) +        done (Trio sstate summarizer (Fold fstep fstate fdone)) =              let -                (s,xss) = sdone ss-                (u,extract -> x) = fdone (foldl' fstep fstate xss)-            in ((s,L.fold summarizer' [u]),x)+                (s,bss) = sdone sstate+                (u,extract -> x) = fdone (foldl' fstep fstate bss)+            in  ((s,L.fold summarizer [u]),x)  {-| Monadic version of 'groups'.		  -}-groupsM :: Monad m => TransducerM m i i' s -> TransductionM m i' b -> TransductionM m i b+groupsM :: Monad m => TransducerM m a b s -> TransductionM m b c -> TransductionM m a c groupsM splitter transduction oldfold =      let transduction' = fmap ((,) ()) . transduction         newfold = @@ -395,33 +492,33 @@ {-| Monadic version of 'groups''.		  -}-groupsM' :: Monad m => TransducerM m i i' s -> FoldM m u v -> TransductionM' m i' a u -> TransductionM' m i a (s,v) -groupsM' (TransducerM sstep sbegin sdone) summarizer t f =-    FoldM step (sbegin >>= \zzz -> return (Trio zzz summarizer (t (duplicated f)))) done        +groupsM' :: Monad m => TransducerM m a b s -> FoldM m u v -> TransductionM' m b c u -> TransductionM' m a c (s,v) +groupsM' (TransducerM sstep sbegin sdone) somesummarizer t somefold =+    FoldM step (sbegin >>= \x -> return (Trio x somesummarizer (t (duplicated somefold)))) done             where-        step (Trio ss summarizer' fs) i = do-            (ss', oldSplit, newSplits) <- sstep ss i -            fs' <- step' fs oldSplit-            (summarizer'',fs'') <- foldlM step'' (summarizer',fs') newSplits-            return $! Trio ss' summarizer'' fs''+        step (Trio sstate summarizer innerfold) i = do+            (sstate', oldSplit, newSplits) <- sstep sstate i +            innerfold' <- feed innerfold oldSplit+            (summarizer',innerfold'') <- foldlM step' (summarizer,innerfold') newSplits+            return $! Trio sstate' summarizer' innerfold'' -        step' = L.foldM . duplicated+        step' = \(summarizer, innerfold) is -> do+            (u,innerfold') <- reset innerfold +            summarizer' <- L.foldM (duplicated summarizer) [u]+            innerfold'' <- feed innerfold' is+            return $! (summarizer',innerfold'')  -        step'' = \(summarizer_, fs) is -> do-            (u,fs') <- reset fs -            u' <- L.foldM (duplicated summarizer_) [u]-            fs'' <- step' fs' is-            return $! (u',fs'') +        feed = L.foldM . duplicated          reset (FoldM _ fstate fdone) = do            (u,x) <- fdone =<< fstate -           return (u, t . duplicated $ x)+           return (u, t (duplicated x)) -        done (Trio ss summarizer' (FoldM fstep fstate fdone)) = do-            (s,xss) <- sdone ss-            (u,finalf) <- fdone =<< flip (foldlM fstep) xss =<< fstate-            v <- L.foldM summarizer' [u]-            r <- L.foldM finalf []+        done (Trio sstate summarizer (FoldM fstep fstate fdone)) = do+            (s,bss) <- sdone sstate+            (u,finalfold) <- fdone =<< flip (foldlM fstep) bss =<< fstate+            v <- L.foldM summarizer [u]+            r <- L.foldM finalfold []             return ((s,v),r)  {-| Summarizes each of the groups demarcated by the 'Transducer' using a@@ -429,14 +526,18 @@          The result value of the 'Transducer' is discarded. +>>> L.fold (folds (chunksOf 3) L.sum L.list) [1..7]+[6,15,7] -}-folds :: Transducer i i' r -> Fold i' b -> Transduction i b+folds :: Transducer a b s -> Fold b c -> Transduction a c folds splitter f = groups splitter (transduce (chokepoint f))  {-| Like 'folds', but preserves the return value of the 'Transducer'. +>>> L.fold (folds' (chunksOf 3) L.sum L.list) [1..7]+((),[6,15,7]) -}-folds' :: Transducer i i' s -> Fold i' b -> Transduction' i b s+folds' :: Transducer a b s -> Fold b c -> Transduction' a c s folds' splitter innerfold somefold =      fmap (bimap fst id) (groups' splitter L.mconcat innertrans somefold)     where@@ -445,14 +546,14 @@ {-| Monadic version of 'folds'.		  -}-foldsM :: (Applicative m,Monad m) => TransducerM m i i' r -> FoldM m i' b -> TransductionM m i b+foldsM :: (Applicative m,Monad m) => TransducerM m a b s -> FoldM m b c -> TransductionM m a c foldsM splitter f = groupsM splitter (transduceM (chokepointM f))   {-| Monadic version of 'folds''.		  -}-foldsM' :: (Applicative m,Monad m) => TransducerM m i i' s -> FoldM m i' b -> TransductionM' m i b s+foldsM' :: (Applicative m,Monad m) => TransducerM m a b s -> FoldM m b c -> TransductionM' m a c s foldsM' splitter innerfold somefold =      fmap (bimap fst id) (groupsM' splitter (L.generalize L.mconcat) innertrans somefold)     where
src/Control/Foldl/Transduce/Internal.hs view
@@ -2,12 +2,12 @@         -- * Strict datatypes          Pair(..)     ,   Trio(..)-    ,   fstOf3+    ,   _1of3     ) where  data Pair a b = Pair !a !b  data Trio a b c = Trio !a !b !c -fstOf3 :: (a,b,c) -> a-fstOf3 (x,_,_) = x+_1of3 :: (a,b,c) -> a+_1of3 (x,_,_) = x
src/Control/Foldl/Transduce/Text.hs view
@@ -18,9 +18,10 @@     ,   stripEnd         -- * Splitters     ,   lines+    ,   words     ) where -import Prelude hiding (lines)+import Prelude hiding (lines,words) import Data.Char import Data.Monoid (mempty) import Data.Foldable (foldMap)@@ -38,7 +39,7 @@  {- $setup ->>> import Data.String hiding (lines)+>>> import Data.String hiding (lines,words) >>> import Data.Text (Text) >>> import Control.Applicative >>> import Control.Monad.Trans.Except@@ -194,25 +195,78 @@             txt : _ -> ((), [T.stripEnd txt])             _ -> ((), []) -{-| Splits a stream into lines, removing the newlines.+{-| Splits a stream of text into lines, removing the newlines. ->>> L.fold (L.groups lines id L.list) (map T.pack ["line 1\n line 2\n"])-["line 1"," line 2"]+>>> L.fold (L.groups lines (transduce (surround [T.pack "x"] [])) L.list) (map T.pack ["line 1\n line 2\n"])+["x","line 1","x"," line 2"]  >>> L.fold (L.groups lines (transduce newline) L.list) (map T.pack ["line 1\n line 2\n"]) ["line 1","\n"," line 2","\n"]++    Used with 'L.transduce', it simply removes newlines:++>>> L.fold (L.transduce lines L.list) (map T.pack ["line 1\n line 2\n"])+["line 1"," line 2"] -} lines :: L.Transducer T.Text T.Text () lines = L.Transducer step False done      where-        step previousnl txt | Data.Text.null txt = (previousnl,[],[]) -        step previousnl txt = do-            let-                lastc = Data.Text.last txt == '\n'-                txts = T.lines txt-            case (previousnl,txts) of-                (_,[]) -> error "never happens"-                (True,_) -> (lastc, [], map pure txts)-                (False,t:ts) -> (lastc, [t], map pure ts)+        step previousnl txt =+            if Data.Text.null txt+               then  +                   (previousnl,[],[])+               else+                   let+                       lastc = Data.Text.last txt == '\n'+                       txts = T.lines txt+                   in+                   case (previousnl,txts) of+                       (_,[]) -> error "never happens"+                       (True,_) -> (lastc, [], map pure txts)+                       (False,t:ts) -> (lastc, [t], map pure ts)++        done _ = ((),[])+++data WordsState = +      NoLastChar+    | LastCharSpace+    | LastCharNotSpace++{-| Splits a stream of text into words, removing whitespace.++>>> L.fold (folds words L.list L.list) (map T.pack ["  a","aa ", "bb c","cc dd ","ee f","f"])+[["a","aa"],["bb"],["c","cc"],["dd"],["ee"],["f","f"]]++    Used with 'L.transduce', it simply removes all whitespace:++>>> L.fold (L.transduce words L.list) (map T.pack ["  a","aa ", "bb c","cc dd ","ee f","f"])+["a","aa","bb","c","cc","dd","ee","f","f"]+-}+words :: L.Transducer T.Text T.Text ()+words = L.Transducer step NoLastChar done +    where+        step tstate txt +            | Data.Text.null txt = (tstate,[],[])+            | blank txt = +                case tstate of+                    NoLastChar -> (NoLastChar,[],[])+                    _ -> (LastCharSpace,[],[])+            | otherwise =                    +                let nextstate = +                        if isSpace (T.last txt) +                           then LastCharSpace +                           else LastCharNotSpace+                    (oldgroup,newgroups) = case (tstate, T.words txt) of+                        (NoLastChar,w:ws) -> +                            ([w],map pure ws)+                        (LastCharSpace,ws) -> +                            ([],map pure ws)+                        (LastCharNotSpace,w:ws) -> +                            if isSpace (T.head txt)+                               then ([],map pure (w:ws))+                               else ([w],map pure ws)+                        (_,[]) -> error "never happens, txt not blank"+                in (nextstate,oldgroup,newgroups)         done _ = ((),[])