packages feed

mono-traversable 0.9.2.1 → 0.9.3

raw patch · 5 files changed

+175/−6 lines, 5 filesdep +splitPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: split

API changes (from Hackage documentation)

+ Data.Sequences: defaultIntercalate :: IsSequence seq => seq -> [seq] -> seq
+ Data.Sequences: defaultSplitOn :: EqSequence s => s -> s -> [s]
+ Data.Sequences: defaultSplitWhen :: IsSequence seq => (Element seq -> Bool) -> seq -> [seq]
+ Data.Sequences: intercalate :: IsSequence seq => seq -> [seq] -> seq
+ Data.Sequences: splitElem :: EqSequence seq => Element seq -> seq -> [seq]
+ Data.Sequences: splitSeq :: EqSequence seq => seq -> seq -> [seq]
+ Data.Sequences: splitWhen :: IsSequence seq => (Element seq -> Bool) -> seq -> [seq]
- Data.Sequences: class (MonoFoldableEq seq, IsSequence seq, Eq (Element seq)) => EqSequence seq where stripPrefix x y = fmap fromList (otoList x `stripPrefix` otoList y) stripSuffix x y = fmap fromList (otoList x `stripSuffix` otoList y) isPrefixOf x y = otoList x `isPrefixOf` otoList y isSuffixOf x y = otoList x `isSuffixOf` otoList y isInfixOf x y = otoList x `isInfixOf` otoList y group = groupBy (==) groupAll = groupAllOn id
+ Data.Sequences: class (MonoFoldableEq seq, IsSequence seq, Eq (Element seq)) => EqSequence seq where splitElem x = splitWhen (== x) splitSeq = defaultSplitOn stripPrefix x y = fmap fromList (otoList x `stripPrefix` otoList y) stripSuffix x y = fmap fromList (otoList x `stripSuffix` otoList y) isPrefixOf x y = otoList x `isPrefixOf` otoList y isSuffixOf x y = otoList x `isSuffixOf` otoList y isInfixOf x y = otoList x `isInfixOf` otoList y group = groupBy (==) groupAll = groupAllOn id
- Data.Sequences: class (Monoid seq, MonoTraversable seq, SemiSequence seq, MonoPointed seq) => IsSequence seq where fromList = mconcat . fmap singleton break f = (fromList *** fromList) . break f . otoList span f = (fromList *** fromList) . span f . otoList dropWhile f = fromList . dropWhile f . otoList takeWhile f = fromList . takeWhile f . otoList splitAt i = (fromList *** fromList) . genericSplitAt i . otoList unsafeSplitAt i seq = (unsafeTake i seq, unsafeDrop i seq) take i = fst . splitAt i unsafeTake = take drop i = snd . splitAt i unsafeDrop = drop partition f = (fromList *** fromList) . partition f . otoList uncons = fmap (second fromList) . uncons . otoList unsnoc = fmap (first fromList) . unsnoc . otoList filter f = fromList . filter f . otoList filterM f = liftM fromList . filterM f . otoList replicate i = fromList . genericReplicate i replicateM i = liftM fromList . replicateM (fromIntegral i) groupBy f = fmap fromList . groupBy f . otoList groupAllOn f = fmap fromList . groupAllOn f . otoList subsequences = map fromList . subsequences . otoList permutations = map fromList . permutations . otoList tailEx = snd . maybe (error "Data.Sequences.tailEx") id . uncons initEx = fst . maybe (error "Data.Sequences.initEx") id . unsnoc unsafeTail = tailEx unsafeInit = initEx index seq' idx = headMay (drop idx seq') indexEx seq' idx = maybe (error "Data.Sequences.indexEx") id (index seq' idx) unsafeIndex = indexEx
+ Data.Sequences: class (Monoid seq, MonoTraversable seq, SemiSequence seq, MonoPointed seq) => IsSequence seq where fromList = mconcat . fmap singleton break f = (fromList *** fromList) . break f . otoList span f = (fromList *** fromList) . span f . otoList dropWhile f = fromList . dropWhile f . otoList takeWhile f = fromList . takeWhile f . otoList splitAt i = (fromList *** fromList) . genericSplitAt i . otoList unsafeSplitAt i seq = (unsafeTake i seq, unsafeDrop i seq) take i = fst . splitAt i unsafeTake = take drop i = snd . splitAt i unsafeDrop = drop partition f = (fromList *** fromList) . partition f . otoList uncons = fmap (second fromList) . uncons . otoList unsnoc = fmap (first fromList) . unsnoc . otoList filter f = fromList . filter f . otoList filterM f = liftM fromList . filterM f . otoList replicate i = fromList . genericReplicate i replicateM i = liftM fromList . replicateM (fromIntegral i) groupBy f = fmap fromList . groupBy f . otoList groupAllOn f = fmap fromList . groupAllOn f . otoList subsequences = map fromList . subsequences . otoList permutations = map fromList . permutations . otoList tailEx = snd . maybe (error "Data.Sequences.tailEx") id . uncons initEx = fst . maybe (error "Data.Sequences.initEx") id . unsnoc unsafeTail = tailEx unsafeInit = initEx index seq' idx = headMay (drop idx seq') indexEx seq' idx = maybe (error "Data.Sequences.indexEx") id (index seq' idx) unsafeIndex = indexEx intercalate = defaultIntercalate splitWhen = defaultSplitWhen

