packages feed

extra 1.0.1 → 1.1

raw patch · 8 files changed

+118/−7 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- System.Time.Extra: instance Eq Timeout
- System.Time.Extra: instance Exception Timeout
- System.Time.Extra: instance Show Timeout
- System.Time.Extra: instance Typeable Timeout
+ Data.List.Extra: groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]
+ Data.List.Extra: groupSortOn :: Ord b => (a -> b) -> [a] -> [[a]]
+ Data.List.Extra: instance GHC.Show.Show Data.List.Extra.Color
+ Data.List.Extra: instance GHC.Show.Show a => GHC.Show.Show (Data.List.Extra.RB a)
+ Data.List.Extra: nubOrd :: Ord a => [a] -> [a]
+ Data.List.Extra: nubOrdBy :: (a -> a -> Ordering) -> [a] -> [a]
+ Data.List.Extra: nubOrdOn :: Ord b => (a -> b) -> [a] -> [a]
+ Data.List.Extra: splitAtEnd :: Int -> [a] -> ([a], [a])
+ Extra: groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]
+ Extra: groupSortOn :: Ord b => (a -> b) -> [a] -> [[a]]
+ Extra: nubOrd :: Ord a => [a] -> [a]
+ Extra: nubOrdBy :: (a -> a -> Ordering) -> [a] -> [a]
+ Extra: nubOrdOn :: Ord b => (a -> b) -> [a] -> [a]
+ Extra: splitAtEnd :: Int -> [a] -> ([a], [a])
+ System.Time.Extra: instance GHC.Classes.Eq System.Time.Extra.Timeout
+ System.Time.Extra: instance GHC.Exception.Exception System.Time.Extra.Timeout
+ System.Time.Extra: instance GHC.Show.Show System.Time.Extra.Timeout

Files

