classy-prelude 0.5.2 → 0.5.3
raw patch · 12 files changed
+305/−2 lines, 12 filesdep ~basic-preludePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: basic-prelude
API changes (from Hackage documentation)
+ ClassyPrelude: data Seq a :: * -> *
+ ClassyPrelude: group :: CanGroup c a => c -> [c]
+ ClassyPrelude: groupBy :: CanGroupBy c a => (a -> a -> Bool) -> c -> [c]
+ ClassyPrelude: groupWith :: (CanGroupBy c a, Eq b) => (a -> b) -> c -> [c]
+ ClassyPrelude: product :: (Foldable t, Num a) => t a -> a
+ ClassyPrelude: repeat :: CanRepeat c a => a -> c
+ ClassyPrelude: sum :: (Foldable t, Num a) => t a -> a
+ ClassyPrelude.Classes: class CanGroup c a | c -> a where group = groupBy (==)
+ ClassyPrelude.Classes: class CanGroupBy c a | c -> a
+ ClassyPrelude.Classes: class CanRepeat c a | c -> a
+ ClassyPrelude.Classes: group :: CanGroup c a => c -> [c]
+ ClassyPrelude.Classes: groupBy :: CanGroupBy c a => (a -> a -> Bool) -> c -> [c]
+ ClassyPrelude.Classes: repeat :: CanRepeat c a => a -> c
Files
- ClassyPrelude.hs +16/−0
- ClassyPrelude/ByteString.hs +16/−0
- ClassyPrelude/Classes.hs +11/−0
- ClassyPrelude/LByteString.hs +16/−0
- ClassyPrelude/LText.hs +6/−0
- ClassyPrelude/List.hs +9/−0
- ClassyPrelude/Sequence.hs +135/−0
- ClassyPrelude/Set.hs +6/−0
- ClassyPrelude/Text.hs +6/−0
- ClassyPrelude/Vector.hs +44/−0
- classy-prelude.cabal +3/−2
- test/main.hs +37/−0
ClassyPrelude.hs view
@@ -6,6 +6,7 @@ module ClassyPrelude ( -- * CorePrelude module CorePrelude+ , Seq -- * Standard -- ** Monoid , empty@@ -69,9 +70,15 @@ , sort , sortBy , sortWith+ , group+ , groupBy+ , groupWith , cons , uncons , compareLength+ , Foldable.sum+ , Foldable.product+ , repeat -- ** Map-like , lookup , insert@@ -143,6 +150,7 @@ import ClassyPrelude.Set () import ClassyPrelude.Text () import ClassyPrelude.Vector ()+import ClassyPrelude.Sequence (Seq) show :: (Show a, CanPack c Char) => a -> c@@ -257,3 +265,11 @@ -- Inspired by <http://hackage.haskell.org/packages/archive/base/latest/doc/html/GHC-Exts.html#v:sortWith>. sortWith :: (CanSortBy c a, Ord b) => (a -> b) -> c -> c sortWith f = sortBy $ comparing f++-- | The 'groupWith' function uses the user supplied function which+-- projects an element out of every list element in order to first sort the+-- input list and then to form groups by equality on these projected elements+--+-- Inspired by <http://hackage.haskell.org/packages/archive/base/latest/doc/html/GHC-Exts.html#v:groupWith>+groupWith :: (CanGroupBy c a, Eq b) => (a -> b) -> c -> [c]+groupWith f = groupBy (\a b -> f a == f b)
ClassyPrelude/ByteString.hs view
@@ -37,6 +37,13 @@ instance CanIntersperse ByteString Word8 where intersperse = ByteString.intersperse +instance CanStripPrefix ByteString where+ stripPrefix x y+ | x `ByteString.isPrefixOf` y =+ Just $ ByteString.drop (ByteString.length x) y+ | otherwise = Nothing+ isPrefixOf = ByteString.isPrefixOf+ instance CanReadFile ByteString where readFile = liftIO . ByteString.readFile . FilePath.encodeString @@ -71,6 +78,9 @@ | otherwise = Nothing isSuffixOf = ByteString.isSuffixOf +instance CanIsInfixOf ByteString where+ isInfixOf = ByteString.isInfixOf+ instance MonadIO m => CanGetLine (m ByteString) where getLine = liftIO ByteString.getLine @@ -82,3 +92,9 @@ instance CanUncons ByteString Word8 where uncons = ByteString.uncons++instance CanGroupBy ByteString Word8 where+ groupBy = ByteString.groupBy++instance CanGroup ByteString Word8 where+ group = ByteString.group
ClassyPrelude/Classes.hs view
@@ -203,3 +203,14 @@ -- or `Text`. It does not traverse the whole data structure if the value -- being compared to is lesser. compareLength :: (Integral l) => c -> l -> Ordering++class CanGroupBy c a | c -> a where+ groupBy :: (a -> a -> Bool) -> c -> [c]++class CanGroup c a | c -> a where+ group :: c -> [c]+ default group :: (CanGroupBy c a, Eq a) => c -> [c]+ group = groupBy (==)++class CanRepeat c a | c -> a where+ repeat :: a -> c
ClassyPrelude/LByteString.hs view
@@ -38,6 +38,13 @@ instance CanIntersperse LByteString Word8 where intersperse = LByteString.intersperse +instance CanStripPrefix LByteString where+ stripPrefix x y+ | x `LByteString.isPrefixOf` y =+ Just $ LByteString.drop (LByteString.length x) y+ | otherwise = Nothing+ isPrefixOf = LByteString.isPrefixOf+ instance CanReadFile LByteString where readFile = liftIO . LByteString.readFile . FilePath.encodeString @@ -88,3 +95,12 @@ instance CanUncons LByteString Word8 where uncons = LByteString.uncons++instance CanGroupBy LByteString Word8 where+ groupBy = LByteString.groupBy++instance CanGroup LByteString Word8 where+ group = LByteString.group++instance CanRepeat LByteString Word8 where+ repeat = LByteString.repeat
ClassyPrelude/LText.hs view
@@ -125,3 +125,9 @@ instance CanCompareLength LText where compareLength c = LText.compareLength c . fromIntegral++instance CanGroupBy LText Char where+ groupBy = LText.groupBy++instance CanGroup LText Char where+ group = LText.group
ClassyPrelude/List.hs view
@@ -148,3 +148,12 @@ compareLength _ i | i <= 0 = GT compareLength [] _ = LT compareLength (_:t) i = compareLength t (i-1)++instance CanGroupBy [a] a where+ groupBy = List.groupBy++instance Eq a => CanGroup [a] a where+ group = List.group++instance CanRepeat [a] a where+ repeat = List.repeat
+ ClassyPrelude/Sequence.hs view
@@ -0,0 +1,135 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+module ClassyPrelude.Sequence+ ( Seq+ ) where++import CorePrelude+import ClassyPrelude.Classes+import qualified Data.Monoid as Monoid+import qualified Control.Monad as Monad+import qualified Data.Foldable as Foldable+import qualified Data.Traversable as Traversable+import qualified Data.Sequence as Sequence+import Data.Sequence (Seq, (<|), (|>), ViewL(..), viewl, ViewR(..), viewr)+++instance CanMap (Seq a) (Seq b) a b where+ map = Monad.fmap++instance CanConcatMap (Seq a) (Seq b) a (Seq b) where+ concatMap = (Monad.=<<)++instance CanFilter (Seq a) a where+ filter = Sequence.filter++instance CanFilterM (Seq a) a where+ filterM p =+ Foldable.foldlM+ (\ xs x -> do res <- p x; return $ if res then xs |> x else xs)+ Sequence.empty++instance CanLength (Seq a) Int where+ length = Sequence.length++instance CanSingleton (Seq a) a where+ singleton = Sequence.singleton++instance CanNull (Seq a) where+ null = Sequence.null++instance CanPack (Seq a) a where+ pack = Sequence.fromList+ unpack = Foldable.toList++instance CanIntersperse (Seq a) a where+ intersperse sep xs = case viewl xs of+ EmptyL -> Sequence.empty+ (h :< t) -> h <| prependToAll sep t+ where+ prependToAll sep xs = case viewl xs of+ EmptyL -> Sequence.empty+ (h :< t) -> sep <| (h <| prependToAll sep t)++instance Eq a => CanStripPrefix (Seq a) where+ stripPrefix x y+ | x == y1 = Just y2+ | otherwise = Nothing+ where+ (y1, y2) = Sequence.splitAt (Sequence.length x) y+ isPrefixOf x y = Sequence.take (Sequence.length x) y == x++instance Eq a => CanStripSuffix (Seq a) where+ stripSuffix x y+ | x == y2 = Just y1+ | otherwise = Nothing+ where+ (y1, y2) = Sequence.splitAt (Sequence.length y - Sequence.length x) y+ isSuffixOf x y = takeRR (Sequence.length x) y == x+ where+ takeRR 0 _ = Sequence.empty+ takeRR n xs = case viewr xs of+ EmptyR -> Sequence.empty+ xs' :> x -> takeRR (n-1) xs' |> x++instance Monad m => CanMapM (Seq i) (m (Seq o)) m i o where+ mapM = Traversable.mapM++instance CanMapM_ (Seq a) a where+ mapM_ = Foldable.mapM_++instance Eq x => CanMember (Seq x) x where+ member x = any (== x)++instance CanBreak (Seq a) a where+ break = Sequence.breakl+ span = Sequence.spanl+ dropWhile = Sequence.dropWhileL+ takeWhile = Sequence.takeWhileL++instance CanAny (Seq a) a where+ any = Foldable.any+ all = Foldable.all++instance CanSplitAt (Seq a) Int where+ splitAt = Sequence.splitAt++instance CanFold (Seq a) a accum where+ fold = Foldable.foldl'++instance CanReverse (Seq a) where+ reverse = Sequence.reverse++instance CanReplicate (Seq a) a Int where+ replicate = Sequence.replicate++instance CanReplicateM (Seq a) a Int where+ replicateM = Sequence.replicateM++instance CanFind (Seq a) a where+ find p s = case Sequence.breakl p s of+ (_, s') -> case Sequence.viewl s' of+ a :< _ -> Just a+ _ -> Nothing++instance (Monoid m) => CanConcat (Seq m) m where+ concat = Foldable.fold++instance CanPartition (Seq a) a where+ partition = Sequence.partition++instance CanSortBy (Seq a) a where+ sortBy = Sequence.sortBy++instance Ord a => CanSort (Seq a) a where+ sort = Sequence.sort++instance CanCons (Seq a) a where+ cons = (<|)++instance CanUncons (Seq a) a where+ uncons s = case Sequence.viewl s of+ EmptyL -> Nothing+ a :< s' -> Just (a, s')
ClassyPrelude/Set.hs view
@@ -16,6 +16,9 @@ instance (Ord a, Ord b) => CanMap (Set a) (Set b) a b where map = Set.map +instance Ord a => CanFilter (Set a) a where+ filter = Set.filter+ instance CanLength (Set x) Int where length = Set.size @@ -31,6 +34,9 @@ instance (Ord x, Set x ~ s, x ~ x') => CanInsert (x' -> s -> Set x) where insert = Set.insert++instance Ord x => CanDeleteVal (Set x) x where+ deleteVal = Set.delete instance Ord x => CanMember (Set x) x where member = Set.member
ClassyPrelude/Text.hs view
@@ -117,3 +117,9 @@ instance CanCompareLength Text where compareLength c = Text.compareLength c . fromIntegral++instance CanGroupBy Text Char where+ groupBy = Text.groupBy++instance CanGroup Text Char where+ group = Text.group
ClassyPrelude/Vector.hs view
@@ -45,6 +45,14 @@ prependToAll _ xs | null xs = Vector.empty prependToAll sep xs = Vector.cons sep $ Vector.cons (Vector.head xs) $ prependToAll sep $ Vector.unsafeTail xs +instance Eq a => CanStripPrefix (Vector a) where+ stripPrefix x y+ | x == y1 = Just y2+ | otherwise = Nothing+ where+ (y1, y2) = Vector.splitAt (Vector.length x) y+ isPrefixOf x y = Vector.take (Vector.length x) y == x+ instance Monad m => CanMapM (Vector i) (m (Vector o)) m i o where mapM = Vector.mapM @@ -93,3 +101,39 @@ instance CanUncons (Vector a) a where uncons v = if null v then Nothing else Just (Vector.unsafeHead v, Vector.unsafeTail v)++instance CanGroupBy (Vector a) a where+ -- | Implementation is stolen from <http://hackage.haskell.org/packages/archive/storablevector/latest/doc/html/src/Data-StorableVector.html#groupBy>+ groupBy k xs =+ switchL []+ (\h t ->+ let n = 1 + findIndexOrEnd (not . k h) t+ in Vector.unsafeTake n xs : groupBy k (Vector.unsafeDrop n xs))+ xs++instance Eq a => CanGroup (Vector a) a where+ -- | A special case of 'groupBy', which is about 40% faster than + -- /groupBy (==)/.+ -- + -- Implementation is stolen from <http://hackage.haskell.org/packages/archive/storablevector/latest/doc/html/src/Data-StorableVector.html#groupBy>+ group xs =+ switchL []+ (\h _ ->+ let (ys, zs) = span (== h) xs+ in ys : group zs)+ xs++-- Helper functions stolen from <http://hackage.haskell.org/packages/archive/storablevector/latest/doc/html/src/Data-StorableVector.html#groupBy>++-- | 'findIndexOrEnd' is a variant of findIndex, that returns the length+-- of the string if no element is found, rather than Nothing.+findIndexOrEnd p xs =+ Vector.foldr+ (\x k n ->+ if p x then n else k (succ n))+ id xs 0+switchL n j x =+ if null x+ then n+ else j (Vector.unsafeHead x) (Vector.unsafeTail x)+
classy-prelude.cabal view
@@ -1,5 +1,5 @@ name: classy-prelude-version: 0.5.2+version: 0.5.3 synopsis: A typeclass-based Prelude. description: Focuses on using common typeclasses when possible, and creating new ones to avoid name clashing. Exposes many recommended datastructures (Map, ByteString, etc) directly without requiring long import lists and qualified modules. homepage: https://github.com/snoyberg/classy-prelude@@ -27,8 +27,9 @@ ClassyPrelude.HashMap ClassyPrelude.HashSet ClassyPrelude.Char+ ClassyPrelude.Sequence build-depends: base >= 4 && < 5- , basic-prelude >= 0.3.3 && < 0.4+ , basic-prelude >= 0.3.4 && < 0.4 , system-filepath >= 0.4 && < 0.5 , transformers , containers >= 0.4.2
test/main.hs view
@@ -243,6 +243,21 @@ prop "compare (length c) i == compareLength c i" $ \i c -> compare (length c) i == compareLength (c `asTypeOf` dummy) i +prefixProps :: ( Show c+ , Eq c+ , Monoid c+ , CanStripPrefix c+ , Arbitrary c+ )+ => c -> Spec+prefixProps dummy = do+ prop "x `isPrefixOf` (x ++ y)" $ \x y ->+ (x `asTypeOf` dummy) `isPrefixOf` (x ++ y)+ prop "stripPrefix x (x ++ y) == Just y" $ \x y ->+ stripPrefix x (x ++ y) == Just (y `asTypeOf` dummy)+ prop "stripPrefix x y == Nothing || x `isPrefixOf` y" $ \x y ->+ stripPrefix x y == Nothing || x `isPrefixOf` (y `asTypeOf` dummy)+ main :: IO () main = hspec $ do describe "dictionary" $ do@@ -258,6 +273,7 @@ describe "Data.ByteString.Lazy" $ mapProps (undefined :: LByteString) (+ 1) (+ 2) describe "Data.Text" $ mapProps (undefined :: Text) succ succ describe "Data.Text.Lazy" $ mapProps (undefined :: LText) succ succ+ describe "Data.Sequence" $ mapProps (undefined :: Seq Int) succ succ describe "concatMap" $ do describe "list" $ concatMapProps (undefined :: [Int]) (\i -> [i + 1, i + 2]) describe "Data.Vector" $ concatMapProps (undefined :: Vector Int) (\i -> fromList [i + 1, i + 2])@@ -265,6 +281,7 @@ describe "Data.ByteString.Lazy" $ concatMapProps (undefined :: LByteString) (\i -> fromList [i + 1, i + 2]) describe "Data.Text" $ concatMapProps (undefined :: Text) (\c -> pack [succ c, succ $ succ c]) describe "Data.Text.Lazy" $ concatMapProps (undefined :: LText) (\c -> pack [succ c, succ $ succ c])+ describe "Data.Sequence" $ concatMapProps (undefined :: Seq Int) (\i -> pack [i + 1, i + 2]) describe "filter" $ do describe "list" $ filterProps (undefined :: [Int]) (< 20) describe "Data.Vector" $ filterProps (undefined :: Vector Int) (< 20)@@ -274,9 +291,12 @@ describe "Data.Text.Lazy" $ filterProps (undefined :: LText) (< 'A') describe "Data.Map" $ filterProps (undefined :: Map Int Char) (\(i, _) -> i < 20) describe "Data.HashMap" $ filterProps (undefined :: HashMap Int Char) (\(i, _) -> i < 20)+ describe "Data.Set" $ filterProps (undefined :: Set Int) (< 20)+ describe "Data.Sequence" $ filterProps (undefined :: Seq Int) (< 20) describe "filterM" $ do describe "list" $ filterMProps (undefined :: [Int]) (< 20) describe "Data.Vector" $ filterMProps (undefined :: Vector Int) (< 20)+ describe "Data.Sequence" $ filterMProps (undefined :: Seq Int) (< 20) describe "length" $ do describe "list" $ lengthProps (undefined :: [Int]) describe "Data.Vector" $ lengthProps (undefined :: Vector Int)@@ -288,14 +308,17 @@ describe "Data.HashMap" $ lengthProps (undefined :: HashMap Int Char) describe "Data.Set" $ lengthProps (undefined :: Set Int) describe "Data.HashSet" $ lengthProps (undefined :: HashSet Int)+ describe "Data.Sequence" $ lengthProps (undefined :: Seq Int) describe "mapM" $ do describe "list" $ mapMProps (undefined :: [Int]) describe "Data.Vector" $ mapMProps (undefined :: Vector Int)+ describe "Seq" $ mapMProps (undefined :: Seq Int) describe "mapM_" $ do describe "list" $ mapM_Props (undefined :: [Int]) describe "Data.Vector" $ mapM_Props (undefined :: Vector Int) describe "Set" $ mapM_Props (undefined :: Set Int) describe "HashSet" $ mapM_Props (undefined :: HashSet Int)+ describe "Seq" $ mapM_Props (undefined :: Seq Int) describe "fold" $ do let f = flip (:) describe "list" $ foldProps (undefined :: [Int]) f []@@ -306,6 +329,7 @@ describe "Data.Text.Lazy" $ foldProps (undefined :: LText) f [] describe "Data.Set" $ foldProps (undefined :: Set Int) f [] describe "Data.HashSet" $ foldProps (undefined :: HashSet Int) f []+ describe "Data.Sequence" $ foldProps (undefined :: Seq Int) f [] describe "replicate" $ do describe "list" $ replicateProps (undefined :: [Int]) pack describe "Data.Vector" $ replicateProps (undefined :: Vector Int) pack@@ -313,6 +337,7 @@ describe "Data.ByteString.Lazy" $ replicateProps (undefined :: LByteString) pack describe "Data.Text" $ replicateProps (undefined :: Text) concat describe "Data.Text.Lazy" $ replicateProps (undefined :: LText) concat+ describe "Data.Sequence" $ replicateProps (undefined :: Seq Int) pack describe "chunks" $ do describe "ByteString" $ chunkProps (asLByteString undefined) describe "Text" $ chunkProps (asLText undefined)@@ -321,9 +346,11 @@ describe "LText" $ stripSuffixProps (undefined :: LText) describe "ByteString" $ stripSuffixProps (undefined :: ByteString) describe "LByteString" $ stripSuffixProps (undefined :: LByteString)+ describe "Seq" $ stripSuffixProps (undefined :: Seq Int) describe "replicateM" $ do describe "list" $ replicateMProps (undefined :: [Int]) describe "Vector" $ replicateMProps (undefined :: Vector Int)+ describe "Seq" $ replicateMProps (undefined :: Seq Int) describe "encode/decode UTF8" $ do describe "Text" $ utf8Props (undefined :: Text) describe "LText" $ utf8Props (undefined :: LText)@@ -331,6 +358,14 @@ describe "list" $ compareLengthProps (undefined :: [Int]) describe "Text" $ compareLengthProps (undefined :: Text) describe "LText" $ compareLengthProps (undefined :: LText)+ describe "Prefix" $ do+ describe "list" $ prefixProps (undefined :: [Int])+ describe "Text" $ prefixProps (undefined :: Text)+ describe "LText" $ prefixProps (undefined :: LText)+ describe "ByteString" $ prefixProps (undefined :: ByteString)+ describe "LByteString" $ prefixProps (undefined :: LByteString)+ describe "Vector" $ prefixProps (undefined :: Vector Int)+ describe "Seq" $ prefixProps (undefined :: Seq Int) instance Arbitrary (Map Int Char) where arbitrary = fromList <$> arbitrary@@ -349,4 +384,6 @@ instance Arbitrary Text where arbitrary = fromList <$> arbitrary instance Arbitrary LText where+ arbitrary = fromList <$> arbitrary+instance Arbitrary (Seq Int) where arbitrary = fromList <$> arbitrary