Files

ChangeLog.md view
@@ -1,3 +1,7 @@+## 0.9.3++* Added `intercalate`, `splitWhen`, `splitElem`, and `splitSeq` [#80](https://github.com/snoyberg/mono-traversable/pull/80)+ ## 0.9.2.1  * Tweak test suite for 32-bit systems [#78](https://github.com/snoyberg/mono-traversable/issues/78)
mono-traversable.cabal view
@@ -1,5 +1,5 @@ name:                mono-traversable-version:             0.9.2.1+version:             0.9.3 synopsis:            Type classes for mapping, folding, and traversing monomorphic containers description:         Monomorphic variants of the Functor, Foldable, and Traversable typeclasses. If you understand Haskell's basic typeclasses, you understand mono-traversable. In addition to what you are used to, it adds on an IsSequence typeclass and has code for marking data structures as non-empty. homepage:            https://github.com/snoyberg/mono-traversable@@ -37,6 +37,7 @@                      , vector-algorithms >= 0.6                      , dlist >= 0.6 && < 1.0                      , dlist-instances == 0.1.*+                     , split >= 0.2   hs-source-dirs:      src   default-language:    Haskell2010 
src/Data/MonoTraversable.hs view
@@ -599,7 +599,6 @@     unsafeLast = V.unsafeLast     maximumByEx = V.maximumBy     minimumByEx = V.minimumBy-    {-# INLINE ofoldMap #-}     {-# INLINE ofoldr #-}     {-# INLINE ofoldl' #-}     {-# INLINE otoList #-}
src/Data/Sequences.hs view
@@ -7,10 +7,11 @@ module Data.Sequences where  import Data.Maybe (fromJust, isJust)-import Data.Monoid (Monoid, mconcat, mempty)+import Data.Monoid (Monoid, mappend, mconcat, mempty) import Data.MonoTraversable import Data.Int (Int64, Int) import qualified Data.List as List+import qualified Data.List.Split as List import qualified Control.Monad (filterM, replicateM) import Prelude (Bool (..), Monad (..), Maybe (..), Ordering (..), Ord (..), Eq (..), Functor (..), fromIntegral, otherwise, (-), fst, snd, Integral, ($), flip, maybe, error) import Data.Char (Char, isSpace)@@ -60,8 +61,6 @@     -- @     intersperse :: Element seq -> seq -> seq -    -- FIXME split :: (Element seq -> Bool) -> seq -> [seq]-     -- | Reverse a sequence     --     -- @@@ -411,6 +410,23 @@     unsafeIndex :: seq -> Index seq -> Element seq     unsafeIndex = indexEx +    -- | 'intercalate' @seq seqs@ inserts @seq@ in between @seqs@ and+    -- concatenates the result.+    --+    -- Since 0.9.3+    intercalate :: seq -> [seq] -> seq+    intercalate = defaultIntercalate++    -- | 'splitWhen' splits a sequence into components delimited by separators,+    -- where the predicate returns True for a separator element. The resulting+    -- components do not contain the separators. Two adjacent separators result+    -- in an empty component in the output. The number of resulting components+    -- is greater by one than number of separators.+    --+    -- Since 0.9.3+    splitWhen :: (Element seq -> Bool) -> seq -> [seq]+    splitWhen = defaultSplitWhen+     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -440,6 +456,7 @@     {-# INLINE index #-}     {-# INLINE indexEx #-}     {-# INLINE unsafeIndex #-}+    {-# INLINE splitWhen #-}  -- | Use "Data.List"'s implementation of 'Data.List.find'. defaultFind :: MonoFoldable seq => (Element seq -> Bool) -> seq -> Maybe (Element seq)@@ -461,6 +478,17 @@ defaultSortBy f = fromList . sortBy f . otoList {-# INLINE defaultSortBy #-} +-- | Default 'intercalate'+defaultIntercalate :: (IsSequence seq) => seq -> [seq] -> seq+defaultIntercalate _ [] = mempty+defaultIntercalate s (seq:seqs) = mconcat (seq : List.map (s `mappend`) seqs)+{-# INLINE defaultIntercalate #-}++-- | Use 'splitWhen' from "Data.List.Split"+defaultSplitWhen :: IsSequence seq => (Element seq -> Bool) -> seq -> [seq]+defaultSplitWhen f = List.map fromList . List.splitWhen f . otoList+{-# INLINE defaultSplitWhen #-}+ -- | Sort a vector using an supplied element ordering function. vectorSortBy :: VG.Vector v e => (e -> e -> Ordering) -> v e -> v e vectorSortBy f = VG.modify (VAM.sortBy f)@@ -538,6 +566,8 @@       where         (matches, nonMatches) = partition ((== f head) . f) tail     groupAllOn _ [] = []+    intercalate = List.intercalate+    splitWhen = List.splitWhen     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -564,6 +594,8 @@     {-# INLINE initEx #-}     {-# INLINE unsafeTail #-}     {-# INLINE unsafeInit #-}+    {-# INLINE intercalate #-}+    {-# INLINE splitWhen #-}  instance SemiSequence (NE.NonEmpty a) where     type Index (NE.NonEmpty a) = Int@@ -618,6 +650,9 @@     tailEx = S.tail     initEx = S.init     unsafeTail = SU.unsafeTail+    splitWhen f s | S.null s = [S.empty]+                  | otherwise = S.splitWith f s+    intercalate = S.intercalate     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -644,6 +679,8 @@     {-# INLINE initEx #-}     {-# INLINE unsafeTail #-}     {-# INLINE unsafeInit #-}+    {-# INLINE splitWhen #-}+    {-# INLINE intercalate #-}      index bs i         | i >= S.length bs = Nothing@@ -688,6 +725,8 @@     groupBy = T.groupBy     tailEx = T.tail     initEx = T.init+    splitWhen = T.split+    intercalate = T.intercalate     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -714,6 +753,8 @@     {-# INLINE initEx #-}     {-# INLINE unsafeTail #-}     {-# INLINE unsafeInit #-}+    {-# INLINE splitWhen #-}+    {-# INLINE intercalate #-}      index t i         | i >= T.length t = Nothing@@ -758,6 +799,9 @@     groupBy = L.groupBy     tailEx = L.tail     initEx = L.init+    splitWhen f s | L.null s = [L.empty]+                  | otherwise = L.splitWith f s+    intercalate = L.intercalate     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -784,6 +828,8 @@     {-# INLINE initEx #-}     {-# INLINE unsafeTail #-}     {-# INLINE unsafeInit #-}+    {-# INLINE splitWhen #-}+    {-# INLINE intercalate #-}      indexEx = L.index     unsafeIndex = L.index@@ -825,6 +871,8 @@     groupBy = TL.groupBy     tailEx = TL.tail     initEx = TL.init+    splitWhen = TL.split+    intercalate = TL.intercalate     {-# INLINE fromList #-}     {-# INLINE break #-}     {-# INLINE span #-}@@ -851,6 +899,8 @@     {-# INLINE initEx #-}     {-# INLINE unsafeTail #-}     {-# INLINE unsafeInit #-}+    {-# INLINE splitWhen #-}+    {-# INLINE intercalate #-}      indexEx = TL.index     unsafeIndex = TL.index@@ -1198,6 +1248,42 @@  -- | A typeclass for sequences whose elements have the 'Eq' typeclass class (MonoFoldableEq seq, IsSequence seq, Eq (Element seq)) => EqSequence seq where++    -- | @'splitElem'@ splits a sequence into components delimited by separator+    -- element. It's equivalent to 'splitWhen' with equality predicate:+    --+    -- > splitElem sep === splitWhen (== sep)+    --+    -- Since 0.9.3+    splitElem :: Element seq -> seq -> [seq]+    splitElem x = splitWhen (== x)++    -- | @'splitSeq'@ splits a sequence into components delimited by+    -- separator subsequence. 'splitSeq' is the right inverse of 'intercalate':+    --+    -- > intercalate x . splitSeq x === id+    --+    -- 'splitElem' can be considered a special case of 'splitSeq'+    --+    -- > splitSeq (singleton sep) === splitElem sep+    --+    -- @'splitSeq' mempty@ is another special case: it splits just before each+    -- element, and in line with 'splitWhen' rules, it has at least one output+    -- component:+    --+    -- @+    -- > 'splitSeq' "" ""+    -- [""]+    -- > 'splitSeq' "" "a"+    -- ["", "a"]+    -- > 'splitSeq' "" "ab"+    -- ["", "a", "b"]+    -- @+    --+    -- Since 0.9.3+    splitSeq :: seq -> seq -> [seq]+    splitSeq = defaultSplitOn+     -- | 'stripPrefix' drops the given prefix from a sequence.     -- It returns 'Nothing' if the sequence did not start with the prefix     -- given, or 'Just' the sequence after the prefix, if it does.@@ -1249,6 +1335,8 @@     -- Equivalent to @'groupAllOn' id@     groupAll :: seq -> [seq]     groupAll = groupAllOn id+    {-# INLINE splitElem #-}+    {-# INLINE splitSeq #-}     {-# INLINE isPrefixOf #-}     {-# INLINE isSuffixOf #-}     {-# INLINE isInfixOf #-}@@ -1265,13 +1353,19 @@ notElem :: EqSequence seq => Element seq -> seq -> Bool notElem = onotElem +-- | Use 'splitOn' from "Data.List.Split"+defaultSplitOn :: EqSequence s => s -> s -> [s]+defaultSplitOn sep = List.map fromList . List.splitOn (otoList sep) . otoList+ instance Eq a => EqSequence [a] where+    splitSeq = List.splitOn     stripPrefix = List.stripPrefix     stripSuffix x y = fmap reverse (List.stripPrefix (reverse x) (reverse y))     group = List.group     isPrefixOf = List.isPrefixOf     isSuffixOf x y = List.isPrefixOf (List.reverse x) (List.reverse y)     isInfixOf = List.isInfixOf+    {-# INLINE splitSeq #-}     {-# INLINE stripPrefix #-}     {-# INLINE stripSuffix #-}     {-# INLINE group #-}@@ -1281,6 +1375,8 @@     {-# INLINE isInfixOf #-}  instance EqSequence S.ByteString where+    splitElem sep s | S.null s = [S.empty]+                    | otherwise = S.split sep s     stripPrefix x y         | x `S.isPrefixOf` y = Just (S.drop (S.length x) y)         | otherwise = Nothing@@ -1291,6 +1387,7 @@     isPrefixOf = S.isPrefixOf     isSuffixOf = S.isSuffixOf     isInfixOf = S.isInfixOf+    {-# INLINE splitElem #-}     {-# INLINE stripPrefix #-}     {-# INLINE stripSuffix #-}     {-# INLINE group #-}@@ -1300,6 +1397,8 @@     {-# INLINE isInfixOf #-}  instance EqSequence L.ByteString where+    splitElem sep s | L.null s = [L.empty]+                    | otherwise = L.split sep s     stripPrefix x y         | x `L.isPrefixOf` y = Just (L.drop (L.length x) y)         | otherwise = Nothing@@ -1310,6 +1409,7 @@     isPrefixOf = L.isPrefixOf     isSuffixOf = L.isSuffixOf     isInfixOf x y = L.unpack x `List.isInfixOf` L.unpack y+    {-# INLINE splitElem #-}     {-# INLINE stripPrefix #-}     {-# INLINE stripSuffix #-}     {-# INLINE group #-}@@ -1319,12 +1419,15 @@     {-# INLINE isInfixOf #-}  instance EqSequence T.Text where+    splitSeq sep | T.null sep = (:) T.empty . List.map singleton . T.unpack+                 | otherwise = T.splitOn sep     stripPrefix = T.stripPrefix     stripSuffix = T.stripSuffix     group = T.group     isPrefixOf = T.isPrefixOf     isSuffixOf = T.isSuffixOf     isInfixOf = T.isInfixOf+    {-# INLINE splitSeq #-}     {-# INLINE stripPrefix #-}     {-# INLINE stripSuffix #-}     {-# INLINE group #-}@@ -1334,12 +1437,15 @@     {-# INLINE isInfixOf #-}  instance EqSequence TL.Text where+    splitSeq sep | TL.null sep = (:) TL.empty . List.map singleton . TL.unpack+                 | otherwise = TL.splitOn sep     stripPrefix = TL.stripPrefix     stripSuffix = TL.stripSuffix     group = TL.group     isPrefixOf = TL.isPrefixOf     isSuffixOf = TL.isSuffixOf     isInfixOf = TL.isInfixOf+    {-# INLINE splitSeq #-}     {-# INLINE stripPrefix #-}     {-# INLINE stripSuffix #-}     {-# INLINE group #-}
test/Spec.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ViewPatterns #-}+ module Spec where  import Data.MonoTraversable@@ -9,11 +11,14 @@ import qualified Data.Sequence as Seq import qualified Data.NonNull as NN import Data.ByteVector+import Data.Monoid (mempty, mconcat)+import Data.Maybe (fromMaybe)  import Test.Hspec import Test.Hspec.QuickCheck import Test.HUnit ((@?=)) import Test.QuickCheck hiding (NonEmptyList(..))+import qualified Test.QuickCheck as QC import qualified Test.QuickCheck.Modifiers as QCM  import Data.Text (Text)@@ -38,7 +43,7 @@ import Control.Monad.Trans.Writer  import Prelude (Bool (..), ($), IO, min, abs, Eq (..), (&&), fromIntegral, Ord (..), String, mod, Int, Integer, show,-                return, asTypeOf, (.), Show, id, (+), succ, Maybe (..), (*), mod, map, flip, otherwise, (-), div, seq)+                return, asTypeOf, (.), Show, id, (+), succ, Maybe (..), (*), mod, map, flip, otherwise, (-), div, seq, maybe) import qualified Prelude  instance Arbitrary a => Arbitrary (NE.NonEmpty a) where@@ -385,6 +390,59 @@         test "Strict Text" T.empty         test "Lazy Text" TL.empty +    describe "Intercalate" $ do+        let test typ dummy = describe typ $ do+                prop "intercalate === defaultIntercalate" $ \list lists ->+                    let seq = fromListAs list dummy+                        seqs = map (`fromListAs` dummy) lists+                    in intercalate seq seqs @?= defaultIntercalate seq seqs+        test "List" ([] :: [Int])+        test "Vector" (V.empty :: V.Vector Int)+        test "Storable Vector" (VS.empty :: VS.Vector Int)+        test "Unboxed Vector" (U.empty :: U.Vector Int)+        test "Strict ByteString" S.empty+        test "Lazy ByteString" L.empty+        test "Strict Text" T.empty+        test "Lazy Text" TL.empty++    describe "Splitting" $ do+        let test typ dummy = describe typ $ do+                let fromList' = (`fromListAs` dummy)+                let fromSepList sep = fromList' . map (fromMaybe sep)+                prop "intercalate sep . splitSeq sep === id" $+                    \(fromList' -> sep) ->+                    \(mconcat . map (maybe sep fromList') -> xs) ->+                    intercalate sep (splitSeq sep xs) @?= xs+                prop "splitSeq mempty xs === mempty : map singleton (otoList xs)" $+                    \input ->+                    splitSeq mempty (fromList' input) @?= mempty : map singleton input+                prop "splitSeq _ mempty == [mempty]" $+                    \(fromList' -> sep) ->+                    splitSeq sep mempty @?= [mempty]+                prop "intercalate (singleton sep) . splitElem sep === id" $+                    \sep -> \(fromSepList sep -> xs) ->+                    intercalate (singleton sep) (splitElem sep xs) @?= xs+                prop "length . splitElem sep === succ . length . filter (== sep)" $+                    \sep -> \(fromSepList sep -> xs) ->+                    olength (splitElem sep xs) @?= olength (filter (== sep) xs) + 1+                prop "splitElem sep (replicate n sep) == replicate (n+1) mempty" $+                    \(NonNegative n) sep ->+                    splitElem sep (fromList' (replicate n sep)) @?= replicate (n + 1) mempty+                prop "splitElem sep === splitWhen (== sep)" $+                    \sep -> \(fromSepList sep -> xs) ->+                    splitElem sep xs @?= splitWhen (== sep) xs+                prop "splitElem sep === splitSeq (singleton sep)" $+                    \sep -> \(fromSepList sep -> xs) ->+                    splitElem sep xs @?= splitSeq (singleton sep) xs+        test "List" ([] :: [Int])+        test "Vector" (V.empty :: V.Vector Int)+        test "Storable Vector" (VS.empty :: VS.Vector Int)+        test "Unboxed Vector" (U.empty :: U.Vector Int)+        test "Strict ByteString" S.empty+        test "Lazy ByteString" L.empty+        test "Strict Text" T.empty+        test "Lazy Text" TL.empty+     describe "Data.ByteVector" $ do         prop "toByteVector" $ \ws ->             (otoList . toByteVector . fromList $ ws) @?= ws@@ -398,3 +456,4 @@          it "#31 find doesn't infinitely loop on NonEmpty" $             find (== "a") ("a" NE.:| ["d","fgf"]) @?= Just "a"+