CHANGES.txt view
@@ -1,5 +1,9 @@ Changelog for Extra +1.1+    #7, add nubOrd, nubOrdOn, nubOrdBy+    #6, add groupSortOn and groupSortBy+    #5, add splitAtEnd 1.0.1     Make listFilesAvoid drop trailing path separators before testing     #3, add a constraint base >= 4.4
LICENSE view
@@ -1,4 +1,4 @@-Copyright Neil Mitchell 2014.+Copyright Neil Mitchell 2014-2015. All rights reserved.  Redistribution and use in source and binary forms, with or without
extra.cabal view
@@ -1,13 +1,13 @@ cabal-version:      >= 1.10 build-type:         Simple name:               extra-version:            1.0.1+version:            1.1 license:            BSD3 license-file:       LICENSE category:           Development author:             Neil Mitchell <ndmitchell@gmail.com> maintainer:         Neil Mitchell <ndmitchell@gmail.com>-copyright:          Neil Mitchell 2014+copyright:          Neil Mitchell 2014-2015 synopsis:           Extra functions I use. description:     A library of extra functions for the standard Haskell libraries. Most functions are simple additions, filling out missing functionality. A few functions are available in later versions of GHC, but this package makes them available back to GHC 7.2.
src/Control/Monad/Extra.hs view
@@ -32,7 +32,7 @@ whenJust mg f = maybe (pure ()) f mg  -- | The identity function which requires the inner argument to be @()@. Useful for functions---   with overloaded return times.+--   with overloaded return types. -- -- > \(x :: Maybe ()) -> unit x == x unit :: m () -> m ()
src/Data/List/Extra.hs view
@@ -10,14 +10,16 @@     -- * String operations     lower, upper, trim, trimStart, trimEnd, word1,     -- * Splitting    -    dropEnd, takeEnd, breakEnd, spanEnd,+    dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd,     dropWhileEnd, dropWhileEnd', takeWhileEnd, stripSuffix,     wordsBy, linesBy,     breakOn, breakOnEnd, splitOn, split, chunksOf,     -- * Basics     list, uncons, unsnoc, cons, snoc, drop1,     -- * List operations-    groupSort, nubOn, groupOn, sortOn,+    groupSort, groupSortOn, groupSortBy,+    nubOrd, nubOrdBy, nubOrdOn,+    nubOn, groupOn, sortOn,     disjoint, allSame, anySame,     repeatedly, for, firstJust,     concatUnzip, concatUnzip3,@@ -153,6 +155,19 @@           f _ _ = []  +-- | @'splitAtEnd' n xs@ returns a split where the second element tries to+--   contain @n@ elements.+--+-- > splitAtEnd 3 "hello" == ("he","llo")+-- > splitAtEnd 3 "he"    == ("", "he")+-- > \i xs -> uncurry (++) (splitAt i xs) == xs+-- > \i xs -> splitAtEnd i xs == (dropEnd i xs, takeEnd i xs)+splitAtEnd :: Int -> [a] -> ([a], [a])+splitAtEnd i xs = f xs (drop i xs)+    where f (x:xs) (y:ys) = first (x:) $ f xs ys+          f xs _ = ([], xs)++ -- | A merging of 'unzip' and 'concat'. -- -- > concatUnzip [("a","AB"),("bc","C")] == ("abc","ABC")@@ -244,6 +259,7 @@ nubOn :: Eq b => (a -> b) -> [a] -> [a] nubOn f = map snd . nubBy ((==) `on` fst) . map (\x -> let y = f x in y `seq` (y, x)) + -- | A combination of 'group' and 'sort'. -- -- > groupSort [(1,'t'),(3,'t'),(2,'e'),(2,'s')] == [(1,"t"),(2,"es"),(3,"t")]@@ -252,7 +268,19 @@ groupSort :: Ord k => [(k, v)] -> [(k, [v])] groupSort = map (\x -> (fst $ head x, map snd x)) . groupOn fst . sortOn fst +-- | A combination of 'group' and 'sort', using a part of the value to compare on.+--+-- > groupSortOn length ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]+groupSortOn :: Ord b => (a -> b) -> [a] -> [[a]]+groupSortOn f = map (map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst) . map (f &&& id) +-- | A combination of 'group' and 'sort', using a predicate to compare on.+--+-- > groupSortBy (compare `on` length) ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]+groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]+groupSortBy f = groupBy (\a b -> f a b == EQ) . sortBy f++ -- | Merge two lists which are assumed to be ordered. -- -- > merge "ace" "bd" == "abcde"@@ -449,3 +477,70 @@ chunksOf :: Int -> [a] -> [[a]] chunksOf i xs | i <= 0 = error $ "chunksOf, number must be positive, got " ++ show i chunksOf i xs = repeatedly (splitAt i) xs+++-- | /O(n log n)/. The 'nubOrd' function removes duplicate elements from a list.+-- In particular, it keeps only the first occurrence of each element.+-- Unlike the standard 'nub' operator, this version requires an 'Ord' instance+-- and consequently runs asymptotically faster.+--+-- > nubOrd "this is a test" == "this ae"+-- > nubOrd (take 4 ("this" ++ undefined)) == "this"+-- > \xs -> nubOrd xs == nub xs+nubOrd :: Ord a => [a] -> [a]+nubOrd = nubOrdBy compare++-- | A version of 'nubOrd' which operates on a portion of the value.+--+-- > nubOrdOn length ["a","test","of","this"] == ["a","test","of"]+nubOrdOn :: Ord b => (a -> b) -> [a] -> [a]+nubOrdOn f = map snd . nubOrdBy (compare `on` fst) . map (f &&& id)++-- | A version of 'nubOrd' with a custom predicate.+--+-- > nubOrdBy (compare `on` length) ["a","test","of","this"] == ["a","test","of"]+nubOrdBy :: (a -> a -> Ordering) -> [a] -> [a]+nubOrdBy cmp xs = f E xs+    where f seen [] = []+          f seen (x:xs) | memberRB cmp x seen = f seen xs+                        | otherwise = x : f (insertRB cmp x seen) xs++---------------------------------------------------------------------+-- OKASAKI RED BLACK TREE+-- Taken from http://www.cs.kent.ac.uk/people/staff/smk/redblack/Untyped.hs++data Color = R | B deriving Show+data RB a = E | T Color (RB a) a (RB a) deriving Show++{- Insertion and membership test as by Okasaki -}+insertRB :: (a -> a -> Ordering) -> a -> RB a -> RB a+insertRB cmp x s =+    T B a z b+    where+    T _ a z b = ins s+    ins E = T R E x E+    ins s@(T B a y b) = case cmp x y of+        LT -> balance (ins a) y b+        GT -> balance a y (ins b)+        EQ -> s+    ins s@(T R a y b) = case cmp x y of+        LT -> T R (ins a) y b+        GT -> T R a y (ins b)+        EQ -> s++memberRB :: (a -> a -> Ordering) -> a -> RB a -> Bool+memberRB cmp x E = False+memberRB cmp x (T _ a y b) = case cmp x y of+    LT -> memberRB cmp x a+    GT -> memberRB cmp x b+    EQ -> True++{- balance: first equation is new,+   to make it work with a weaker invariant -}+balance :: RB a -> a -> RB a -> RB a+balance (T R a x b) y (T R c z d) = T R (T B a x b) y (T B c z d)+balance (T R (T R a x b) y c) z d = T R (T B a x b) y (T B c z d)+balance (T R a x (T R b y c)) z d = T R (T B a x b) y (T B c z d)+balance a x (T R b y (T R c z d)) = T R (T B a x b) y (T B c z d)+balance a x (T R (T R b y c) z d) = T R (T B a x b) y (T B c z d)+balance a x b = T B a x b
src/Extra.hs view
@@ -20,7 +20,7 @@     modifyIORef', writeIORef', atomicModifyIORef', atomicWriteIORef, atomicWriteIORef',     -- * Data.List.Extra     -- | Extra functions available in @"Data.List.Extra"@.-    lower, upper, trim, trimStart, trimEnd, word1, dropEnd, takeEnd, breakEnd, spanEnd, dropWhileEnd, dropWhileEnd', takeWhileEnd, stripSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, list, uncons, unsnoc, cons, snoc, drop1, groupSort, nubOn, groupOn, sortOn, disjoint, allSame, anySame, repeatedly, for, firstJust, concatUnzip, concatUnzip3, replace, merge, mergeBy,+    lower, upper, trim, trimStart, trimEnd, word1, dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd, dropWhileEnd, dropWhileEnd', takeWhileEnd, stripSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, list, uncons, unsnoc, cons, snoc, drop1, groupSort, groupSortOn, groupSortBy, nubOrd, nubOrdBy, nubOrdOn, nubOn, groupOn, sortOn, disjoint, allSame, anySame, repeatedly, for, firstJust, concatUnzip, concatUnzip3, replace, merge, mergeBy,     -- * Data.Tuple.Extra     -- | Extra functions available in @"Data.Tuple.Extra"@.     first, second, (***), (&&&), dupe, both, fst3, snd3, thd3,
test/TestGen.hs view
@@ -84,6 +84,10 @@     testGen "\\i xs -> dropEnd i xs `isPrefixOf` xs" $ \i xs -> dropEnd i xs `isPrefixOf` xs     testGen "\\i xs -> length (dropEnd i xs) == max 0 (length xs - max 0 i)" $ \i xs -> length (dropEnd i xs) == max 0 (length xs - max 0 i)     testGen "\\i -> take 3 (dropEnd 5 [i..]) == take 3 [i..]" $ \i -> take 3 (dropEnd 5 [i..]) == take 3 [i..]+    testGen "splitAtEnd 3 \"hello\" == (\"he\",\"llo\")" $ splitAtEnd 3 "hello" == ("he","llo")+    testGen "splitAtEnd 3 \"he\"    == (\"\", \"he\")" $ splitAtEnd 3 "he"    == ("", "he")+    testGen "\\i xs -> uncurry (++) (splitAt i xs) == xs" $ \i xs -> uncurry (++) (splitAt i xs) == xs+    testGen "\\i xs -> splitAtEnd i xs == (dropEnd i xs, takeEnd i xs)" $ \i xs -> splitAtEnd i xs == (dropEnd i xs, takeEnd i xs)     testGen "concatUnzip [(\"a\",\"AB\"),(\"bc\",\"C\")] == (\"abc\",\"ABC\")" $ concatUnzip [("a","AB"),("bc","C")] == ("abc","ABC")     testGen "concatUnzip3 [(\"a\",\"AB\",\"\"),(\"bc\",\"C\",\"123\")] == (\"abc\",\"ABC\",\"123\")" $ concatUnzip3 [("a","AB",""),("bc","C","123")] == ("abc","ABC","123")     testGen "takeWhileEnd even [2,3,4,6] == [4,6]" $ takeWhileEnd even [2,3,4,6] == [4,6]@@ -104,6 +108,8 @@     testGen "groupSort [(1,'t'),(3,'t'),(2,'e'),(2,'s')] == [(1,\"t\"),(2,\"es\"),(3,\"t\")]" $ groupSort [(1,'t'),(3,'t'),(2,'e'),(2,'s')] == [(1,"t"),(2,"es"),(3,"t")]     testGen "\\xs -> map fst (groupSort xs) == sort (nub (map fst xs))" $ \xs -> map fst (groupSort xs) == sort (nub (map fst xs))     testGen "\\xs -> concatMap snd (groupSort xs) == map snd (sortOn fst xs)" $ \xs -> concatMap snd (groupSort xs) == map snd (sortOn fst xs)+    testGen "groupSortOn length [\"test\",\"of\",\"sized\",\"item\"] == [[\"of\"],[\"test\",\"item\"],[\"sized\"]]" $ groupSortOn length ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]+    testGen "groupSortBy (compare `on` length) [\"test\",\"of\",\"sized\",\"item\"] == [[\"of\"],[\"test\",\"item\"],[\"sized\"]]" $ groupSortBy (compare `on` length) ["test","of","sized","item"] == [["of"],["test","item"],["sized"]]     testGen "merge \"ace\" \"bd\" == \"abcde\"" $ merge "ace" "bd" == "abcde"     testGen "\\xs ys -> merge (sort xs) (sort ys) == sort (xs ++ ys)" $ \xs ys -> merge (sort xs) (sort ys) == sort (xs ++ ys)     testGen "replace \"el\" \"_\" \"Hello Bella\" == \"H_lo B_la\"" $ replace "el" "_" "Hello Bella" == "H_lo B_la"@@ -153,6 +159,11 @@     testGen "chunksOf 3 \"mytest\"  == [\"myt\",\"est\"]" $ chunksOf 3 "mytest"  == ["myt","est"]     testGen "chunksOf 8 \"\"        == []" $ chunksOf 8 ""        == []     testGen "chunksOf 0 \"test\"    == undefined" $ erroneous $ chunksOf 0 "test"+    testGen "nubOrd \"this is a test\" == \"this ae\"" $ nubOrd "this is a test" == "this ae"+    testGen "nubOrd (take 4 (\"this\" ++ undefined)) == \"this\"" $ nubOrd (take 4 ("this" ++ undefined)) == "this"+    testGen "\\xs -> nubOrd xs == nub xs" $ \xs -> nubOrd xs == nub xs+    testGen "nubOrdOn length [\"a\",\"test\",\"of\",\"this\"] == [\"a\",\"test\",\"of\"]" $ nubOrdOn length ["a","test","of","this"] == ["a","test","of"]+    testGen "nubOrdBy (compare `on` length) [\"a\",\"test\",\"of\",\"this\"] == [\"a\",\"test\",\"of\"]" $ nubOrdBy (compare `on` length) ["a","test","of","this"] == ["a","test","of"]     testGen "first succ (1,\"test\") == (2,\"test\")" $ first succ (1,"test") == (2,"test")     testGen "second reverse (1,\"test\") == (1,\"tset\")" $ second reverse (1,"test") == (1,"tset")     testGen "(succ *** reverse) (1,\"test\") == (2,\"tset\")" $ (succ *** reverse) (1,"test") == (2,"tset")
test/TestUtil.hs view
@@ -15,6 +15,7 @@ import Extra as X import Control.Applicative as X import Control.Monad as X+import Data.Function as X import Data.List as X import Data.Char as X import Data.Tuple as X