packages feed

foldl-transduce 0.4.5.0 → 0.4.6.0

raw patch · 8 files changed

+423/−84 lines, 8 filesdep +semigroupsdep +splitPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: semigroups, split

API changes (from Hackage documentation)

- Control.Foldl.Transduce.Internal: _1of3 :: (a, b, c) -> a
+ Control.Foldl.Transduce.ByteString: chunkSize :: Int -> ChunkSize
+ Control.Foldl.Transduce.ByteString: chunkSizeDefault :: ChunkSize
+ Control.Foldl.Transduce.ByteString: data ChunkSize
+ Control.Foldl.Transduce.ByteString: drainHandle :: (MonadIO m, ToFoldM m f) => f ByteString r -> ChunkSize -> Handle -> m r
+ Control.Foldl.Transduce.ByteString: instance GHC.Classes.Eq Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Classes.Ord Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Num.Num Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Show.Show Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: toHandle :: (MonadIO m) => Handle -> FoldM m ByteString ()
+ Control.Foldl.Transduce.ByteString: toHandleBuilder :: (MonadIO m) => Handle -> FoldM m Builder ()
+ Control.Foldl.Transduce.Internal: fst3 :: (a, b, c) -> a
+ Control.Foldl.Transduce.Text: paragraphs :: Transducer Text Text ()

Files

