packages feed

split 0.2.3.5 → 0.2.4

raw patch · 7 files changed

+614/−514 lines, 7 filesdep ~QuickCheck

Dependency ranges changed: QuickCheck

Files

CHANGES view
@@ -1,3 +1,9 @@+* 0.2.4 (9 October 2023)++  - Test with GHC 9.6.+  - Change examples to doctests (+ add a few more), and check them as part of CI.+  - Fix up a bunch of style hints.+ * 0.2.3.5 (11 August 2022)    - Change base upper bound to < 5.
− README
@@ -1,32 +0,0 @@--Data.List.Split provides a wide range of strategies and a unified-combinator framework for splitting lists with respect to some sort of-delimiter.----------------------------------------------------------------------------Dependencies:--  There are no dependencies other than the base package.-  Data.List.Split has been tested with versions of GHC from 6.8.3 up-  through 9.0.1.  It is completely Haskell2010 (probably also-  Haskell98) compliant, so it probably builds with other compilers as-  well.--  The Properties.hs file depends on QuickCheck >= 2.4, but you don't-  need it in order to build the library itself, only to run the tests.--Build with Cabal:--    cabal install--Building Haddock documentation (recommended):--    cabal haddock--  Once the documentation has been built, you can access it by -  pointing your browser to dist/doc/html/split/index.html.--Running the tests:--  cabal configure --enable-tests && cabal build && cabal test
+ README.md view
@@ -0,0 +1,28 @@+[![Build Status][build-status]][actions]+[![split release on Hackage][hackage-img]][hackage]++[build-status]: https://github.com/byorgey/split/actions/workflows/haskell-ci.yml/badge.svg+[hackage-img]: https://img.shields.io/hackage/v/split.svg?logo=haskell+[hackage]: https://hackage.haskell.org/package/split+[actions]: https://github.com/byorgey/split/actions++List splitting+==============++`Data.List.Split` provides a wide range of strategies and a unified+combinator framework for splitting lists with respect to some sort of+delimiter.  See+<https://hackage.haskell.org/package/split/docs/Data-List-Split.html>+to get started using it.++Dependencies+============++There are no dependencies other than the base package.+`Data.List.Split` is currently tested with versions of GHC from 7.0 up+through 9.6.  It is completely Haskell2010 (probably also Haskell98)+compliant, so it probably builds with other compilers as well.++The tests in `Properties.hs` depend on `QuickCheck` >= 2.4, but you+don't need it in order to build the library itself, only to run the+tests.
split.cabal view
@@ -1,5 +1,5 @@ Name:                split-Version:             0.2.3.5+Version:             0.2.4 Stability:           stable  Description:         A collection of various methods for splitting@@ -29,35 +29,20 @@ License:             BSD3 License-file:        LICENSE Copyright:           (c) Brent Yorgey, Louis Wasserman 2008-2012-Extra-source-files:  README, test/Properties.hs, CHANGES+Extra-source-files:  README.md, test/Properties.hs, CHANGES Author:              Brent Yorgey Maintainer:          byorgey@gmail.com Category:            List Build-type:          Simple Cabal-Version:       >= 1.10-Tested-with:-  GHC == 7.0.4-  GHC == 7.2.2-  GHC == 7.4.2-  GHC == 7.6.3-  GHC == 7.8.4-  GHC == 7.10.3-  GHC == 8.0.2-  GHC == 8.2.2-  GHC == 8.4.4-  GHC == 8.6.5-  GHC == 8.8.4-  GHC == 8.10.7-  GHC == 9.0.1-  GHC == 9.2.4-  GHC == 9.4.1+Tested-with:         GHC ==9.6.2 || ==9.4.5 || ==9.2.7 || ==9.0.2 || ==8.10.7 || ==8.8.4 || ==8.6.5 || ==8.4.4 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2 || ==7.2.2 || ==7.0.4  Bug-reports:         https://github.com/byorgey/split/issues  Test-suite split-tests   type:              exitcode-stdio-1.0   main-is:           Properties.hs-  build-depends:     base, QuickCheck >= 2.4, split+  build-depends:     base, QuickCheck >= 2.4 && < 3, split   default-language:  Haskell2010   Hs-source-dirs:    test 
src/Data/List/Split.hs view
@@ -1,6 +1,5 @@ {-# OPTIONS_HADDOCK prune #-} ------------------------------------------------------------------------------ -- | -- Module      :  Data.List.Split -- Copyright   :  (c) Brent Yorgey, Louis Wasserman 2008-2012@@ -19,81 +18,70 @@ -- A git repository containing the source (including a module with -- over 40 QuickCheck properties) can be found at -- <https://github.com/byorgey/split>.--------------------------------------------------------------------------------- module Data.List.Split (--                       -- * Getting started-                       -- $started--                       -- * Convenience functions-                       -- $conv--                         splitOn-                       , splitOneOf-                       , splitWhen-                       , endBy-                       , endByOneOf--                       , wordsBy-                       , linesBy--                       -- * Other splitting methods-                       -- $other-                       , chunksOf-                       , splitPlaces-                       , splitPlacesBlanks-                       , chop-                       , divvy--                       -- * Splitting combinators-                       -- $comb--                       , Splitter-                       , defaultSplitter-                       , split--                       -- ** Basic strategies-                       -- $basic--                       , oneOf-                       , onSublist-                       , whenElt+  -- * Getting started+  -- $started -                       -- ** Strategy transformers-                       -- $transform+  -- * Convenience functions+  -- $conv+  splitOn,+  splitOneOf,+  splitWhen,+  endBy,+  endByOneOf,+  wordsBy,+  linesBy, -                       , dropDelims-                       , keepDelimsL-                       , keepDelimsR-                       , condense-                       , dropInitBlank-                       , dropFinalBlank-                       , dropInnerBlanks+  -- * Other splitting methods+  -- $other+  chunksOf,+  splitPlaces,+  splitPlacesBlanks,+  chop,+  divvy, -                       -- ** Derived combinators-                       -- $derived+  -- * Splitting combinators+  -- $comb+  Splitter,+  defaultSplitter,+  split, -                       , dropBlanks-                       , startsWith-                       , startsWithOneOf-                       , endsWith-                       , endsWithOneOf+  -- ** Basic strategies+  -- $basic+  oneOf,+  onSublist,+  whenElt, -                       -- The following synonyms are deprecated, but-                       -- still exported for now.  No documentation is-                       -- generated for them via the 'OPTIONS_HADDOCK-                       -- prune' pragma.+  -- ** Strategy transformers+  -- $transform+  dropDelims,+  keepDelimsL,+  keepDelimsR,+  condense,+  dropInitBlank,+  dropFinalBlank,+  dropInnerBlanks, -                       , sepBy-                       , sepByOneOf-                       , unintercalate-                       , splitEvery-                       , chunk+  -- ** Derived combinators+  -- $derived+  dropBlanks,+  startsWith,+  startsWithOneOf,+  endsWith,+  endsWithOneOf,+  -- The following synonyms are deprecated, but+  -- still exported for now.  No documentation is+  -- generated for them via the 'OPTIONS_HADDOCK+  -- prune' pragma. -                       ) where+  sepBy,+  sepByOneOf,+  unintercalate,+  splitEvery,+  chunk,+) where -import           Data.List.Split.Internals+import Data.List.Split.Internals  -- $started -- To get started, you should take a look at the functions 'splitOn',@@ -102,24 +90,24 @@ -- functions implement various common splitting operations, and one of -- them will probably do the job 90\% of the time.  For example: ----- > > splitOn "x" "axbxc"--- > ["a","b","c"]--- >--- > > splitOn "x" "axbxcx"--- > ["a","b","c",""]--- >--- > > endBy ";" "foo;bar;baz;"--- > ["foo","bar","baz"]--- >--- > > splitWhen (<0) [1,3,-4,5,7,-9,0,2]--- > [[1,3],[5,7],[0,2]]--- >--- > > splitOneOf ";.," "foo,bar;baz.glurk"--- > ["foo","bar","baz","glurk"]--- >--- > > chunksOf 3 ['a'..'z']--- > ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]+-- >>> splitOn "x" "axbxc"+-- ["a","b","c"] --+-- >>> splitOn "x" "axbxcx"+-- ["a","b","c",""]+--+-- >>> endBy ";" "foo;bar;baz;"+-- ["foo","bar","baz"]+--+-- >>> splitWhen (<0) [1,3,-4,5,7,-9,0,2]+-- [[1,3],[5,7],[0,2]]+--+-- >>> splitOneOf ";.," "foo,bar;baz.glurk"+-- ["foo","bar","baz","glurk"]+--+-- >>> chunksOf 3 ['a'..'z']+-- ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]+-- -- If you want more flexibility, however, you can use the combinator -- library in terms of which these functions are defined.  For more -- information, see the section labeled \"Splitting Combinators\".@@ -148,8 +136,8 @@ -- suitable 'Splitter' has been created, it can be run with the -- 'split' function.  For example: ----- > > split (dropBlanks . condense $ whenElt (<0)) [1,2,4,-5,-6,4,9,-19,-30]--- > [[1,2,4],[-5,-6],[4,9],[-19,-30]]+-- >>> split (dropBlanks . condense $ whenElt (<0)) [1,2,4,-5,-6,4,9,-19,-30]+-- [[1,2,4],[-5,-6],[4,9],[-19,-30]]  -- $basic -- All these basic strategies have the same parameters as the
src/Data/List/Split/Internals.hs view
@@ -1,6 +1,5 @@ {-# OPTIONS_HADDOCK prune #-} ------------------------------------------------------------------------------ -- | -- Module      :  Data.List.Split.Internals -- Copyright   :  (c) Brent Yorgey, Louis Wasserman 2008-2012@@ -12,31 +11,29 @@ -- Implementation module for "Data.List.Split", a combinator library -- for splitting lists.  See the "Data.List.Split" documentation for -- more description and examples.---------------------------------------------------------------------------------- module Data.List.Split.Internals where -import           Data.List (genericSplitAt)+import Data.List (genericSplitAt)  -- * Types and utilities  -- | A splitting strategy.-data Splitter a = Splitter { delimiter        :: Delimiter a-                               -- ^ What delimiter to split on-                           , delimPolicy      :: DelimPolicy-                               -- ^ What to do with delimiters (drop-                               --   from output, keep as separate-                               --   elements in output, or merge with-                               --   previous or following chunks)-                           , condensePolicy   :: CondensePolicy-                               -- ^ What to do with multiple-                               --   consecutive delimiters-                           , initBlankPolicy  :: EndPolicy-                               -- ^ Drop an initial blank?-                           , finalBlankPolicy :: EndPolicy-                               -- ^ Drop a final blank?-                           }+data Splitter a = Splitter+  { delimiter :: Delimiter a+  -- ^ What delimiter to split on+  , delimPolicy :: DelimPolicy+  -- ^ What to do with delimiters (drop+  --   from output, keep as separate+  --   elements in output, or merge with+  --   previous or following chunks)+  , condensePolicy :: CondensePolicy+  -- ^ What to do with multiple+  --   consecutive delimiters+  , initBlankPolicy :: EndPolicy+  -- ^ Drop an initial blank?+  , finalBlankPolicy :: EndPolicy+  -- ^ Drop a final blank?+  }  -- | The default splitting strategy: keep delimiters in the output --   as separate chunks, don't condense multiple consecutive@@ -55,12 +52,14 @@ --   the original input list.  This default strategy can be overridden --   to allow discarding various sorts of information. defaultSplitter :: Splitter a-defaultSplitter = Splitter { delimiter        = Delimiter [const False]-                           , delimPolicy      = Keep-                           , condensePolicy   = KeepBlankFields-                           , initBlankPolicy  = KeepBlank-                           , finalBlankPolicy = KeepBlank-                           }+defaultSplitter =+  Splitter+    { delimiter = Delimiter [const False]+    , delimPolicy = Keep+    , condensePolicy = KeepBlankFields+    , initBlankPolicy = KeepBlank+    , finalBlankPolicy = KeepBlank+    }  -- | A delimiter is a list of predicates on elements, matched by some --   contiguous subsequence of a list.@@ -69,33 +68,42 @@ -- | Try to match a delimiter at the start of a list, either failing --   or decomposing the list into the portion which matched the delimiter --   and the remainder.-matchDelim :: Delimiter a -> [a] -> Maybe ([a],[a])-matchDelim (Delimiter []) xs = Just ([],xs)-matchDelim (Delimiter _)  [] = Nothing-matchDelim (Delimiter (p:ps)) (x:xs)-  | p x       = matchDelim (Delimiter ps) xs >>= \(h,t) -> Just (x:h,t)+matchDelim :: Delimiter a -> [a] -> Maybe ([a], [a])+matchDelim (Delimiter []) xs = Just ([], xs)+matchDelim (Delimiter _) [] = Nothing+matchDelim (Delimiter (p : ps)) (x : xs)+  | p x = matchDelim (Delimiter ps) xs >>= \(h, t) -> Just (x : h, t)   | otherwise = Nothing  -- | What to do with delimiters?-data DelimPolicy = Drop      -- ^ Drop delimiters from the output.-                 | Keep      -- ^ Keep delimiters as separate chunks-                             --   of the output.-                 | KeepLeft  -- ^ Keep delimiters in the output,-                             --   prepending them to the following-                             --   chunk.-                 | KeepRight -- ^ Keep delimiters in the output,-                             --   appending them to the previous chunk.+data DelimPolicy+  = -- | Drop delimiters from the output.+    Drop+  | -- | Keep delimiters as separate chunks+    --   of the output.+    Keep+  | -- | Keep delimiters in the output,+    --   prepending them to the following+    --   chunk.+    KeepLeft+  | -- | Keep delimiters in the output,+    --   appending them to the previous chunk.+    KeepRight   deriving (Eq, Show)  -- | What to do with multiple consecutive delimiters?-data CondensePolicy = Condense         -- ^ Condense into a single delimiter.-                    | DropBlankFields  -- ^ Keep consecutive-                                       --   delimiters separate, but-                                       --   don't insert blank chunks in-                                       --   between them.-                    | KeepBlankFields  -- ^ Insert blank chunks-                                       --   between consecutive-                                       --   delimiters.+data CondensePolicy+  = -- | Condense into a single delimiter.+    Condense+  | -- | Keep consecutive+    --   delimiters separate, but+    --   don't insert blank chunks in+    --   between them.+    DropBlankFields+  | -- | Insert blank chunks+    --   between consecutive+    --   delimiters.+    KeepBlankFields   deriving (Eq, Show)  -- | What to do with a blank chunk at either end of the list@@ -138,48 +146,51 @@ splitInternal :: Delimiter a -> [a] -> SplitList a splitInternal _ [] = [] splitInternal d xxs-  | null xs   = toSplitList match+  | null xs = toSplitList match   | otherwise = Text xs : toSplitList match  where-  (xs,match) = breakDelim d xxs+  (xs, match) = breakDelim d xxs -  toSplitList Nothing             = []-  toSplitList (Just ([],r:rs))    = Delim [] : Text [r] : splitInternal d rs-  toSplitList (Just (delim,rest)) = Delim delim : splitInternal d rest+  toSplitList Nothing = []+  toSplitList (Just ([], r : rs)) = Delim [] : Text [r] : splitInternal d rs+  toSplitList (Just (delim, rest)) = Delim delim : splitInternal d rest -breakDelim :: Delimiter a -> [a] -> ([a],Maybe ([a],[a]))-breakDelim (Delimiter []) xs         = ([],Just ([],xs))-breakDelim _              []         = ([],Nothing)-breakDelim d              xxs@(x:xs) =+breakDelim :: Delimiter a -> [a] -> ([a], Maybe ([a], [a]))+breakDelim (Delimiter []) xs = ([], Just ([], xs))+breakDelim _ [] = ([], Nothing)+breakDelim d xxs@(x : xs) =   case matchDelim d xxs of-      Nothing    -> let (ys,match) = breakDelim d xs in (x:ys,match)-      Just match -> ([], Just match)+    Nothing -> let (ys, match) = breakDelim d xs in (x : ys, match)+    Just match -> ([], Just match)  -- | Given a split list in the internal tagged representation, produce --   a new internal tagged representation corresponding to the final --   output, according to the strategy defined by the given --   'Splitter'. postProcess :: Splitter a -> SplitList a -> SplitList a-postProcess s = dropFinal (finalBlankPolicy s)-              . dropInitial (initBlankPolicy s)-              . doMerge (delimPolicy s)-              . doDrop (delimPolicy s)-              . insertBlanks (condensePolicy s)-              . doCondense (condensePolicy s)+postProcess s =+  dropFinal (finalBlankPolicy s)+    . dropInitial (initBlankPolicy s)+    . doMerge (delimPolicy s)+    . doDrop (delimPolicy s)+    . insertBlanks (condensePolicy s)+    . doCondense (condensePolicy s)  -- | Drop delimiters if the 'DelimPolicy' is 'Drop'. doDrop :: DelimPolicy -> SplitList a -> SplitList a-doDrop Drop l = [ c | c@(Text _) <- l ]+doDrop Drop l = [c | c@(Text _) <- l] doDrop _ l = l  -- | Condense multiple consecutive delimiters into one if the --   'CondensePolicy' is 'Condense'. doCondense :: CondensePolicy -> SplitList a -> SplitList a doCondense Condense ls = condense' ls-  where condense' [] = []-        condense' (c@(Text _) : l) = c : condense' l-        condense' l = (Delim $ concatMap fromElem ds) : condense' rest-          where (ds,rest) = span isDelim l+ where+  condense' [] = []+  condense' (c@(Text _) : l) = c : condense' l+  condense' l = Delim (concatMap fromElem ds) : condense' rest+   where+    (ds, rest) = span isDelim l doCondense _ ls = ls  -- | Insert blank chunks between any remaining consecutive delimiters@@ -187,16 +198,16 @@ --   beginning or end if the first or last element is a delimiter. insertBlanks :: CondensePolicy -> SplitList a -> SplitList a insertBlanks _ [] = [Text []]-insertBlanks cp (d@(Delim _) : l) = Text [] : insertBlanks' cp (d:l)+insertBlanks cp (d@(Delim _) : l) = Text [] : insertBlanks' cp (d : l) insertBlanks cp l = insertBlanks' cp l  -- | Insert blank chunks between consecutive delimiters. insertBlanks' :: CondensePolicy -> SplitList a -> SplitList a insertBlanks' _ [] = []-insertBlanks' cp@DropBlankFields (d1@(Delim _) : d2@(Delim _) : l)-  = d1           : insertBlanks' cp (d2:l)-insertBlanks' cp (d1@(Delim _) : d2@(Delim _) : l)-  = d1 : Text [] : insertBlanks' cp (d2:l)+insertBlanks' cp@DropBlankFields (d1@(Delim _) : d2@(Delim _) : l) =+  d1 : insertBlanks' cp (d2 : l)+insertBlanks' cp (d1@(Delim _) : d2@(Delim _) : l) =+  d1 : Text [] : insertBlanks' cp (d2 : l) insertBlanks' _ [d@(Delim _)] = [d, Text []] insertBlanks' cp (c : l) = c : insertBlanks' cp l @@ -211,7 +222,7 @@ --   chunks, so they are merged with chunks to their right). mergeLeft :: SplitList a -> SplitList a mergeLeft [] = []-mergeLeft ((Delim d) : (Text c) : l) = Text (d++c) : mergeLeft l+mergeLeft ((Delim d) : (Text c) : l) = Text (d ++ c) : mergeLeft l mergeLeft (c : l) = c : mergeLeft l  -- | Merge delimiters with adjacent chunks to the left.@@ -220,10 +231,11 @@ -- below fanciness is with the goal of laziness: we want to start returning -- stuff before we've necessarily discovered a delimiter, in case we're -- processing some infinite list with no delimiter-mergeRight ((Text c) : l) = Text (c++d) : mergeRight lTail-  where (d, lTail) = case l of-                     Delim d' : l' -> (d', l')-                     _ -> ([], l)+mergeRight ((Text c) : l) = Text (c ++ d) : mergeRight lTail+ where+  (d, lTail) = case l of+    Delim d' : l' -> (d', l')+    _ -> ([], l) mergeRight (c : l) = c : mergeRight l  -- | Drop an initial blank chunk according to the given 'EndPolicy'.@@ -233,12 +245,13 @@  -- | Drop a final blank chunk according to the given 'EndPolicy'. dropFinal :: EndPolicy -> SplitList a -> SplitList a-dropFinal _         [] = []-dropFinal DropBlank l  = dropFinal' l-  where dropFinal' []        = []-        dropFinal' [Text []] = []-        dropFinal' (x:xs)    = x:dropFinal' xs-dropFinal _         l  = l+dropFinal _ [] = []+dropFinal DropBlank l = dropFinal' l+ where+  dropFinal' [] = []+  dropFinal' [Text []] = []+  dropFinal' (x : xs) = x : dropFinal' xs+dropFinal _ l = l  -- * Combinators @@ -249,229 +262,283 @@ split s = map fromElem . postProcess s . splitInternal (delimiter s)  -- ** Basic strategies---+ -- $ All these basic strategies have the same parameters as the -- 'defaultSplitter' except for the delimiters.  -- | A splitting strategy that splits on any one of the given---   elements.  For example:+--   elements. ----- > split (oneOf "xyz") "aazbxyzcxd" == ["aa","z","b","x","","y","","z","c","x","d"]-oneOf :: Eq a => [a] -> Splitter a-oneOf elts = defaultSplitter { delimiter = Delimiter [(`elem` elts)] }+-- >>> split (oneOf ",;") "hi;there,world"+-- ["hi",";","there",",","world"]+--+-- >>> split (oneOf "xyz") "aazbxyzcxd"+-- ["aa","z","b","x","","y","","z","c","x","d"]+oneOf :: (Eq a) => [a] -> Splitter a+oneOf elts = defaultSplitter {delimiter = Delimiter [(`elem` elts)]}  -- | A splitting strategy that splits on the given list, when it is---   encountered as an exact subsequence.  For example:+--   encountered as an exact subsequence. ----- > split (onSublist "xyz") "aazbxyzcxd" == ["aazb","xyz","cxd"]+-- >>> split (onSublist "xyz") "aazbxyzcxd"+-- ["aazb","xyz","cxd"] -- --   Note that splitting on the empty list is a special case, which---   splits just before every element of the list being split.  For example:+--   splits just before every element of the list being split. ----- > split (onSublist "") "abc" == ["","","a","","b","","c"]--- > split (dropDelims . dropBlanks $ onSublist "") "abc" == ["a","b","c"]+-- >>> split (onSublist "") "abc"+-- ["","","a","","b","","c"] --+-- >>> split (dropDelims . dropBlanks $ onSublist "") "abc"+-- ["a","b","c"]+-- --   However, if you want to break a list into singleton elements like --   this, you are better off using @'chunksOf' 1@, or better yet, --   @'map' (:[])@.-onSublist :: Eq a => [a] -> Splitter a-onSublist lst = defaultSplitter { delimiter = Delimiter (map (==) lst) }+onSublist :: (Eq a) => [a] -> Splitter a+onSublist lst = defaultSplitter {delimiter = Delimiter (map (==) lst)}  -- | A splitting strategy that splits on any elements that satisfy the---   given predicate.  For example:+--   given predicate. ----- > split (whenElt (<0)) [2,4,-3,6,-9,1] == [[2,4],[-3],[6],[-9],[1]]+-- >>> split (whenElt (<0)) [2,4,-3,6,-9,1 :: Int]+-- [[2,4],[-3],[6],[-9],[1]] whenElt :: (a -> Bool) -> Splitter a-whenElt p = defaultSplitter { delimiter = Delimiter [p] }+whenElt p = defaultSplitter {delimiter = Delimiter [p]}  -- ** Strategy transformers  -- | Drop delimiters from the output (the default is to keep---   them). For example,+--   them). ----- > split (oneOf ":") "a:b:c" == ["a", ":", "b", ":", "c"]--- > split (dropDelims $ oneOf ":") "a:b:c" == ["a", "b", "c"]+-- >>> split (oneOf ":") "a:b:c"+-- ["a",":","b",":","c"]+--+-- >>> split (dropDelims $ oneOf ":") "a:b:c"+-- ["a","b","c"] dropDelims :: Splitter a -> Splitter a-dropDelims s = s { delimPolicy = Drop }+dropDelims s = s {delimPolicy = Drop}  -- | Keep delimiters in the output by prepending them to adjacent---   chunks.  For example:+--   chunks. ----- > split (keepDelimsL $ oneOf "xyz") "aazbxyzcxd" == ["aa","zb","x","y","zc","xd"]+-- >>> split (keepDelimsL $ oneOf "xyz") "aazbxyzcxd"+-- ["aa","zb","x","y","zc","xd"] keepDelimsL :: Splitter a -> Splitter a-keepDelimsL s = s { delimPolicy = KeepLeft }+keepDelimsL s = s {delimPolicy = KeepLeft}  -- | Keep delimiters in the output by appending them to adjacent---   chunks. For example:+--   chunks. ----- > split (keepDelimsR $ oneOf "xyz") "aazbxyzcxd" == ["aaz","bx","y","z","cx","d"]+-- >>> split (keepDelimsR $ oneOf "xyz") "aazbxyzcxd"+-- ["aaz","bx","y","z","cx","d"] keepDelimsR :: Splitter a -> Splitter a-keepDelimsR s = s { delimPolicy = KeepRight }+keepDelimsR s = s {delimPolicy = KeepRight} --- | Condense multiple consecutive delimiters into one.  For example:+-- | Condense multiple consecutive delimiters into one. ----- > split (condense $ oneOf "xyz") "aazbxyzcxd" == ["aa","z","b","xyz","c","x","d"]--- > split (dropDelims $ oneOf "xyz") "aazbxyzcxd" == ["aa","b","","","c","d"]--- > split (condense . dropDelims $ oneOf "xyz") "aazbxyzcxd" == ["aa","b","c","d"]+-- >>> split (condense $ oneOf "xyz") "aazbxyzcxd"+-- ["aa","z","b","xyz","c","x","d"]+--+-- >>> split (dropDelims $ oneOf "xyz") "aazbxyzcxd"+-- ["aa","b","","","c","d"]+--+-- >>> split (condense . dropDelims $ oneOf "xyz") "aazbxyzcxd"+-- ["aa","b","c","d"] condense :: Splitter a -> Splitter a-condense s = s { condensePolicy = Condense }+condense s = s {condensePolicy = Condense}  -- | Don't generate a blank chunk if there is a delimiter at the---   beginning.  For example:+--   beginning. ----- > split (oneOf ":") ":a:b" == ["",":","a",":","b"]--- > split (dropInitBlank $ oneOf ":") ":a:b" == [":","a",":","b"]+-- >>> split (oneOf ":") ":a:b"+-- ["",":","a",":","b"]+--+-- >>> split (dropInitBlank $ oneOf ":") ":a:b"+-- [":","a",":","b"] dropInitBlank :: Splitter a -> Splitter a-dropInitBlank s = s { initBlankPolicy = DropBlank }+dropInitBlank s = s {initBlankPolicy = DropBlank}  -- | Don't generate a blank chunk if there is a delimiter at the end.---   For example: ----- > split (oneOf ":") "a:b:" == ["a",":","b",":",""]--- > split (dropFinalBlank $ oneOf ":") "a:b:" == ["a",":","b",":"]+-- >>> split (oneOf ":") "a:b:"+-- ["a",":","b",":",""]+--+-- >>> split (dropFinalBlank $ oneOf ":") "a:b:"+-- ["a",":","b",":"] dropFinalBlank :: Splitter a -> Splitter a-dropFinalBlank s = s { finalBlankPolicy = DropBlank }+dropFinalBlank s = s {finalBlankPolicy = DropBlank}  -- | Don't generate blank chunks between consecutive delimiters.---   For example: ----- > split (oneOf ":") "::b:::a" == ["",":","",":","b",":","",":","",":","a"]--- > split (dropInnerBlanks $ oneOf ":") "::b:::a" == ["", ":",":","b",":",":",":","a"]+-- >>> split (oneOf ":") "::b:::a"+-- ["",":","",":","b",":","",":","",":","a"]+--+-- >>> split (dropInnerBlanks $ oneOf ":") "::b:::a"+-- ["",":",":","b",":",":",":","a"] dropInnerBlanks :: Splitter a -> Splitter a-dropInnerBlanks s = s { condensePolicy = DropBlankFields }+dropInnerBlanks s = s {condensePolicy = DropBlankFields}  -- ** Derived combinators  -- | Drop all blank chunks from the output, and condense consecutive --   delimiters into one.  Equivalent to @'dropInitBlank'---   . 'dropFinalBlank' . 'condense'@.  For example:+--   . 'dropFinalBlank' . 'condense'@. ----- > split (oneOf ":") "::b:::a" == ["",":","",":","b",":","",":","",":","a"]--- > split (dropBlanks $ oneOf ":") "::b:::a" == ["::","b",":::","a"]+-- >>> split (oneOf ":") "::b:::a"+-- ["",":","",":","b",":","",":","",":","a"]+--+-- >>> split (dropBlanks $ oneOf ":") "::b:::a"+-- ["::","b",":::","a"] dropBlanks :: Splitter a -> Splitter a dropBlanks = dropInitBlank . dropFinalBlank . condense  -- | Make a strategy that splits a list into chunks that all start --   with the given subsequence (except possibly the first). --   Equivalent to @'dropInitBlank' . 'keepDelimsL' . 'onSublist'@.---   For example: ----- > split (startsWith "app") "applyapplicativeapplaudapproachapple" == ["apply","applicative","applaud","approach","apple"]-startsWith :: Eq a => [a] -> Splitter a+-- >>> split (startsWith "app") "applyapplicativeapplaudapproachapple"+-- ["apply","applicative","applaud","approach","apple"]+startsWith :: (Eq a) => [a] -> Splitter a startsWith = dropInitBlank . keepDelimsL . onSublist  -- | Make a strategy that splits a list into chunks that all start --   with one of the given elements (except possibly the first).---   Equivalent to @'dropInitBlank' . 'keepDelimsL' . 'oneOf'@.  For+--   Equivalent to @'dropInitBlank' . 'keepDelimsL' . 'oneOf'@. --   example: ----- > split (startsWithOneOf ['A'..'Z']) "ACamelCaseIdentifier" == ["A","Camel","Case","Identifier"]-startsWithOneOf :: Eq a => [a] -> Splitter a+-- >>> split (startsWithOneOf ['A'..'Z']) "ACamelCaseIdentifier"+-- ["A","Camel","Case","Identifier"]+startsWithOneOf :: (Eq a) => [a] -> Splitter a startsWithOneOf = dropInitBlank . keepDelimsL . oneOf  -- | Make a strategy that splits a list into chunks that all end with --   the given subsequence, except possibly the last.  Equivalent to---   @'dropFinalBlank' . 'keepDelimsR' . 'onSublist'@.  For example:+--   @'dropFinalBlank' . 'keepDelimsR' . 'onSublist'@. ----- > split (endsWith "ly") "happilyslowlygnarlylily" == ["happily","slowly","gnarly","lily"]-endsWith :: Eq a => [a] -> Splitter a+-- >>> split (endsWith "ly") "happilyslowlygnarlylily"+-- ["happily","slowly","gnarly","lily"]+endsWith :: (Eq a) => [a] -> Splitter a endsWith = dropFinalBlank . keepDelimsR . onSublist  -- | Make a strategy that splits a list into chunks that all end with --   one of the given elements, except possibly the last.  Equivalent---   to @'dropFinalBlank' . 'keepDelimsR' . 'oneOf'@.  For example:+--   to @'dropFinalBlank' . 'keepDelimsR' . 'oneOf'@. ----- > split (condense $ endsWithOneOf ".,?! ") "Hi, there!  How are you?" == ["Hi, ","there!  ","How ","are ","you?"]-endsWithOneOf :: Eq a => [a] -> Splitter a+-- >>> split (condense $ endsWithOneOf ".,?! ") "Hi, there!  How are you?"+-- ["Hi, ","there!  ","How ","are ","you?"]+endsWithOneOf :: (Eq a) => [a] -> Splitter a endsWithOneOf = dropFinalBlank . keepDelimsR . oneOf  -- ** Convenience functions------ These functions implement some common splitting strategies.  Note--- that all of the functions in this section drop delimiters from--- the final output, since that is a more common use case even--- though it is not the default.  -- | Split on any of the given elements.  Equivalent to @'split'---   . 'dropDelims' . 'oneOf'@.  For example:+--   . 'dropDelims' . 'oneOf'@. ----- > splitOneOf ";.," "foo,bar;baz.glurk" == ["foo","bar","baz","glurk"]-splitOneOf :: Eq a => [a] -> [a] -> [[a]]+-- >>> splitOneOf ";.," "foo,bar;baz.glurk"+-- ["foo","bar","baz","glurk"]+splitOneOf :: (Eq a) => [a] -> [a] -> [[a]] splitOneOf = split . dropDelims . oneOf  -- | Split on the given sublist.  Equivalent to @'split'---   . 'dropDelims' . 'onSublist'@.  For example:+--   . 'dropDelims' . 'onSublist'@. ----- > splitOn ".." "a..b...c....d.." == ["a","b",".c","","d",""]+-- >>> splitOn ":" "12:35:07"+-- ["12","35","07"] --+-- >>> splitOn "x" "axbxc"+-- ["a","b","c"]+--+-- >>> splitOn "x" "axbxcx"+-- ["a","b","c",""]+--+-- >>> splitOn ".." "a..b...c....d.."+-- ["a","b",".c","","d",""]+-- --   In some parsing combinator frameworks this is also known as --   @sepBy@. -- --   Note that this is the right inverse of the 'Data.List.intercalate' function --   from "Data.List", that is, -----   > intercalate x . splitOn x === id+-- @+-- intercalate x . splitOn x === id+-- @ -- --   @'splitOn' x . 'Data.List.intercalate' x@ is the identity on --   certain lists, but it is tricky to state the precise conditions --   under which this holds.  (For example, it is not enough to say --   that @x@ does not occur in any elements of the input list. --   Working out why is left as an exercise for the reader.)-splitOn :: Eq a => [a] -> [a] -> [[a]]-splitOn   = split . dropDelims . onSublist+splitOn :: (Eq a) => [a] -> [a] -> [[a]]+splitOn = split . dropDelims . onSublist  -- | Split on elements satisfying the given predicate.  Equivalent to---   @'split' . 'dropDelims' . 'whenElt'@.  For example:+--   @'split' . 'dropDelims' . 'whenElt'@. ----- > splitWhen (<0) [1,3,-4,5,7,-9,0,2] == [[1,3],[5,7],[0,2]]+-- >>> splitWhen (<0) [1,3,-4,5,7,-9,0,2]+-- [[1,3],[5,7],[0,2]]+--+-- >>> splitWhen (<0) [1,-2,3,4,-5,-6,7,8,-9]+-- [[1],[3,4],[],[7,8],[]] splitWhen :: (a -> Bool) -> [a] -> [[a]] splitWhen = split . dropDelims . whenElt  {-# DEPRECATED sepBy "Use splitOn." #-}-sepBy :: Eq a => [a] -> [a] -> [[a]]+sepBy :: (Eq a) => [a] -> [a] -> [[a]] sepBy = splitOn  {-# DEPRECATED sepByOneOf "Use splitOneOf." #-}-sepByOneOf :: Eq a => [a] -> [a] -> [[a]]+sepByOneOf :: (Eq a) => [a] -> [a] -> [[a]] sepByOneOf = splitOneOf  -- | Split into chunks terminated by the given subsequence. --   Equivalent to @'split' . 'dropFinalBlank' . 'dropDelims'---   . 'onSublist'@.  For example:+--   . 'onSublist'@. ----- > endBy ";" "foo;bar;baz;" == ["foo","bar","baz"]+-- >>> endBy ".;" "foo.;bar.;baz.;"+-- ["foo","bar","baz"] -- --   Note also that the 'lines' function from "Data.List" is equivalent --   to @'endBy' \"\\n\"@.-endBy :: Eq a => [a] -> [a] -> [[a]]+endBy :: (Eq a) => [a] -> [a] -> [[a]] endBy = split . dropFinalBlank . dropDelims . onSublist  -- | Split into chunks terminated by one of the given elements. --   Equivalent to @'split' . 'dropFinalBlank' . 'dropDelims'---   . 'oneOf'@. For example:+--   . 'oneOf'@. ----- > endByOneOf ";," "foo;bar,baz;" == ["foo","bar","baz"]-endByOneOf :: Eq a => [a] -> [a] -> [[a]]+-- >>> endByOneOf ";," "foo;bar,baz;"+-- ["foo","bar","baz"]+endByOneOf :: (Eq a) => [a] -> [a] -> [[a]] endByOneOf = split . dropFinalBlank . dropDelims . oneOf  {-# DEPRECATED unintercalate "Use splitOn." #-}-unintercalate :: Eq a => [a] -> [a] -> [[a]]+unintercalate :: (Eq a) => [a] -> [a] -> [[a]] unintercalate = splitOn  -- | Split into \"words\", with word boundaries indicated by the given --   predicate.  Satisfies @'Data.List.words' === wordsBy --   'Data.Char.isSpace'@; equivalent to @'split' . 'dropBlanks'---   . 'dropDelims' . 'whenElt'@.  For example:+--   . 'dropDelims' . 'whenElt'@. ----- > wordsBy (=='x') "dogxxxcatxbirdxx" == ["dog","cat","bird"]+-- >>> wordsBy (`elem` ",;.?! ") "Hello there, world! How?"+-- ["Hello","there","world","How"]+--+-- >>> wordsBy (=='x') "dogxxxcatxbirdxx"+-- ["dog","cat","bird"] wordsBy :: (a -> Bool) -> [a] -> [[a]] wordsBy = split . dropBlanks . dropDelims . whenElt  -- | Split into \"lines\", with line boundaries indicated by the given --   predicate. Satisfies @'lines' === linesBy (=='\n')@; equivalent to---   @'split' . 'dropFinalBlank' . 'dropDelims' . 'whenElt'@.  For example:+--   @'split' . 'dropFinalBlank' . 'dropDelims' . 'whenElt'@. ----- > linesBy (=='x') "dogxxxcatxbirdxx" == ["dog","","","cat","bird",""]+-- >>> linesBy (==';') "foo;bar;;baz;"+-- ["foo","bar","","baz"]+--+-- >>> linesBy (=='x') "dogxxxcatxbirdxx"+-- ["dog","","","cat","bird",""] linesBy :: (a -> Bool) -> [a] -> [[a]] linesBy = split . dropFinalBlank . dropDelims . whenElt @@ -501,20 +568,29 @@ -- | @'chunksOf' n@ splits a list into length-n pieces.  The last --   piece will be shorter if @n@ does not evenly divide the length of --   the list.  If @n <= 0@, @'chunksOf' n l@ returns an infinite list---   of empty lists.  For example:+--   of empty lists. --+-- >>> chunksOf 3 [1..12]+-- [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]+--+-- >>> chunksOf 3 "Hello there"+-- ["Hel","lo ","the","re"]+--+-- >>> chunksOf 3 ([] :: [Int])+-- []+-- --   Note that @'chunksOf' n []@ is @[]@, not @[[]]@.  This is---   intentional, and is consistent with a recursive definition of---   'chunksOf'; it satisfies the property that+--   intentional, and satisfies the property that -- --   @chunksOf n xs ++ chunksOf n ys == chunksOf n (xs ++ ys)@ -- --   whenever @n@ evenly divides the length of @xs@. chunksOf :: Int -> [e] -> [[e]]-chunksOf i ls = map (take i) (build (splitter ls)) where+chunksOf i ls = map (take i) (build (splitter ls))+ where   splitter :: [e] -> ([e] -> a -> a) -> a -> a   splitter [] _ n = n-  splitter l c n  = l `c` splitter (drop i l) c n+  splitter l c n = l `c` splitter (drop i l) c n  {-# DEPRECATED chunk "Use chunksOf." #-} chunk :: Int -> [e] -> [[e]]@@ -524,24 +600,31 @@ splitEvery :: Int -> [e] -> [[e]] splitEvery = chunksOf --- | Split a list into chunks of the given lengths. For example:+-- | Split a list into chunks of the given lengths. ----- > splitPlaces [2,3,4] [1..20] == [[1,2],[3,4,5],[6,7,8,9]]--- > splitPlaces [4,9] [1..10] == [[1,2,3,4],[5,6,7,8,9,10]]--- > splitPlaces [4,9,3] [1..10] == [[1,2,3,4],[5,6,7,8,9,10]]+-- >>> splitPlaces [2,3,4] [1..20]+-- [[1,2],[3,4,5],[6,7,8,9]] --+-- >>> splitPlaces [4,9] [1..10]+-- [[1,2,3,4],[5,6,7,8,9,10]]+--+-- >>> splitPlaces [4,9,3] [1..10]+-- [[1,2,3,4],[5,6,7,8,9,10]]+-- --   If the input list is longer than the total of the given lengths, --   then the remaining elements are dropped. If the list is shorter --   than the total of the given lengths, then the result may contain --   fewer chunks than requested, and the last chunk may be shorter --   than requested.-splitPlaces :: Integral a => [a] -> [e] -> [[e]]-splitPlaces is ys = build (splitPlacer is ys) where-  splitPlacer :: Integral i => [i] -> [b] -> ([b] -> t -> t) -> t -> t-  splitPlacer [] _ _ n      = n-  splitPlacer _ [] _ n      = n-  splitPlacer (l:ls) xs c n = let (x1, x2) = genericSplitAt l xs-                              in  x1 `c` splitPlacer ls x2 c n+splitPlaces :: (Integral a) => [a] -> [e] -> [[e]]+splitPlaces is ys = build (splitPlacer is ys)+ where+  splitPlacer :: (Integral i) => [i] -> [b] -> ([b] -> t -> t) -> t -> t+  splitPlacer [] _ _ n = n+  splitPlacer _ [] _ n = n+  splitPlacer (l : ls) xs c n =+    let (x1, x2) = genericSplitAt l xs+     in x1 `c` splitPlacer ls x2 c n  -- | Split a list into chunks of the given lengths. Unlike --   'splitPlaces', the output list will always be the same length as@@ -549,20 +632,27 @@ --   total of the given lengths, then the remaining elements are --   dropped. If the list is shorter than the total of the given --   lengths, then the last several chunks will be shorter than---   requested or empty. For example:+--   requested or empty. ----- > splitPlacesBlanks [2,3,4] [1..20] == [[1,2],[3,4,5],[6,7,8,9]]--- > splitPlacesBlanks [4,9] [1..10] == [[1,2,3,4],[5,6,7,8,9,10]]--- > splitPlacesBlanks [4,9,3] [1..10] == [[1,2,3,4],[5,6,7,8,9,10],[]]+-- >>> splitPlacesBlanks [2,3,4] [1..20]+-- [[1,2],[3,4,5],[6,7,8,9]] --+-- >>> splitPlacesBlanks [4,9] [1..10]+-- [[1,2,3,4],[5,6,7,8,9,10]]+--+-- >>> splitPlacesBlanks [4,9,3] [1..10]+-- [[1,2,3,4],[5,6,7,8,9,10],[]]+-- --   Notice the empty list in the output of the third example, which --   differs from the behavior of 'splitPlaces'.-splitPlacesBlanks :: Integral a => [a] -> [e] -> [[e]]-splitPlacesBlanks is ys = build (splitPlacer is ys) where-  splitPlacer :: Integral i => [i] -> [b] -> ([b] -> t -> t) -> t -> t-  splitPlacer [] _ _ n      = n-  splitPlacer (l:ls) xs c n = let (x1, x2) = genericSplitAt l xs-                              in  x1 `c` splitPlacer ls x2 c n+splitPlacesBlanks :: (Integral a) => [a] -> [e] -> [[e]]+splitPlacesBlanks is ys = build (splitPlacer is ys)+ where+  splitPlacer :: (Integral i) => [i] -> [b] -> ([b] -> t -> t) -> t -> t+  splitPlacer [] _ _ n = n+  splitPlacer (l : ls) xs c n =+    let (x1, x2) = genericSplitAt l xs+     in x1 `c` splitPlacer ls x2 c n  -- | A useful recursion pattern for processing a list to produce a new --   list, often used for \"chopping\" up the input list.  Typically@@ -576,39 +666,41 @@ -- > group = chop (\ xs@(x:_) -> span (==x) xs) -- > -- > words :: String -> [String]--- > words = filter (not . null) . chop (span (not . isSpace) . dropWhile isSpace)-+-- > words = filter (not . null) . chop (break isSpace . dropWhile isSpace) chop :: ([a] -> (b, [a])) -> [a] -> [b] chop _ [] = [] chop f as = b : chop f as'-  where (b, as') = f as+ where+  (b, as') = f as  -- | Divides up an input list into a set of sublists, according to 'n' and 'm' --   input specifications you provide. Each sublist will have 'n' items, and the --   start of each sublist will be offset by 'm' items from the previous one. ----- > divvy 5 5 [1..20] == [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]]+-- >>> divvy 5 5 [1..15]+-- [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]] --+-- >>> divvy 5 2 [1..15]+-- [[1,2,3,4,5],[3,4,5,6,7],[5,6,7,8,9],[7,8,9,10,11],[9,10,11,12,13],[11,12,13,14,15]]+-- --   In the case where a source list's trailing elements do no fill an entire --   sublist, those trailing elements will be dropped. ----- > divvy 5 2 [1..10] == [[1,2,3,4,5],[3,4,5,6,7],[5,6,7,8,9]]+-- >>> divvy 5 2 [1..10]+-- [[1,2,3,4,5],[3,4,5,6,7],[5,6,7,8,9]] -- --   As an example, you can generate a moving average over a list of prices:--- +-- -- > type Prices = [Float] -- > type AveragePrices = [Float]--- > +-- > -- > average :: [Float] -> Float -- > average xs = sum xs / (fromIntegral $ length xs)--- > +-- > -- > simpleMovingAverage :: Prices -> AveragePrices--- > simpleMovingAverage priceList =--- >   map average divvyedPrices--- >     where divvyedPrices = divvy 20 1 priceList-+-- > simpleMovingAverage = map average . divvy 20 1 divvy :: Int -> Int -> [a] -> [[a]] divvy _ _ [] = []-divvy n m lst = filter (\ws -> (n == length ws)) choppedl-  where choppedl = chop (\xs -> (take n xs , drop m xs)) lst-+divvy n m lst = filter ((n ==) . length) choppedl+ where+  choppedl = chop (\xs -> (take n xs, drop m xs)) lst
test/Properties.hs view
@@ -1,23 +1,30 @@-{-# LANGUAGE FlexibleInstances  #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StandaloneDeriving #-}+ module Main where -import           Data.List.Split.Internals-import           Test.QuickCheck-import           Test.QuickCheck.Function+import Data.List.Split.Internals+import Test.QuickCheck+import Test.QuickCheck.Function -import           Control.Monad-import           System.Environment-import           Text.Printf+import Control.Monad+import System.Environment+import Text.Printf -import           Data.Char-import           Data.Functor-import           Data.List                 (genericTake, group, intercalate,-                                            isInfixOf, isPrefixOf, isSuffixOf,-                                            tails)-import           Data.Maybe                (isJust)+import Data.Char+import Data.Functor+import Data.List (+  genericTake,+  group,+  intercalate,+  isInfixOf,+  isPrefixOf,+  isSuffixOf,+  tails,+ )+import Data.Maybe (isJust) -newtype Elt = Elt { unElt :: Char }+newtype Elt = Elt {unElt :: Char}   deriving (Eq)  instance Show Elt where@@ -38,12 +45,14 @@   show (Delimiter ps) = show (map function ps)  instance (Arbitrary a, CoArbitrary a, Function a) => Arbitrary (Delimiter a) where-  arbitrary = (Delimiter . map apply) <$> arbitrary+  arbitrary = Delimiter . map apply <$> arbitrary -instance Arbitrary a => Arbitrary (Chunk a) where-  arbitrary = oneof [ liftM Text (listOf arbitrary)-                    , liftM Delim (listOf arbitrary)-                    ]+instance (Arbitrary a) => Arbitrary (Chunk a) where+  arbitrary =+    oneof+      [ Text <$> listOf arbitrary+      , Delim <$> listOf arbitrary+      ]  instance Arbitrary DelimPolicy where   arbitrary = elements [Drop, Keep, KeepLeft, KeepRight]@@ -64,96 +73,99 @@  main :: IO () main = do-    results <- mapM (\(s,t) -> printf "%-40s" s >> t) tests-    when (not . all isSuccess $ results) $ fail "Not all tests passed!"+  results <- mapM (\(s, t) -> printf "%-40s" s >> t) tests+  unless (all isSuccess results) $ fail "Not all tests passed!"  where-    isSuccess (Success{}) = True-    isSuccess _ = False-    qc x = quickCheckWithResult (stdArgs { maxSuccess = 200 }) x-    tests = [ ("default/id",                    qc prop_default_id)-            , ("match/decompose",               qc prop_match_decompose)-            , ("match/yields delim",            qc prop_match_yields_delim)-            , ("splitInternal/lossless",        qc prop_splitInternal_lossless)-            , ("splitInternal/yields delims",   qc prop_splitInternal_yields_delims)-            , ("splitInternal/text",            qc prop_splitInternal_text_not_delims)-            , ("doCondense/no consec delims",   qc prop_doCondense_no_consec_delims)-            , ("insBlanks/no consec delims",    qc prop_insBlanks_no_consec_delims)-            , ("insBlanks/fl not delims",       qc prop_insBlanks_fl_not_delim)-            , ("mergeL/no delims",              qc prop_mergeL_no_delims)-            , ("mergeR/no delims",              qc prop_mergeR_no_delims)-            , ("oneOf",                         qc prop_oneOf)-            , ("oneOf/not text",                qc prop_oneOf_not_text)-            , ("onSublist",                     qc prop_onSublist)-            , ("onSublist/not text",            qc prop_onSublist_not_text)-            , ("whenElt",                       qc prop_whenElt)-            , ("whenElt/not text",              qc prop_whenElt_not_text)-            , ("process/dropDelims",            qc prop_dropDelims)-            , ("process/keepDelimsL no delims", qc prop_keepDelimsL_no_delims)-            , ("process/keepDelimsR no delims", qc prop_keepDelimsR_no_delims)-            , ("process/keepDelimsL match",     qc prop_keepDelimsL_match)-            , ("process/keepDelimsR match",     qc prop_keepDelimsR_match)-            , ("condense/no consec delims",     qc prop_condense_no_consec_delims)-            , ("condense/all delims",           qc prop_condense_all_delims)-            , ("dropInitBlank",                 qc prop_dropInitBlank)-            , ("dropFinalBlank",                qc prop_dropFinalBlank)-            , ("dropBlanks",                    qc prop_dropBlanks)-            , ("startsWith",                    qc prop_startsWith)-            , ("startsWithOneOf",               qc prop_startsWithOneOf)-            , ("endsWith",                      qc prop_endsWith)-            , ("endsWithOneOf",                 qc prop_endsWithOneOf)-            , ("splitOn/right inv",             qc prop_splitOn_right_inv)-            , ("splitOn/idem",                  qc prop_splitOn_intercalate_idem)-            , ("splitOn/empty delim",           qc prop_splitOn_empty_delim)-            , ("split/empty delim",             qc prop_split_empty_delim_drop)-            , ("chunksOf/lengths",              qc prop_chunksOf_all_n)-            , ("chunksOf/last <= n",            qc prop_chunksOf_last_less_n)-            , ("chunksOf/preserve",             qc prop_chunksOf_preserve)-            , ("splitPlaces/lengths",           qc prop_splitPlaces_lengths)-            , ("splitPlaces/last <= n",         qc prop_splitPlaces_last_less_n)-            , ("splitPlaces/preserve",          qc prop_splitPlaces_preserve)-            , ("splitPlaces/chunksOf",          qc prop_splitPlaces_chunksOf)-            , ("splitPlacesB/length",           qc prop_splitPlacesB_length)-            , ("splitPlacesB/last <= n",        qc prop_splitPlacesB_last_less_n)-            , ("splitPlacesB/preserve",         qc prop_splitPlacesB_preserve)-            , ("lines",                         qc prop_lines)-            , ("wordsBy/words",                 qc prop_wordsBy_words)-            , ("linesBy/lines",                 qc prop_linesBy_lines)-            , ("chop/group",                    qc prop_chop_group)-            , ("chop/words",                    qc prop_chop_words)-            , ("divvy/evenly",                  qc prop_divvy_evenly)-            , ("divvy/discard_remainder",  qc prop_divvy_discard_remainder)-            , ("divvy/outputlists_allsame_length", qc prop_divvy_outputlists_allsame_length)-            , ("divvy/output_are_sublists", qc prop_divvy_output_are_sublists)-            , ("divvy/heads", qc prop_divvy_heads)-            ]+  isSuccess (Success {}) = True+  isSuccess _ = False+  qc x = quickCheckWithResult (stdArgs {maxSuccess = 200}) x+  tests =+    [ ("default/id", qc prop_default_id)+    , ("match/decompose", qc prop_match_decompose)+    , ("match/yields delim", qc prop_match_yields_delim)+    , ("splitInternal/lossless", qc prop_splitInternal_lossless)+    , ("splitInternal/yields delims", qc prop_splitInternal_yields_delims)+    , ("splitInternal/text", qc prop_splitInternal_text_not_delims)+    , ("doCondense/no consec delims", qc prop_doCondense_no_consec_delims)+    , ("insBlanks/no consec delims", qc prop_insBlanks_no_consec_delims)+    , ("insBlanks/fl not delims", qc prop_insBlanks_fl_not_delim)+    , ("mergeL/no delims", qc prop_mergeL_no_delims)+    , ("mergeR/no delims", qc prop_mergeR_no_delims)+    , ("oneOf", qc prop_oneOf)+    , ("oneOf/not text", qc prop_oneOf_not_text)+    , ("onSublist", qc prop_onSublist)+    , ("onSublist/not text", qc prop_onSublist_not_text)+    , ("whenElt", qc prop_whenElt)+    , ("whenElt/not text", qc prop_whenElt_not_text)+    , ("process/dropDelims", qc prop_dropDelims)+    , ("process/keepDelimsL no delims", qc prop_keepDelimsL_no_delims)+    , ("process/keepDelimsR no delims", qc prop_keepDelimsR_no_delims)+    , ("process/keepDelimsL match", qc prop_keepDelimsL_match)+    , ("process/keepDelimsR match", qc prop_keepDelimsR_match)+    , ("condense/no consec delims", qc prop_condense_no_consec_delims)+    , ("condense/all delims", qc prop_condense_all_delims)+    , ("dropInitBlank", qc prop_dropInitBlank)+    , ("dropFinalBlank", qc prop_dropFinalBlank)+    , ("dropBlanks", qc prop_dropBlanks)+    , ("startsWith", qc prop_startsWith)+    , ("startsWithOneOf", qc prop_startsWithOneOf)+    , ("endsWith", qc prop_endsWith)+    , ("endsWithOneOf", qc prop_endsWithOneOf)+    , ("splitOn/right inv", qc prop_splitOn_right_inv)+    , ("splitOn/idem", qc prop_splitOn_intercalate_idem)+    , ("splitOn/empty delim", qc prop_splitOn_empty_delim)+    , ("split/empty delim", qc prop_split_empty_delim_drop)+    , ("chunksOf/lengths", qc prop_chunksOf_all_n)+    , ("chunksOf/last <= n", qc prop_chunksOf_last_less_n)+    , ("chunksOf/preserve", qc prop_chunksOf_preserve)+    , ("splitPlaces/lengths", qc prop_splitPlaces_lengths)+    , ("splitPlaces/last <= n", qc prop_splitPlaces_last_less_n)+    , ("splitPlaces/preserve", qc prop_splitPlaces_preserve)+    , ("splitPlaces/chunksOf", qc prop_splitPlaces_chunksOf)+    , ("splitPlacesB/length", qc prop_splitPlacesB_length)+    , ("splitPlacesB/last <= n", qc prop_splitPlacesB_last_less_n)+    , ("splitPlacesB/preserve", qc prop_splitPlacesB_preserve)+    , ("lines", qc prop_lines)+    , ("wordsBy/words", qc prop_wordsBy_words)+    , ("linesBy/lines", qc prop_linesBy_lines)+    , ("chop/group", qc prop_chop_group)+    , ("chop/words", qc prop_chop_words)+    , ("divvy/evenly", qc prop_divvy_evenly)+    , ("divvy/discard_remainder", qc prop_divvy_discard_remainder)+    , ("divvy/outputlists_allsame_length", qc prop_divvy_outputlists_allsame_length)+    , ("divvy/output_are_sublists", qc prop_divvy_output_are_sublists)+    , ("divvy/heads", qc prop_divvy_heads)+    ]  prop_default_id :: [Elt] -> Bool prop_default_id l = split defaultSplitter l == [l]  prop_match_decompose :: Delim Elt -> [Elt] -> Bool-prop_match_decompose d l = maybe True ((==l) . uncurry (++)) $ matchDelim (unDelim d) l+prop_match_decompose d l = maybe True ((== l) . uncurry (++)) $ matchDelim (unDelim d) l  isDelimMatch :: Delim Elt -> [Elt] -> Bool-isDelimMatch d l = matchDelim (unDelim d) l == Just (l,[])+isDelimMatch d l = matchDelim (unDelim d) l == Just (l, [])  prop_match_yields_delim :: Delim Elt -> [Elt] -> Bool prop_match_yields_delim d l =-    case matchDelim (unDelim d) l of-      Nothing -> True-      Just (del,rest) -> isDelimMatch d del+  case matchDelim (unDelim d) l of+    Nothing -> True+    Just (del, rest) -> isDelimMatch d del  prop_splitInternal_lossless :: Delim Elt -> [Elt] -> Bool prop_splitInternal_lossless d l = concatMap fromElem (splitInternal (unDelim d) l) == l  prop_splitInternal_yields_delims :: Delim Elt -> [Elt] -> Bool prop_splitInternal_yields_delims d l =-    all (isDelimMatch d) $ [ del | (Delim del) <- splitInternal d' l ]-  where d' = unDelim d+  all (isDelimMatch d) $ [del | (Delim del) <- splitInternal d' l]+ where+  d' = unDelim d  prop_splitInternal_text_not_delims :: Delim Elt -> [Elt] -> Bool prop_splitInternal_text_not_delims d l =-    all (not . isDelimMatch d) $ [ ch | (Text ch) <- splitInternal d' l ]-  where d' = unDelim d+  not (any (isDelimMatch d) ([ch | (Text ch) <- splitInternal d' l]))+ where+  d' = unDelim d  noConsecDelims :: SplitList Elt -> Bool noConsecDelims [] = True@@ -169,87 +181,97 @@  prop_insBlanks_fl_not_delim :: SplitList Elt -> Bool prop_insBlanks_fl_not_delim l =-    case insertBlanks Condense l of-      [] -> True-      xs -> (not . isDelim $ head xs) && (not . isDelim $ last xs)+  case insertBlanks Condense l of+    [] -> True+    xs -> (not . isDelim $ head xs) && (not . isDelim $ last xs)  prop_mergeL_no_delims :: SplitList Elt -> Bool-prop_mergeL_no_delims = all (not . isDelim) . mergeLeft . insertBlanks Condense+prop_mergeL_no_delims = not . any isDelim . mergeLeft . insertBlanks Condense  prop_mergeR_no_delims :: SplitList Elt -> Bool-prop_mergeR_no_delims = all (not . isDelim) . mergeRight . insertBlanks Condense+prop_mergeR_no_delims = not . any isDelim . mergeRight . insertBlanks Condense  getDelims :: Splitter Elt -> [Elt] -> [[Elt]]-getDelims s l = [ d | Delim d <- splitInternal (delimiter s) l ]+getDelims s l = [d | Delim d <- splitInternal (delimiter s) l]  getTexts :: Splitter Elt -> [Elt] -> [[Elt]]-getTexts s l = [ c | Text c <- splitInternal (delimiter s) l ]+getTexts s l = [c | Text c <- splitInternal (delimiter s) l]  prop_oneOf :: [Elt] -> [Elt] -> Bool-prop_oneOf elts l = all ((==1) . length) ds && all ((`elem` elts) . head) ds-  where ds = getDelims (oneOf elts) l+prop_oneOf elts l = all ((== 1) . length) ds && all ((`elem` elts) . head) ds+ where+  ds = getDelims (oneOf elts) l  prop_oneOf_not_text :: [Elt] -> [Elt] -> Bool-prop_oneOf_not_text elts l = all (not . (`elem` elts)) (concat cs)-  where cs = getTexts (oneOf elts) l+prop_oneOf_not_text elts l = not (any (`elem` elts) (concat cs))+ where+  cs = getTexts (oneOf elts) l  prop_onSublist :: [Elt] -> [Elt] -> Bool-prop_onSublist sub l = all (==sub) $ getDelims (onSublist sub) l+prop_onSublist sub l = all (== sub) $ getDelims (onSublist sub) l  prop_onSublist_not_text :: [Elt] -> [Elt] -> Property prop_onSublist_not_text sub l =-    (not . null $ sub) ==>-      all (not . isInfixOf sub) $ getTexts (onSublist sub) l+  (not . null $ sub)+    ==> not (any (isInfixOf sub) $ getTexts (onSublist sub) l) -prop_whenElt :: (Fun Elt Bool) -> [Elt] -> Bool-prop_whenElt (Fun _ p) l = all ((==1) . length) ds && all (p . head) ds-  where ds = getDelims (whenElt p) l+prop_whenElt :: Fun Elt Bool -> [Elt] -> Bool+prop_whenElt (Fun _ p) l = all ((== 1) . length) ds && all (p . head) ds+ where+  ds = getDelims (whenElt p) l -prop_whenElt_not_text :: (Fun Elt Bool) -> [Elt] -> Bool-prop_whenElt_not_text (Fun _ p) l = all (not . p) (concat cs)-  where cs = getTexts (whenElt p) l+prop_whenElt_not_text :: Fun Elt Bool -> [Elt] -> Bool+prop_whenElt_not_text (Fun _ p) l = not (any p (concat cs))+ where+  cs = getTexts (whenElt p) l  process :: Splitter Elt -> [Elt] -> SplitList Elt process s = postProcess s . splitInternal (delimiter s)  prop_dropDelims :: Splitter Elt -> [Elt] -> Bool-prop_dropDelims s l = all (not . isDelim) (process (dropDelims s) l)+prop_dropDelims s l = not (any isDelim (process (dropDelims s) l))  prop_keepDelimsL_no_delims :: Splitter Elt -> [Elt] -> Bool-prop_keepDelimsL_no_delims s l = all (not . isDelim) (process (keepDelimsL s) l)+prop_keepDelimsL_no_delims s l = not (any isDelim (process (keepDelimsL s) l))  prop_keepDelimsL_match :: Splitter Elt -> NonEmptyList Elt -> Bool prop_keepDelimsL_match s (NonEmpty l) =-  all (isJust . matchDelim (delimiter s)) [ c | Text c <- tail p ]-    where p = process (keepDelimsL s) l+  all (isJust . matchDelim (delimiter s)) [c | Text c <- tail p]+ where+  p = process (keepDelimsL s) l  prop_keepDelimsR_no_delims :: Splitter Elt -> [Elt] -> Bool-prop_keepDelimsR_no_delims s l = all (not . isDelim) (process (keepDelimsR s) l)+prop_keepDelimsR_no_delims s l = not (any isDelim (process (keepDelimsR s) l))  prop_keepDelimsR_match :: Splitter Elt -> NonEmptyList Elt -> Bool prop_keepDelimsR_match s (NonEmpty l) =-  all (any (isJust . matchDelim (delimiter s)) . tails)-    [ c | Text c <- init p ]-      where p = process (keepDelimsR s) l+  all+    (any (isJust . matchDelim (delimiter s)) . tails)+    [c | Text c <- init p]+ where+  p = process (keepDelimsR s) l  prop_condense_no_consec_delims :: Splitter Elt -> [Elt] -> Bool prop_condense_no_consec_delims s l = noConsecDelims $ process (condense s) l  prop_condense_all_delims :: Splitter Elt -> [Elt] -> Bool prop_condense_all_delims s l = all allDelims p-  where p = [ d | Delim d <- process (condense s) l ]-        allDelims t = all isDelim (splitInternal (delimiter s) t)+ where+  p = [d | Delim d <- process (condense s) l]+  allDelims t = all isDelim (splitInternal (delimiter s) t)  prop_dropInitBlank :: Splitter Elt -> NonEmptyList Elt -> Bool prop_dropInitBlank s (NonEmpty l) = head p /= Text []-  where p = process (dropInitBlank $ s { delimPolicy = Keep } ) l+ where+  p = process (dropInitBlank $ s {delimPolicy = Keep}) l  prop_dropFinalBlank :: Splitter Elt -> NonEmptyList Elt -> Bool prop_dropFinalBlank s (NonEmpty l) = last p /= Text []-  where p = process (dropFinalBlank $ s { delimPolicy = Keep } ) l+ where+  p = process (dropFinalBlank $ s {delimPolicy = Keep}) l  prop_dropBlanks :: Splitter Elt -> [Elt] -> Bool-prop_dropBlanks s = null . filter (== (Text [])) . process (dropBlanks s)+prop_dropBlanks s = notElem (Text []) . process (dropBlanks s)  prop_startsWith :: [Elt] -> NonEmptyList Elt -> Bool prop_startsWith s (NonEmpty l) = all (s `isPrefixOf`) (tail $ split (startsWith s) l)@@ -273,7 +295,6 @@    so it's not enough just to say that the delimiter is not an infix of    any elements of l! - prop_splitOn_left_inv :: [Elt] -> NonEmptyList [Elt] -> Property prop_splitOn_left_inv x (NonEmpty ls) = not (any (x `isInfixOf`) ls) ==>                                         splitOn x (intercalate x ls) == ls@@ -283,52 +304,59 @@ -- prop_splitOn_right_inv, but we keep it here just for kicks. prop_splitOn_intercalate_idem :: [Elt] -> [[Elt]] -> Bool prop_splitOn_intercalate_idem x ls = f (f ls) == f ls-  where f = splitOn x . intercalate x+ where+  f = splitOn x . intercalate x  prop_splitOn_empty_delim :: [Elt] -> Bool-prop_splitOn_empty_delim ls = splitOn [] ls == [] : map (:[]) ls+prop_splitOn_empty_delim ls = splitOn [] ls == [] : map (: []) ls  prop_split_empty_delim_drop :: [Elt] -> Bool-prop_split_empty_delim_drop ls-  = split (dropDelims . dropBlanks $ onSublist []) ls == map (:[]) ls+prop_split_empty_delim_drop ls =+  split (dropDelims . dropBlanks $ onSublist []) ls == map (: []) ls  prop_chunksOf_all_n :: Positive Int -> NonEmptyList Elt -> Bool-prop_chunksOf_all_n (Positive n) (NonEmpty l) = all ((==n) . length) (init $ chunksOf n l)+prop_chunksOf_all_n (Positive n) (NonEmpty l) = all ((== n) . length) (init $ chunksOf n l)  prop_chunksOf_last_less_n :: Positive Int -> NonEmptyList Elt -> Bool-prop_chunksOf_last_less_n (Positive n) (NonEmpty l) = (<=n) . length . last $ chunksOf n l+prop_chunksOf_last_less_n (Positive n) (NonEmpty l) = (<= n) . length . last $ chunksOf n l  prop_chunksOf_preserve :: Positive Int -> [Elt] -> Bool prop_chunksOf_preserve (Positive n) l = concat (chunksOf n l) == l  prop_splitPlaces_lengths :: [NonNegative Int] -> [Elt] -> Bool prop_splitPlaces_lengths ps = and . mInit . zipWith (==) ps' . map length . splitPlaces ps'-  where ps' = map unNN ps+ where+  ps' = map unNN ps  prop_splitPlaces_last_less_n :: NonEmptyList (NonNegative Int) -> NonEmptyList Elt -> Bool-prop_splitPlaces_last_less_n (NonEmpty ps) (NonEmpty l) = (head $ drop (length l' - 1) ps') >= length (last l')-  where l' = splitPlaces ps' l-        ps' = map unNN ps+prop_splitPlaces_last_less_n (NonEmpty ps) (NonEmpty l) = (ps' !! max 0 (length l' - 1)) >= length (last l')+ where+  l' = splitPlaces ps' l+  ps' = map unNN ps  prop_splitPlaces_preserve :: [NonNegative Integer] -> [Elt] -> Bool prop_splitPlaces_preserve ps l = concat (splitPlaces ps' l) == genericTake (sum ps') l-  where ps' = map unNN ps+ where+  ps' = map unNN ps  prop_splitPlaces_chunksOf :: Positive Int -> [Elt] -> Bool prop_splitPlaces_chunksOf (Positive n) l = splitPlaces (repeat n) l == chunksOf n l  prop_splitPlacesB_length :: [NonNegative Int] -> [Elt] -> Bool prop_splitPlacesB_length ps xs = length ps' == length (splitPlacesBlanks ps' xs)-  where ps' = map unNN ps+ where+  ps' = map unNN ps  prop_splitPlacesB_last_less_n :: NonEmptyList (NonNegative Int) -> NonEmptyList Elt -> Bool-prop_splitPlacesB_last_less_n (NonEmpty ps) (NonEmpty l) = (head $ drop (length l' - 1) ps') >= length (last l')-  where l' = splitPlacesBlanks ps' l-        ps' = map unNN ps+prop_splitPlacesB_last_less_n (NonEmpty ps) (NonEmpty l) = (ps' !! max 0 (length l' - 1)) >= length (last l')+ where+  l' = splitPlacesBlanks ps' l+  ps' = map unNN ps  prop_splitPlacesB_preserve :: [NonNegative Integer] -> [Elt] -> Bool prop_splitPlacesB_preserve ps l = concat (splitPlacesBlanks ps' l) == genericTake (sum ps') l-  where ps' = map unNN ps+ where+  ps' = map unNN ps  unNN :: NonNegative a -> a unNN (NonNegative x) = x@@ -336,9 +364,9 @@ mInit :: [a] -> [a] mInit [] = [] mInit [x] = []-mInit (x:xs) = x : init xs+mInit (x : xs) = x : init xs -newtype EltWS = EltWS { unEltWS :: Char }+newtype EltWS = EltWS {unEltWS :: Char}   deriving (Eq, Show)  instance Arbitrary EltWS where@@ -346,31 +374,35 @@  prop_lines :: [EltWS] -> Bool prop_lines s = lines s' == endBy "\n" s'-  where s' = map unEltWS s+ where+  s' = map unEltWS s  prop_wordsBy_words :: [EltWS] -> Bool prop_wordsBy_words s = words s' == wordsBy isSpace s'-  where s' = map unEltWS s+ where+  s' = map unEltWS s  prop_linesBy_lines :: [EltWS] -> Bool-prop_linesBy_lines s = lines s' == linesBy (=='\n') s'-  where s' = map unEltWS s+prop_linesBy_lines s = lines s' == linesBy (== '\n') s'+ where+  s' = map unEltWS s  prop_chop_group :: [Elt] -> Bool-prop_chop_group s = chop (\xs@(x:_) -> span (==x) xs) s == group s+prop_chop_group s = chop (\xs@(x : _) -> span (== x) xs) s == group s  prop_chop_words :: [EltWS] -> Bool-prop_chop_words s = words s' == (filter (not . null) . chop (span (not . isSpace) . dropWhile isSpace) $ s')-  where s' = map unEltWS s+prop_chop_words s = words s' == (filter (not . null) . chop (break isSpace . dropWhile isSpace) $ s')+ where+  s' = map unEltWS s  prop_divvy_evenly :: [Elt] -> Positive Int -> Bool prop_divvy_evenly elems (Positive n) = concat (divvy n n elems') == elems'-  where-    -- Chop off the smallest possible tail of elems to make the length-    -- evenly divisible by n.  This property used to have a-    -- precondition (length elements `mod` n == 0), but that led to too-    -- many discarded test cases and occasional test suite failures.-    elems' = take ((length elems `div` n) * n) elems+ where+  -- Chop off the smallest possible tail of elems to make the length+  -- evenly divisible by n.  This property used to have a+  -- precondition (length elements `mod` n == 0), but that led to too+  -- many discarded test cases and occasional test suite failures.+  elems' = take ((length elems `div` n) * n) elems  prop_divvy_discard_remainder :: [Elt] -> Positive Int -> Bool prop_divvy_discard_remainder elems (Positive n) =@@ -378,27 +410,28 @@  prop_divvy_outputlists_allsame_length :: [Elt] -> Positive Int -> Positive Int -> Bool prop_divvy_outputlists_allsame_length elems (Positive n) (Positive m) = allSame xs-  where-    allSame :: [Int] -> Bool-    allSame [] = True-    allSame zs = and $ map (== head zs) (tail zs)-    xs = map length (divvy n m elems)+ where+  allSame :: [Int] -> Bool+  allSame [] = True+  allSame zs = all (== head zs) (tail zs)+  xs = map length (divvy n m elems)  prop_divvy_output_are_sublists :: [Elt] -> Positive Int -> Positive Int -> Bool-prop_divvy_output_are_sublists elems (Positive n) (Positive m) = and $ map (\x -> isInfixOf x elems) xs-  where xs = divvy n m elems+prop_divvy_output_are_sublists elems (Positive n) (Positive m) = all (`isInfixOf` elems) xs+ where+  xs = divvy n m elems  takeEvery :: Int -> [a] -> [a] takeEvery _ [] = []-takeEvery n lst = (map head . chunksOf n) $ lst+takeEvery n lst = (map head . chunksOf n) lst  initNth :: Int -> [a] -> [a] initNth _ [] = []-initNth n lst = (reverse . drop n . reverse) $ lst+initNth n lst = (reverse . drop n . reverse) lst  prop_divvy_heads :: [Elt] -> Positive Int -> Positive Int -> Bool prop_divvy_heads [] _ _ = True prop_divvy_heads elems (Positive n) (Positive m) = hds1 == hds2-  where hds1 = takeEvery m (initNth (n - 1) elems)-        hds2 = map head $ divvy n m elems-+ where+  hds1 = takeEvery m (initNth (n - 1) elems)+  hds2 = map head $ divvy n m elems