grouped-list 0.1.3.0 → 0.2.0.0
raw patch · 6 files changed
+99/−15 lines, 6 filesdep +transformersdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: transformers
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Data.GroupedList: firstGroup :: Grouped a -> Maybe (Group a, Grouped a)
+ Data.GroupedList: groupSize :: Group a -> Int
+ Data.GroupedList: lastGroup :: Grouped a -> Maybe (Grouped a, Group a)
+ Data.GroupedList: length :: Foldable t => forall a. t a -> Int
Files
- CHANGELOG.md +10/−0
- Data/GroupedList.hs +67/−8
- README.md +5/−0
- bench/Main.hs +1/−0
- grouped-list.cabal +8/−5
- test/properties.hs +8/−2
CHANGELOG.md view
@@ -1,4 +1,14 @@ +# 0.1.3.0++* IsList instance to use with the OverloadedLists+ language extension.++* Addition of ``take`` and ``drop``.++* Two test suites added, one with example-based+ tests, and other with property-based tests.+ # 0.1.2.0 * Addition of ``adjustM``.
Data/GroupedList.hs view
@@ -1,5 +1,5 @@ -{-# LANGUAGE TupleSections, TypeFamilies #-}+{-# LANGUAGE TupleSections, TypeFamilies, CPP #-} -- | Grouped lists are like lists, but internally they are represented -- as groups of consecutive elements.@@ -18,6 +18,8 @@ , concatMap , replicate , fromGroup+ -- * Info+ , length -- * Indexing , index , adjust@@ -43,17 +45,21 @@ , Group , buildGroup , groupElement+ , groupSize+ -- ** In grouped lists , groupedGroups+ , firstGroup+ , lastGroup ) where import Prelude hiding ( concat, concatMap, replicate, filter, map- , take, drop+ , take, drop, foldl, foldr, length ) import qualified Prelude as Prelude import Data.Pointed-import Data.Foldable (toList, fold, foldrM)-import Data.List (group, foldl')+import Data.Foldable (Foldable (..), toList, foldrM)+import Data.List (group) import Data.Sequence (Seq) import qualified Data.Sequence as S import Data.Monoid ((<>))@@ -61,8 +67,21 @@ import Control.Arrow (second) import qualified Data.Map.Strict as M import Data.Functor.Identity (Identity (..))++------------------------------------------------------------------+------------------------------------------------------------------+-- COMPATIBILITY++#if MIN_VERSION_base(4,7,0) import qualified GHC.Exts as GHC+#endif +#if !MIN_VERSION_base(4,8,0)+import Control.Applicative (Applicative (..), (<$>))+import Data.Traversable (traverse)+import Data.Monoid (Monoid (..))+#endif+ ------------------------------------------------------------------ ------------------------------------------------------------------ -- GROUP@@ -80,6 +99,10 @@ groupElement :: Group a -> a groupElement (Group _ a) = a +-- | Size of a group.+groupSize :: Group a -> Int+groupSize (Group n _) = n+ -- | A group is larger than other if its constituent element is -- larger. If they are equal, the group with more elements is -- the larger.@@ -97,9 +120,11 @@ instance Foldable Group where foldMap f (Group n a) = mconcat $ Prelude.replicate n $ f a+#if MIN_VERSION_base(4,8,0) elem x (Group _ a) = x == a null _ = False length (Group n _) = n+#endif instance Show a => Show (Group a) where show = show . toList@@ -115,6 +140,9 @@ gf <*> gx = groupBind gx $ \x -> fmap ($x) gf instance Monad Group where+#if !MIN_VERSION_base(4,8,0)+ return = pure+#endif (>>=) = groupBind instance NFData a => NFData (Group a) where@@ -133,18 +161,19 @@ empty :: Grouped a empty = Grouped S.empty +#if MIN_VERSION_base(4,7,0) -- | Method 'fromList' doesn't work for infinite lists. -- A grouped list cannot be infinite. instance Eq a => GHC.IsList (Grouped a) where type (Item (Grouped a)) = a- fromList = Grouped . S.fromList . fmap (\g -> Group (length g) $ head g) . group+ fromList = fromList toList = toList+#endif -- | Build a grouped list from a regular list. It doesn't work if--- the input list is infinite. This is just a specialized version--- of 'GHC.fromList'.+-- the input list is infinite. fromList :: Eq a => [a] -> Grouped a-fromList = GHC.fromList+fromList = Grouped . S.fromList . fmap (\g -> Group (Prelude.length g) $ head g) . group -- | Build a grouped list from a group (see 'Group'). fromGroup :: Group a -> Grouped a@@ -154,6 +183,22 @@ groupedGroups :: Grouped a -> [Group a] groupedGroups (Grouped gs) = toList gs +-- | Get the first group (if the list is not empty) and+-- the rest of the list.+firstGroup :: Grouped a -> Maybe (Group a, Grouped a)+firstGroup (Grouped gs) =+ case S.viewl gs of+ g S.:< hs -> Just (g, Grouped hs)+ _ -> Nothing++-- | Get the last group (if the list is not empty) and+-- the rest of the list.+lastGroup :: Grouped a -> Maybe (Grouped a, Group a)+lastGroup (Grouped gs) =+ case S.viewr gs of+ hs S.:> g -> Just (Grouped hs,g)+ _ -> Nothing+ instance Pointed Grouped where point = fromGroup . point @@ -185,9 +230,15 @@ instance Foldable Grouped where foldMap f (Grouped gs) = foldMap (foldMap f) gs+#if MIN_VERSION_base(4,8,0) length (Grouped gs) = foldl' (+) 0 $ fmap length gs null (Grouped gs) = null gs+#else +length :: Grouped a -> Int+length (Grouped gs) = foldl' (+) 0 $ fmap groupSize gs+#endif+ instance Show a => Show (Grouped a) where show = show . toList @@ -269,7 +320,11 @@ adjust f i g = runIdentity $ adjustM (Identity . f) i g -- | Just like 'adjust', but the function returns in a 'Monad'.+#if MIN_VERSION_base(4,8,0) adjustM :: (Monad m, Eq a) => (a -> m a) -> Int -> Grouped a -> m (Grouped a)+#else+adjustM :: (Applicative m, Monad m, Eq a) => (a -> m a) -> Int -> Grouped a -> m (Grouped a)+#endif adjustM f k g@(Grouped gs) = if k < 0 then pure g else Grouped <$> go 0 k gs where -- Pre-condition: 0 <= i@@ -399,7 +454,11 @@ -- | Like 'traverseGroupedByGroup', but carrying an accumulator. -- Note the 'Monad' constraint instead of 'Applicative'. traverseGroupedByGroupAccum ::+#if MIN_VERSION_base(4,8,0) (Monad m, Eq b)+#else+ (Applicative m, Monad m, Eq b)+#endif => (acc -> Group a -> m (acc, Grouped b)) -> acc -- ^ Initial value of the accumulator. -> Grouped a
README.md view
@@ -1,3 +1,4 @@+ # grouped-list Welcome to the `grouped-list` repository.@@ -21,3 +22,7 @@ usage is reduced. However, this type is suboptimal for lists that do not have many consecutive repetitions. We are trying to ameliorate this.++# Automatic build++[](https://travis-ci.org/Daniel-Diaz/grouped-list)
bench/Main.hs view
@@ -58,4 +58,5 @@ , benchGroup "adjust 1/2" $ nf $ G.adjust (+1) $ sampleSize2 + 1 , benchGroup "adjust 2/2" $ nf $ G.adjust (+1) $ sampleSize - 1 , bench "mappend" $ nf (\xs -> mappend xs xs) halflist+ , benchGroup "sort" $ nf G.sort ]
grouped-list.cabal view
@@ -1,5 +1,5 @@ name: grouped-list-version: 0.1.3.0+version: 0.2.0.0 synopsis: Grouped lists. Equal consecutive elements are grouped. description: Grouped lists work like regular lists, except for two conditions:@@ -30,11 +30,14 @@ default-language: Haskell2010 exposed-modules: Data.GroupedList build-depends:- base >= 4.8 && < 5+ base >= 4.7 && < 4.9 , containers , pointed , deepseq ghc-options: -O2 -Wall+ -- compatibility+ if impl(ghc < 7.10)+ build-depends: transformers benchmark grouped-list-bench default-language: Haskell2010@@ -42,7 +45,7 @@ hs-source-dirs: bench main-is: Main.hs ghc-options: -O2 -Wall- build-depends: base >= 4.8, grouped-list, criterion+ build-depends: base, grouped-list, criterion source-repository head type: git@@ -53,7 +56,7 @@ type: exitcode-stdio-1.0 hs-source-dirs: test main-is: examples.hs- build-depends: base >= 4.8, grouped-list+ build-depends: base, grouped-list test-suite grouped-list-properties default-language: Haskell2010@@ -62,5 +65,5 @@ main-is: properties.hs ghc-options: -Wall build-depends:- base >= 4.8, grouped-list+ base, grouped-list , QuickCheck, tasty, tasty-quickcheck
test/properties.hs view
@@ -1,4 +1,6 @@ +{-# LANGUAGE CPP #-}+ module Main (main) where import Data.GroupedList (Grouped)@@ -10,6 +12,10 @@ import qualified Test.Tasty.QuickCheck as QC import Test.QuickCheck (Arbitrary (..), Testable, choose) +#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+ -- | A short alias for 'QC.testProperty'. prop :: Testable a => TestName -> a -> TestTree prop = QC.testProperty@@ -28,7 +34,7 @@ , prop "right mempty" $ \(G xs) -> xs <> GL.empty == xs , prop "mappend" $ \(G xs) (G ys) (G zs) -> (xs <> ys) <> zs == xs <> (ys <> zs) , prop "index" $ \(G xs) ->- let n = length xs+ let n = GL.length xs in (\i -> let r = GL.index xs i in if i <= n - 1@@ -36,7 +42,7 @@ else r == Nothing ) <$> choose (0,2*n) , prop "split and concat" $ \(G xs) ->- let n = length xs+ let n = GL.length xs in (\i -> GL.take i xs <> GL.drop i xs == xs) <$> choose (0,n) , prop "map id" $ \(G xs) -> GL.map id xs == xs , prop "map (+1) . map (+1) = map (+2)" $