CHANGELOG view
@@ -1,3 +1,9 @@+# 0.4.6.0++- Deprecated Control.Foldl.Transduce.ByteString.IO +- Added Control.Foldl.Transduce.ByteString+- Added "paragraphs" splitter.+ # 0.4.5.0  - added split
foldl-transduce.cabal view
@@ -1,5 +1,5 @@ Name: foldl-transduce-Version: 0.4.5.0+Version: 0.4.6.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -30,16 +30,19 @@         containers                   < 0.6 ,         bifunctors    == 5.*               ,         profunctors   == 5.*               ,+        semigroups    >= 0.18              ,         semigroupoids >= 5.0               ,         foldl         >= 1.1      && < 2   ,         comonad       == 4.*               ,         free          == 4.*               ,                  void          >= 0.6               ,+        split         >= 0.2.2             ,         monoid-subclasses == 0.4.*              Exposed-Modules:         Control.Foldl.Transduce,         Control.Foldl.Transduce.Text,         Control.Foldl.Transduce.Textual,+        Control.Foldl.Transduce.ByteString,         Control.Foldl.Transduce.ByteString.IO,         Control.Foldl.Transduce.Internal     GHC-Options: -O2 -Wall@@ -67,6 +70,7 @@         tasty-hunit >= 0.9.2,         tasty-quickcheck >= 0.8.3.2,          monoid-subclasses == 0.4.*,+        split         >= 0.2.2,         foldl               ,         foldl-transduce 
src/Control/Foldl/Transduce.hs view
@@ -121,7 +121,7 @@ import Control.Comonad.Cofree  import Control.Foldl (Fold(..),FoldM(..)) import qualified Control.Foldl as L-import Control.Foldl.Transduce.Internal (Pair(..),Quartet(..),_1of3)+import Control.Foldl.Transduce.Internal (Pair(..),Quartet(..),fst3)  {- $setup @@ -168,7 +168,7 @@ -} type Transduction' a b r = forall x. Fold b x -> Fold a (r,x) -{-| Helper for storing a 'ReifiedTransduction'' safely on a container.		+{-| Helper for storing a 'Transduction'' safely on a container.		  -} newtype ReifiedTransduction' a b r = ReifiedTransduction' { getTransduction' :: Transduction' a b r }@@ -203,7 +203,7 @@      = forall x. Transducer (x -> i -> (x,[o],[[o]])) x (x -> (r,[o],[[o]]))  instance Comonad (Transducer i o) where-    extract (Transducer _ begin done) = _1of3 (done begin)+    extract (Transducer _ begin done) = fst3 (done begin)     {-# INLINABLE extract #-}      duplicate (Transducer step begin done) = Transducer step begin (\x -> (Transducer step x done,[],[]))@@ -486,14 +486,14 @@ -} foldify :: Transducer i o s -> Fold i s foldify (Transducer step begin done) =-    Fold (\x i -> _1of3 (step x i)) begin (\x -> _1of3 (done x))+    Fold (\x i -> fst3 (step x i)) begin (\x -> fst3 (done x))  {-| Monadic version of 'foldify'.		  -} foldifyM :: Functor m => TransducerM m i o s -> FoldM m i s foldifyM (TransducerM step begin done) =-    FoldM (\x i -> fmap _1of3 (step x i)) begin (\x -> fmap _1of3 (done x))+    FoldM (\x i -> fmap fst3 (step x i)) begin (\x -> fmap fst3 (done x))  {-| Transforms a 'Fold' into a 'Transducer' that sends the return value of the     'Fold' downstream when upstream closes.		
+ src/Control/Foldl/Transduce/ByteString.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- |+--+-- Pour handles into folds,+-- write to handles using folds. +module Control.Foldl.Transduce.ByteString (+        -- * Reading from handles+        drainHandle+    ,   ChunkSize+    ,   chunkSize+    ,   chunkSizeDefault+        -- * Writing to handles+    ,   toHandle+    ,   toHandleBuilder  +    ) where++import qualified Control.Foldl as L+import Control.Foldl.Transduce +import qualified Data.ByteString as B+import qualified Data.ByteString.Builder as B+import Control.Monad.IO.Class+import System.IO+import Data.ByteString.Lazy.Internal (defaultChunkSize)++{-| Feed a fold with bytes read from a 'Handle'.++-}+drainHandle +    :: (MonadIO m,ToFoldM m f) +    => f B.ByteString r +    -> ChunkSize +    -> Handle +    -> m r +drainHandle f (ChunkSize csize) h = driveHandle f csize h++{-| Maximum chunk size		++-}+newtype ChunkSize = ChunkSize Int deriving (Show,Eq,Ord,Num)++chunkSize :: Int -> ChunkSize+chunkSize = ChunkSize++chunkSizeDefault :: ChunkSize+chunkSizeDefault = chunkSize defaultChunkSize++driveHandle :: (MonadIO m,ToFoldM m f) +            => f B.ByteString r +            -> Int -- ^ max chunk size+            -> Handle +            -> m r +driveHandle (toFoldM -> f) chunkSize handle = +    L.impurely consumeFunc f (B.hGetSome handle chunkSize,hIsEOF handle)+    where+        -- adapted from foldM in Pipes.Prelude+        consumeFunc step begin done (readChunk,checkEOF) = do+            x0 <- begin+            loop x0+              where+                loop x = do+                    atEOF <- liftIO checkEOF+                    if atEOF +                       then done x +                       else do+                           chunk <- liftIO readChunk+                           x' <- step x chunk+                           loop $! x'+++toHandle :: (MonadIO m) => Handle -> L.FoldM m B.ByteString ()+toHandle handle = +    L.FoldM +    (\_ b -> liftIO (B.hPut handle b))  +    (return ()) +    (\_ -> return ())+++toHandleBuilder :: (MonadIO m) => Handle -> L.FoldM m B.Builder ()+toHandleBuilder handle = +    L.FoldM+    (\_ b -> liftIO (B.hPutBuilder handle b)) +    (return ()) +    (\_ -> return ())++
src/Control/Foldl/Transduce/ByteString/IO.hs view
@@ -5,7 +5,7 @@ -- -- Pour handles into folds, -- write to handles using folds. -module Control.Foldl.Transduce.ByteString.IO (+module Control.Foldl.Transduce.ByteString.IO {-# DEPRECATED "Use Control.Foldl.Transduce.ByteString instead." #-} (         driveHandle     ,   toHandle     ,   toHandleBuilder  
src/Control/Foldl/Transduce/Internal.hs view
@@ -2,12 +2,12 @@         -- * Strict datatypes          Pair(..)     ,   Quartet(..)-    ,   _1of3+    ,   fst3     ) where  data Pair a b = Pair !a !b  data Quartet a b c d = Quartet !a !b !c !d -_1of3 :: (a,b,c) -> a-_1of3 (x,_,_) = x+fst3 :: (a,b,c) -> a+fst3 (x,_,_) = x
src/Control/Foldl/Transduce/Text.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}  -- | --@@ -17,8 +18,9 @@     ,   stripStart     ,   stripEnd         -- * Splitters-    ,   lines     ,   words+    ,   lines+    ,   paragraphs         -- * Re-exports         -- $reexports     ,   module Control.Foldl.Transduce.Textual@@ -27,7 +29,7 @@ import Prelude hiding (lines,words) import Data.Char import Data.Monoid (mempty)-import Data.Foldable (foldMap)+import Data.Foldable (foldMap,foldl') import qualified Data.ByteString as B import qualified Data.Text  import qualified Data.Text as T@@ -40,6 +42,11 @@ import qualified Control.Foldl.Transduce as L import Control.Foldl.Transduce.Textual import Control.Foldl.Transduce.Internal (Pair(..))+import qualified Data.List+import Data.List.Split+import qualified Data.List.Split+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty  {- $setup @@ -55,7 +62,7 @@  {-| Builds a decoding 'Transducer' out of a stream-oriented decoding function     from "Data.Text.Encoding" and an error handler from-    "Data.Text.Encoding.Error".		+    "Data.Text.Encoding.Error".          -} decoder :: (B.ByteString -> T.Decoding) -> T.OnDecodeError -> L.Transducer B.ByteString T.Text ()@@ -73,7 +80,7 @@     onLeftovers' = onLeftovers "leftovers" Nothing  {-| Builds a UTF8-decoding 'Transducer'. Takes an error handler from-    "Data.Text.Encoding.Error".		+    "Data.Text.Encoding.Error".          -} utf8 :: T.OnDecodeError -> L.Transducer B.ByteString T.Text ()@@ -112,7 +119,7 @@ utf8strict = utf8 T.strictDecode  {-| Similar to 'decoder', but catches 'UnicodeException' in 'IO' and uses-    'Control.Monad.Trans.Except' to communicate the error.		+    'Control.Monad.Trans.Except' to communicate the error.          -} decoderE :: MonadIO m@@ -141,7 +148,7 @@         onLeftovers' = T.strictDecode "leftovers" Nothing  {-| Like 'utf8strict', but catches 'UnicodeException' in 'IO' and uses-    'Control.Monad.Trans.Except' to communicate the error.		+    'Control.Monad.Trans.Except' to communicate the error.          >>> runExceptT $ L.foldM (transduceM utf8E (L.generalize L.list)) (map fromString ["invalid \xc3\x28 sequence"]) Left Cannot decode byte '\x28': Data.Text.Internal.Encoding.streamDecodeUtf8With: Invalid UTF-8 stream@@ -152,7 +159,7 @@ utf8E :: MonadIO m => L.TransducerM (ExceptT T.UnicodeException m) B.ByteString T.Text ()    utf8E = decoderE T.streamDecodeUtf8With -{-| Appends a newline at the end of the stream.		+{-| Appends a newline at the end of the stream.          >>> L.fold (transduce newline L.list) (map T.pack ["without","newline"]) ["without","newline","\n"]@@ -163,7 +170,7 @@ blank :: T.Text -> Bool blank = Data.Text.all isSpace -{-| Remove leading white space from a stream of 'Text'.		+{-| Remove leading white space from a stream of 'Text'.          >>> L.fold (transduce stripStart L.list) (map T.pack ["   ","", "   text "]) ["text "]@@ -178,7 +185,7 @@                 else (True, [T.stripStart i],[])         done _  = ((),[],[]) -{-| Remove trailing white space from a stream of 'Text'.		+{-| Remove trailing white space from a stream of 'Text'.              __/BEWARE!/__      This function naively accumulates in memory any arriving "blank blocks" of@@ -274,6 +281,119 @@                         (_,[]) -> error "never happens, txt not blank"                 in (nextstate,oldgroup,newgroups)         done _ = ((),[],[])+++data ParagraphsState = +      SkippingAfterStreamStart+    | SkippingAfterNewline+    | SkippingAfterBlankLine+    | ContinuingNonemptyLine++{-| Splits a stream of text into paragraphs, removing empty lines and trimming+    newspace from the start of each line.++>>> map mconcat (L.fold (folds paragraphs L.list L.list) (map T.pack [" \n aaa","\naa ", " \n\nbb\n"]))+["aaa\naa  \n","bb\n"]++    Used with 'L.transduce', it removes empty lines and trims newspace from the+    start of each line.+-}+paragraphs :: L.Transducer T.Text T.Text ()+paragraphs = L.Transducer step SkippingAfterStreamStart done +    where+        step tstate txt+            | Data.Text.null txt = +                (tstate,[],[])+            | otherwise = +                let (initlines,lastline) = splittedLines txt+                    (tstate', outputsreversed) =+                        advanceLast+                        (foldl' +                            advance+                            (tstate,pure [])+                            initlines)+                        lastline          +                    (xs :| xss) = fmap reverse (NonEmpty.reverse outputsreversed)+                in (tstate',xs,xss)+        done _ = +            ((),[],[])+        splittedLines :: T.Text -> ([T.Text],T.Text)+        splittedLines nonEmptyChunk = +            let splitted = +                    Data.Text.lines nonEmptyChunk +                    +++                    if T.last nonEmptyChunk == '\n' then [mempty] else mempty+            in (init splitted, last splitted) -- unsafe with empty lists!!!+        advance +            :: (ParagraphsState, NonEmpty [T.Text]) +            -> T.Text +            -> (ParagraphsState, NonEmpty [T.Text])+        advance (s,outputs) i = +            case (s, blank i) of+                (SkippingAfterStreamStart, True) -> +                    (,) +                    SkippingAfterStreamStart +                    outputs+                (SkippingAfterStreamStart, False) -> +                    (,)+                    SkippingAfterNewline+                    (prepend ["\n",T.stripStart i] outputs) +                (SkippingAfterNewline, True) -> +                    (,) +                    SkippingAfterBlankLine +                    outputs +                (SkippingAfterNewline, False) -> +                    (,)+                    SkippingAfterNewline+                    (prepend ["\n",T.stripStart i] outputs)+                (SkippingAfterBlankLine, True) -> +                    (,) +                    SkippingAfterBlankLine +                    outputs +                (SkippingAfterBlankLine, False) -> +                    (,)+                    SkippingAfterNewline+                    (prepend ["\n",T.stripStart i] (NonEmpty.cons [] outputs)) +                (ContinuingNonemptyLine, _) -> +                    (,)+                    SkippingAfterNewline+                    (prepend ["\n",i] outputs)+        advanceLast +                :: (ParagraphsState, NonEmpty [T.Text]) +                -> T.Text +                -> (ParagraphsState, NonEmpty [T.Text])+        advanceLast (s,outputs) i = +            case (s, blank i) of+                (SkippingAfterStreamStart, True) -> +                    (,) +                    SkippingAfterStreamStart +                    outputs+                (SkippingAfterStreamStart, False) -> +                    (,)+                    ContinuingNonemptyLine+                    (prepend [T.stripStart i] outputs)+                (SkippingAfterNewline, True) -> +                    (,) +                    SkippingAfterNewline +                    outputs+                (SkippingAfterNewline, False) -> +                    (,)+                    ContinuingNonemptyLine+                    (prepend [T.stripStart i] outputs)+                (SkippingAfterBlankLine, True) -> +                    (,)+                    SkippingAfterBlankLine+                    outputs +                (SkippingAfterBlankLine, False) -> +                    (,)+                    ContinuingNonemptyLine+                    (prepend [T.stripStart i] (NonEmpty.cons [] outputs))+                (ContinuingNonemptyLine, _) -> +                    (,)+                    ContinuingNonemptyLine+                    (prepend [i] outputs)+        prepend :: [a] -> NonEmpty [a] -> NonEmpty [a]+        prepend as (as':| rest) = (as ++ as') :| rest  ------------------------------------------------------------------------------ 
tests/tests.hs view
@@ -1,9 +1,12 @@ module Main where  import Prelude hiding (splitAt,lines,words)+import Data.Char import Data.String hiding (lines,words) import Data.Monoid import Data.Bifunctor+import qualified Data.List (intersperse,splitAt)+import qualified Data.List.Split as Split import qualified Data.Monoid.Factorial as SFM import Test.Tasty import Test.Tasty.HUnit@@ -17,104 +20,222 @@ import Control.Foldl.Transduce.Text import Control.Foldl.Transduce.Textual +{- $quickcheck++   Notes for quickchecking on the REPL:++cabal repl tests+:t sample+sample :: Show a => Gen a -> IO ()+sample (arbitrary :: Gen WordA)++-}+ main :: IO () main = defaultMain tests -newtype WordQC = WordQC { getWordQC :: T.Text } deriving (Show)+testCaseEq :: (Eq a, Show a) => TestName -> a -> a -> TestTree+testCaseEq name a1 a2 = testCase name (assertEqual "" a1 a2) -instance Arbitrary WordQC where+blank :: T.Text -> Bool+blank = T.all isSpace++nl :: T.Text+nl = T.pack "\n"++sp :: T.Text+sp = T.pack " "++c :: T.Text+c = T.pack "c"++{- $words++-}++newtype WordA = WordA { getWord :: T.Text } deriving (Show)++instance Arbitrary WordA where     arbitrary = do         firstChar <- oneof [pure ' ', pure '\n', arbitrary]         lastChar <- oneof [pure ' ', pure '\n', arbitrary]         middle <- listOf (frequency [(1,pure ' '),(4,arbitrary)])-        return (WordQC (T.pack (firstChar : (middle ++ [lastChar]))))+        return (WordA (T.pack (firstChar : (middle ++ [lastChar])))) +{- $paragraphs++-}++newtype TextChunksA = TextChunksA { getChunks :: [T.Text] } deriving (Show)++instance Arbitrary TextChunksA where+    arbitrary = flip suchThat (not . blank . mconcat . getChunks) (do+        TextChunksA <$> partz)+            where+                chunkz = frequency [+                      (20::Int, flip T.replicate sp <$> choose (1,40)) +                    , (20, flip T.replicate sp <$> choose (1,3)) +                    , (50, pure nl)+                    , (20, flip T.replicate c <$> choose (1,30))+                    , (20, flip T.replicate c <$> choose (1,3))+                    ]+                combined = mconcat <$> vectorOf 40 chunkz +                partitions = infiniteListOf (choose (1::Int,7))+                partz = partition [] <$> combined <*> partitions+                partition :: [T.Text] -> T.Text -> [Int] -> [T.Text]+                partition accum text (x:xs) =+                    if x >= T.length text    +                       then reverse (text:accum)+                       else +                           let (point,rest) = T.splitAt x text +                           in +                           partition (point:accum) rest xs+                partition _ _ [] = error "never happens"+    shrink (TextChunksA texts) = +        let removeIndex i xs = +                let (xs',xs'') = Data.List.splitAt i xs+                in xs' ++ tail xs'' +            l = length texts+        in +        if l == 1 +           then []+           else map (\i -> TextChunksA (removeIndex i texts)) [0..l-1] ++paragraphsBaseline +    :: T.Text -> [T.Text] +paragraphsBaseline =  +      map (T.unlines . map T.stripStart . T.lines)+    . map mconcat +    . map (`mappend` [nl])+    . map (Data.List.intersperse nl)+    . filter (not . null) +    . Split.splitWhen blank +    . T.lines++ignoreLastNewline :: [T.Text] -> [T.Text]+ignoreLastNewline ts = +    let +        lastt = last ts+        lastt' = if T.last lastt == '\n' then T.init lastt else lastt +    in init ts ++ [lastt']++-- (paragraphs,chunks)+splittedParagraphs :: T.Text -> [Int] -> [([T.Text],[T.Text])]+splittedParagraphs txt splitsizes =   +    let +        splitted = paragraphsBaseline txt+    in +    zip (repeat splitted) (map (flip T.chunksOf txt) splitsizes)++paragraphsUnderTest+    :: [T.Text] -> [T.Text] +paragraphsUnderTest txt =+    map mconcat (L.fold (folds paragraphs L.list L.list) txt)++paragraph01 :: T.Text+paragraph01 = +    T.pack +    "  \n \n\n \n \n \+    \a aa aaa \nb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bb \n \+    \ ccccccccccccccccccccccc cccccccc \n\n  \n \n\n ccc\     +    \ \n \n \nd\n\n\ne \+    \\n" +    +paragraph02 :: T.Text+paragraph02 = T.pack " cc  "+ tests :: TestTree tests =      testGroup "Tests"      [         testGroup "surround"          [-            testCase "surroundempty" $ -                assertEqual mempty-                    "prefixsuffix"-                    (L.fold (transduce (surround "prefix" "suffix") L.list) "")-        ]-        ,+            testCaseEq "surroundempty" +                "prefixsuffix"+                (L.fold (transduce (surround "prefix" "suffix") L.list) "")+        ],         testGroup "chunksOf"          [-            testCase "emptyList3" $ -                assertEqual mempty-                    ([[]]::[[Int]])-                    (L.fold (folds (chunksOf 3) L.list L.list) [])+            testCaseEq "emptyList3"+                ([[]]::[[Int]])+                (L.fold (folds (chunksOf 3) L.list L.list) [])             ,-            testCase "size1" $ -                assertEqual mempty-                    ([[1],[2],[3],[4],[5],[6],[7]]::[[Int]])-                    (L.fold (folds (chunksOf 1) L.list L.list) [1..7])+            testCaseEq "size1" +                ([[1],[2],[3],[4],[5],[6],[7]]::[[Int]])+                (L.fold (folds (chunksOf 1) L.list L.list) [1..7])             ,-            testCase "size3" $ -                assertEqual mempty-                    ([[1,2,3],[4,5,6],[7]]::[[Int]])-                    (L.fold (folds (chunksOf 3) L.list L.list) [1..7])-        ]-        ,-        testGroup "textualBreak" $ +            testCaseEq "size3" +                ([[1,2,3],[4,5,6],[7]]::[[Int]])+                (L.fold (folds (chunksOf 3) L.list L.list) [1..7])+        ],+        testGroup "textualBreak"         [-            testCase "beginwithdot" $-                assertEqual mempty-                    ".bb"-                    (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa",".bb"])+            testCaseEq "beginwithdot"+                ".bb"+                (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa",".bb"])             ,-            testCase "endwithdot" $-                assertEqual mempty-                    "."-                    (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa","bb."])-        ]   -        ,-        testGroup "newline" $ +            testCaseEq "endwithdot"+                "."+                (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa","bb."])+        ],+        testGroup "newline"         [-            testCase "newlineempty" $-                assertEqual mempty+            testCaseEq "newlineempty"                 (T.pack "\n")                 (mconcat (L.fold (transduce newline L.list) (map T.pack [])))             ,-            testCase "newlinenull" $-                assertEqual mempty+            testCaseEq "newlinenull"                 (T.pack "\n")                 (mconcat (L.fold (transduce newline L.list) (map T.pack [""])))-        ]-        ,+        ],         testGroup "words"          [              testGroup "quickcheck"              [ -                testProperty "quickcheck1" (\chunks -> -                         let tchunks = fmap getWordQC chunks -                         in-                         (case TL.words (TL.fromChunks tchunks) of-                            [] -> [mempty]-                            x -> x) ==-                         (fmap TL.fromChunks (L.fold (folds words L.list L.list) tchunks)))+                testProperty "quickcheck1" (\chunks -> -- list of words +                    let tchunks = fmap getWord chunks +                    in+                    (case TL.words (TL.fromChunks tchunks) of+                       [] -> [mempty]+                       x -> x) ==+                    (fmap TL.fromChunks (L.fold (folds words L.list L.list) tchunks)))             ]-        ]-        ,-        testGroup "quiesceWith" $ +        ],+        testGroup "paragraphs"          [-            testCase "collectAfterFailure" $-                let foldthatfails = -                        transduceM utf8E (L.generalize L.list)-                    inputs = -                        map fromString ["invalid \xc3\x28 sequence","xxx","zzz","___"]-                    fallbackfold =-                        bisectM (chunkedSplitAt 4) (reifyM id) ignore (L.generalize L.list)-                in-                do-                   r <- L.foldM (quiesceWith fallbackfold foldthatfails) inputs -                   assertEqual -                       mempty -                       (Left ('C',4))-                       (first (bimap (head . show) (SFM.length . mconcat)) r)+            testCase "paragraphs01"+                (mapM_+                    (\(x,y) -> assertEqual "" (ignoreLastNewline x) (ignoreLastNewline (paragraphsUnderTest y))) +                    (splittedParagraphs paragraph01 [1..7])),+            testCaseEq "newlineAtEnd"+                (map T.pack ["aa\n"]) +                (paragraphsUnderTest (map T.pack ["a","a","\n"])),+            testCaseEq "noNewlineAtEnd"+                (map T.pack ["aa"]) +                (paragraphsUnderTest (map T.pack ["a","a"])),+            testGroup "quickcheck" +            [ +                testProperty "quickcheck1" (\(TextChunksA chunks) ->+                        ignoreLastNewline (paragraphsUnderTest chunks)+                        ==+                        ignoreLastNewline (paragraphsBaseline (mconcat chunks)))+            ]+        ],+        testGroup "quiesceWith"  +        [+            testCase "collectAfterFailure" (do+               let+                  foldthatfails = +                      transduceM utf8E (L.generalize L.list)+                  inputs = +                      map fromString ["invalid \xc3\x28 sequence","xxx","zzz","___"]+                  fallbackfold =+                      bisectM (chunkedSplitAt 4) (reifyM id) ignore (L.generalize L.list)+               r <- L.foldM (quiesceWith fallbackfold foldthatfails) inputs +               assertEqual +                   mempty +                   (Left ('C',4))+                   (first (bimap (head . show) (SFM.length . mconcat)) r))         ]        ]