utility-ht 0.0.11 → 0.0.12
raw patch · 17 files changed
+477/−47 lines, 17 files
Files
- src/Control/Applicative/HT.hs +31/−0
- src/Control/Functor/HT.hs +18/−0
- src/Control/Monad/HT.hs +10/−0
- src/Data/Bits/HT.hs +20/−0
- src/Data/List/HT.hs +14/−2
- src/Data/List/HT/Private.hs +71/−25
- src/Data/List/Reverse/StrictElement.hs +44/−0
- src/Data/List/Reverse/StrictSpine.hs +41/−0
- src/Data/String/HT.hs +9/−3
- src/Data/Tuple/HT.hs +5/−0
- src/Data/Tuple/Lazy.hs +14/−5
- src/Data/Tuple/Strict.hs +12/−3
- src/Test.hs +4/−0
- src/Test/Data/List.hs +60/−7
- src/Test/Data/List/Reverse/StrictElement.hs +53/−0
- src/Test/Data/List/Reverse/StrictSpine.hs +62/−0
- utility-ht.cabal +9/−2
+ src/Control/Applicative/HT.hs view
@@ -0,0 +1,31 @@+module Control.Applicative.HT where++import qualified Data.Tuple.HT as Tuple++import Control.Applicative (Applicative, liftA2, liftA3, (<$>), (<*>), )++mapPair :: (Applicative f) => (a -> f c, b -> f d) -> (a,b) -> f (c,d)+mapPair fg = uncurry (liftA2 (,)) . Tuple.mapPair fg++mapTriple ::+ (Applicative m) => (a -> m d, b -> m e, c -> m f) -> (a,b,c) -> m (d,e,f)+mapTriple fgh = Tuple.uncurry3 (liftA3 (,,)) . Tuple.mapTriple fgh+++{-# INLINE liftA4 #-}+liftA4 :: Applicative f =>+ (a -> b -> c -> d -> e) ->+ f a -> f b -> f c -> f d -> f e+liftA4 f a b c d = f <$> a <*> b <*> c <*> d++{-# INLINE liftA5 #-}+liftA5 :: Applicative f =>+ (a -> b -> c -> d -> e -> g) ->+ f a -> f b -> f c -> f d -> f e -> f g+liftA5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e++{-# INLINE liftA6 #-}+liftA6 :: Applicative f =>+ (a -> b -> c -> d -> e -> g -> h) ->+ f a -> f b -> f c -> f d -> f e -> f g -> f h+liftA6 f a b c d e g = f <$> a <*> b <*> c <*> d <*> e <*> g
src/Control/Functor/HT.hs view
@@ -28,6 +28,24 @@ unzip3 :: Functor f => f (a, b, c) -> (f a, f b, f c) unzip3 x = (fmap fst3 x, fmap snd3 x, fmap thd3 x) ++mapFst :: Functor f => (a -> f c) -> (a, b) -> f (c, b)+mapFst f ~(a,b) = fmap (flip (,) b) $ f a++mapSnd :: Functor f => (b -> f c) -> (a, b) -> f (a, c)+mapSnd f ~(a,b) = fmap ((,) a) $ f b+++mapFst3 :: Functor f => (a -> f d) -> (a,b,c) -> f (d,b,c)+mapFst3 f ~(a,b,c) = fmap (\x -> (x,b,c)) $ f a++mapSnd3 :: Functor f => (b -> f d) -> (a,b,c) -> f (a,d,c)+mapSnd3 f ~(a,b,c) = fmap (\x -> (a,x,c)) $ f b++mapThd3 :: Functor f => (c -> f d) -> (a,b,c) -> f (a,b,d)+mapThd3 f ~(a,b,c) = fmap ((,,) a b) $ f c++ {- | Generalization of 'Data.List.HT.outerProduct'. -}
src/Control/Monad/HT.hs view
@@ -45,6 +45,15 @@ in aux m {- |+I think this makes only sense in a lazy monad+like @Trans.State.Lazy@ or @IO.Lazy@.+-}+iterate :: Monad m => (a -> m a) -> a -> m [a]+iterate f =+ let go x = lift (x:) $ go =<< f x+ in go++{- | Lazy monadic conjunction. That is, when the first action returns @False@, then @False@ is immediately returned, without running the second action.@@ -84,6 +93,7 @@ chain :: (Monad m) => [a -> m a] -> (a -> m a) chain = foldr (flip (<=<)) return +-- there is also mfilter, but this should be part of Control.Monad.Plus filter :: Monad m => (a -> m Bool) -> [a] -> m [a] filter = M.filterM
+ src/Data/Bits/HT.hs view
@@ -0,0 +1,20 @@+module Data.Bits.HT where++import Data.Bits (Bits, shiftL, shiftR)+++infixl 7 .<<., .>>.++{- |+Infix variant of 'shiftL'.+Precedence is chosen like multiplication since @a .<<. k == a * 2^k@.+-}+(.<<.) :: Bits a => a -> Int -> a+(.<<.) = shiftL++{- |+Infix variant of 'shiftR'.+Precedence is chosen like division since @a .>>. k == a / 2^k@.+-}+(.>>.) :: Bits a => a -> Int -> a+(.>>.) = shiftR
src/Data/List/HT.hs view
@@ -11,6 +11,7 @@ -- * Split L.chop, L.breakAfter,+ L.takeUntil, L.segmentAfter, L.segmentBefore, L.segmentAfterMaybe,@@ -26,10 +27,12 @@ -- * List processing starting at the end L.dropRev, L.takeRev,- L.dropWhileRev,- L.takeWhileRev,+ L.splitAtRev,+ dropWhileRev,+ takeWhileRev, -- * List processing with Maybe and Either L.maybePrefixOf,+ L.maybeSuffixOf, L.partitionMaybe, L.takeWhileJust, L.unzipEithers,@@ -63,3 +66,12 @@ ) where import qualified Data.List.HT.Private as L+import qualified Data.List.Reverse.StrictElement as Rev++{-# DEPRECATED dropWhileRev "Use dropWhile from Data.List.Reverse.StrictElement or Data.List.Reverse.StrictSpine instead" #-}+dropWhileRev :: (a -> Bool) -> [a] -> [a]+dropWhileRev = Rev.dropWhile++{-# DEPRECATED takeWhileRev "Use takeWhile from Data.List.Reverse.StrictElement or Data.List.Reverse.StrictSpine instead" #-}+takeWhileRev :: (a -> Bool) -> [a] -> [a]+takeWhileRev = Rev.takeWhile
src/Data/List/HT/Private.hs view
@@ -5,10 +5,12 @@ import Data.Maybe as Maybe (fromMaybe, catMaybes, ) import Data.Maybe.HT (toMaybe, ) import Control.Monad (guard, msum, )+import Control.Applicative ((<*>), ) import Data.Tuple.HT (mapPair, mapFst, mapSnd, forcePair, swap, ) import qualified Data.List.Key.Private as Key import qualified Data.List.Match.Private as Match+import qualified Data.List.Reverse.StrictElement as Rev import Prelude hiding (unzip, break, span, ) @@ -180,7 +182,7 @@ in recourse -chopAtRun :: (Eq a) => (a -> Bool) -> [a] -> [[a]]+chopAtRun :: (a -> Bool) -> [a] -> [[a]] chopAtRun p = let recourse [] = [[]] recourse y =@@ -193,7 +195,10 @@ Like 'break', but splits after the matching element. -} breakAfter :: (a -> Bool) -> [a] -> ([a], [a])-breakAfter p =+breakAfter = breakAfterRec++breakAfterRec :: (a -> Bool) -> [a] -> ([a], [a])+breakAfterRec p = let recourse [] = ([],[]) recourse (x:xs) = mapFst (x:) $@@ -202,8 +207,40 @@ else recourse xs in forcePair . recourse +{-+The use of 'foldr' might allow for fusion,+but unfortunately this simple implementation would copy the tail of the list.+-}+breakAfterFoldr :: (a -> Bool) -> [a] -> ([a], [a])+breakAfterFoldr p =+ forcePair .+ foldr+ (\x yzs -> mapFst (x:) $ if p x then ([], uncurry (++) yzs) else yzs)+ ([],[]) +breakAfterBreak :: (a -> Bool) -> [a] -> ([a], [a])+breakAfterBreak p xs =+ case break p xs of+ (ys, []) -> (ys, [])+ (ys, z:zs) -> (ys++[z], zs)++breakAfterTakeUntil :: (a -> Bool) -> [a] -> ([a], [a])+breakAfterTakeUntil p xs =+ forcePair $+ (\ys -> (map fst ys, maybe [] (snd . snd) $ viewR ys)) $+ takeUntil (p . fst) $ zip xs $ tail $ tails xs+ {- |+Take all elements until one matches.+The matching element is returned, too.+This is the key difference to @takeWhile (not . p)@.+It holds @takeUntil p xs == fst (breakAfter p xs)@.+-}+takeUntil :: (a -> Bool) -> [a] -> [a]+takeUntil p = foldr (\x ys -> x : if p x then [] else ys) []+++{- | Split the list after each occurence of a terminator. Keep the terminator. There is always a list for the part after the last terminator.@@ -452,43 +489,39 @@ dropRev :: Int -> [a] -> [a] dropRev n xs = Match.take (drop n xs) xs - {- |-Remove the longest suffix of elements satisfying p.-In contrast to @reverse . dropWhile p . reverse@-this works for infinite lists, too.+@splitAtRev n xs == (dropRev n xs, takeRev n xs)@.+It holds @xs == uncurry (++) (splitAtRev n xs)@ -}+splitAtRev :: Int -> [a] -> ([a], [a])+splitAtRev n xs = Match.splitAt (drop n xs) xs++ dropWhileRev :: (a -> Bool) -> [a] -> [a] dropWhileRev p =- foldr (\x xs -> if p x && null xs then [] else x:xs) []--dropWhileRev' :: (a -> Bool) -> [a] -> [a]-dropWhileRev' p = concat . init . segmentAfter (not . p) -{- |-Alternative version of @reverse . takeWhile p . reverse@.--}-takeWhileRev :: (a -> Bool) -> [a] -> [a]-takeWhileRev p =+takeWhileRev0 :: (a -> Bool) -> [a] -> [a]+takeWhileRev0 p = last . segmentAfter (not . p) {- | Doesn't seem to be superior to the naive implementation. -}-takeWhileRev' :: (a -> Bool) -> [a] -> [a]-takeWhileRev' p =- (\xs -> if fst (head xs)- then map snd xs- else []) .- last . Key.aux groupBy (==) p+takeWhileRev1 :: (a -> Bool) -> [a] -> [a]+takeWhileRev1 p =+ (\mx ->+ case mx of+ Just (_, xs@((True,_):_)) -> map snd xs+ _ -> []) .+ viewR . Key.aux groupBy (==) p {- | However it is more inefficient, because of repeatedly appending single elements. :-( -}-takeWhileRev'' :: (a -> Bool) -> [a] -> [a]-takeWhileRev'' p =+takeWhileRev2 :: (a -> Bool) -> [a] -> [a]+takeWhileRev2 p = foldl (\xs x -> if p x then xs++[x] else []) [] @@ -498,12 +531,18 @@ @maybePrefixOf xs ys@ is @Just zs@ if @xs@ is a prefix of @ys@, where @zs@ is @ys@ without the prefix @xs@. Otherwise it is @Nothing@.+It is the same as 'Data.List.stripPrefix'. -} maybePrefixOf :: Eq a => [a] -> [a] -> Maybe [a] maybePrefixOf (x:xs) (y:ys) = guard (x==y) >> maybePrefixOf xs ys maybePrefixOf [] ys = Just ys maybePrefixOf _ [] = Nothing +maybeSuffixOf :: Eq a => [a] -> [a] -> Maybe [a]+maybeSuffixOf xs ys =+ fmap reverse $ maybePrefixOf (reverse xs) (reverse ys)++ {- | Partition a list into elements which evaluate to @Just@ or @Nothing@ by @f@. @@ -699,7 +738,7 @@ transposeFill = unfoldr (\xs -> toMaybe (not (null xs))- (mapSnd (dropWhileRev null) $ unzipCons xs))+ (mapSnd (Rev.dropWhile null) $ unzipCons xs)) unzipCons :: [[a]] -> ([Maybe a], [[a]]) unzipCons =@@ -732,7 +771,7 @@ zipConc (a:as) (b:bs) = (a++b) : zipConc as bs zipConc [] bs = bs zipConc as [] = as- in y : zipConc ys (shear' (dropWhileRev null zs))+ in y : zipConc ys (shear' (Rev.dropWhile null zs)) {- Dropping trailing empty lists is necessary, otherwise finite lists are filled with empty lists. -} shear' [] = []@@ -945,6 +984,13 @@ -} mapAdjacent :: (a -> a -> b) -> [a] -> [b] mapAdjacent f xs = zipWith f xs (tail xs)++{- |+<http://mail.haskell.org/libraries/2016-April/026912.html>+-}+mapAdjacentPointfree :: (a -> a -> b) -> [a] -> [b]+mapAdjacentPointfree f = zipWith f <*> tail+ {- | > mapAdjacent f a0 [(a1,b1), (a2,b2), (a3,b3)]
+ src/Data/List/Reverse/StrictElement.hs view
@@ -0,0 +1,44 @@+{- |+The functions in this module process the list formally from the end.+Actually they traverse the list from the start and check every element.+This way they are strict in the elements and lazy in the list spline.+Thus you can apply them to infinite lists.+Use these functions if the list is long or the test is cheap.+-}+module Data.List.Reverse.StrictElement where++import Data.Tuple.HT (mapFst, mapSnd, forcePair, )++import Prelude hiding (dropWhile, takeWhile, span, )+++{- |+Remove the longest suffix of elements satisfying p.+In contrast to @reverse . dropWhile p . reverse@+this works for infinite lists, too.+-}+dropWhile :: (a -> Bool) -> [a] -> [a]+dropWhile p =+ foldr (\x xs -> if p x && null xs then [] else x:xs) []++{- |+Alternative version of @reverse . takeWhile p . reverse@.+-}+takeWhile :: (a -> Bool) -> [a] -> [a]+takeWhile p =+ snd .+ foldr+ (\x xys ->+ (if p x && fst xys then mapSnd (x:) else mapFst (const False)) xys)+ (True, [])++{- |+@span p xs == (dropWhile p xs, takeWhile p xs)@+-}+span :: (a -> Bool) -> [a] -> ([a], [a])+span p =+ forcePair .+ foldr+ (\x xys ->+ (if p x && null (fst xys) then mapSnd else mapFst) (x:) xys)+ ([], [])
+ src/Data/List/Reverse/StrictSpine.hs view
@@ -0,0 +1,41 @@+{- |+The functions in this module process the list from the end.+They do not access elements at the beginning if not necessary.+You can apply the function only to infinite lists.+Use these functions if the list is short and the test is expensive.+-}+module Data.List.Reverse.StrictSpine where++import Data.Tuple.HT (mapFst, mapSnd, forcePair, )++import Prelude hiding (dropWhile, takeWhile, span, )+++{- |+Like @reverse . List.dropWhile p . reverse@.+-}+dropWhile :: (a -> Bool) -> [a] -> [a]+dropWhile p =+ foldr (\x xs -> if null xs && p x then [] else x:xs) []++{- |+Like @reverse . List.takeWhile p . reverse@.+-}+takeWhile :: (a -> Bool) -> [a] -> [a]+takeWhile p =+ snd .+ foldr+ (\x xys ->+ (if fst xys && p x then mapSnd (x:) else mapFst (const False)) xys)+ (True, [])++{- |+@span p xs == (dropWhile p xs, takeWhile p xs)@+-}+span :: (a -> Bool) -> [a] -> ([a], [a])+span p =+ forcePair .+ foldr+ (\x xys ->+ (if null (fst xys) && p x then mapSnd else mapFst) (x:) xys)+ ([], [])
src/Data/String/HT.hs view
@@ -1,8 +1,14 @@ module Data.String.HT where +import qualified Data.List.Reverse.StrictSpine as Rev import Data.Char (isSpace, )-import Data.List.HT (dropWhileRev, ) --- | remove leading and trailing spaces+{- |+Remove leading and trailing spaces.++We use spine strict 'Rev.dropWhile' instead of the element strict version.+This is more efficient for finite 'String's because 'isSpace' is expensive.+The downside is that 'trim' does not work for infinite 'String's.+-} trim :: String -> String-trim = dropWhileRev isSpace . dropWhile isSpace+trim = Rev.dropWhile isSpace . dropWhile isSpace
src/Data/Tuple/HT.hs view
@@ -4,6 +4,7 @@ mapFst, mapSnd, swap,+ sortPair, forcePair, -- * Triple@@ -36,3 +37,7 @@ {-# INLINE curry3 #-} curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d curry3 f a b c = f (a,b,c)++sortPair, _sortPairMinMax :: (Ord a) => (a,a) -> (a,a)+sortPair (x,y) = if x<=y then (x,y) else (y,x)+_sortPairMinMax (x,y) = (min x y, max x y)
src/Data/Tuple/Lazy.hs view
@@ -15,12 +15,12 @@ where one variant is definitely better than the other one. -} {--Instead of lazy pattern matching with \code{(x,y)}+Instead of lazy pattern matching with \code{(a,b)} we may use \function{fst} and \function{snd}. -} {-# INLINE mapPair #-} mapPair :: (a -> c, b -> d) -> (a,b) -> (c,d)-mapPair ~(f,g) ~(x,y) = (f x, g y)+mapPair ~(f,g) ~(a,b) = (f a, g b) -- | 'Control.Arrow.first' {-# INLINE mapFst #-}@@ -32,21 +32,25 @@ mapSnd :: (b -> c) -> (a,b) -> (a,c) mapSnd f ~(a,b) = (a, f b) +{-# INLINE zipWithPair #-}+zipWithPair :: (a -> c -> e, b -> d -> f) -> (a,b) -> (c,d) -> (e,f)+zipWithPair ~(e,f) ~(a,b) ~(c,d) = (e a c, f b d) + {-# INLINE swap #-} swap :: (a,b) -> (b,a)-swap ~(x,y) = (y,x)+swap ~(a,b) = (b,a) {-# INLINE forcePair #-} forcePair :: (a,b) -> (a,b)-forcePair ~(x,y) = (x,y)+forcePair ~(a,b) = (a,b) -- * Triple {-# INLINE mapTriple #-} mapTriple :: (a -> d, b -> e, c -> f) -> (a,b,c) -> (d,e,f)-mapTriple ~(f,g,h) ~(x,y,z) = (f x, g y, h z)+mapTriple ~(f,g,h) ~(a,b,c) = (f a, g b, h c) {-# INLINE mapFst3 #-} mapFst3 :: (a -> d) -> (a,b,c) -> (d,b,c)@@ -59,6 +63,11 @@ {-# INLINE mapThd3 #-} mapThd3 :: (c -> d) -> (a,b,c) -> (a,b,d) mapThd3 f ~(a,b,c) = (a, b, f c)++{-# INLINE zipWithTriple #-}+zipWithTriple ::+ (a -> d -> g, b -> e -> h, c -> f -> i) -> (a,b,c) -> (d,e,f) -> (g,h,i)+zipWithTriple ~(g,h,i) ~(a,b,c) ~(d,e,f) = (g a d, h b e, i c f) {-# INLINE uncurry3 #-} uncurry3 :: (a -> b -> c -> d) -> ((a, b, c) -> d)
src/Data/Tuple/Strict.hs view
@@ -4,7 +4,7 @@ {-# INLINE mapPair #-} mapPair :: (a -> c, b -> d) -> (a,b) -> (c,d)-mapPair (f,g) (x,y) = (f x, g y)+mapPair (f,g) (a,b) = (f a, g b) {-# INLINE mapFst #-} mapFst :: (a -> c) -> (a,b) -> (c,b)@@ -14,17 +14,21 @@ mapSnd :: (b -> c) -> (a,b) -> (a,c) mapSnd f (a,b) = (a, f b) +{-# INLINE zipWithPair #-}+zipWithPair :: (a -> c -> e, b -> d -> f) -> (a,b) -> (c,d) -> (e,f)+zipWithPair (e,f) (a,b) (c,d) = (e a c, f b d) + {-# INLINE swap #-} swap :: (a,b) -> (b,a)-swap (x,y) = (y,x)+swap (a,b) = (b,a) -- * Triple {-# INLINE mapTriple #-} mapTriple :: (a -> d, b -> e, c -> f) -> (a,b,c) -> (d,e,f)-mapTriple (f,g,h) (x,y,z) = (f x, g y, h z)+mapTriple (f,g,h) (a,b,c) = (f a, g b, h c) {-# INLINE mapFst3 #-} mapFst3 :: (a -> d) -> (a,b,c) -> (d,b,c)@@ -37,6 +41,11 @@ {-# INLINE mapThd3 #-} mapThd3 :: (c -> d) -> (a,b,c) -> (a,b,d) mapThd3 f (a,b,c) = (a, b, f c)++{-# INLINE zipWithTriple #-}+zipWithTriple ::+ (a -> d -> g, b -> e -> h, c -> f -> i) -> (a,b,c) -> (d,e,f) -> (g,h,i)+zipWithTriple (g,h,i) (a,b,c) (d,e,f) = (g a d, h b e, i c f) {-# INLINE uncurry3 #-} uncurry3 :: (a -> b -> c -> d) -> ((a, b, c) -> d)
src/Test.hs view
@@ -1,5 +1,7 @@ module Main where +import qualified Test.Data.List.Reverse.StrictElement as RevElem+import qualified Test.Data.List.Reverse.StrictSpine as RevSpine import qualified Test.Data.List as ListHT import qualified Test.Data.ListMatch as ListMatch import qualified Test.Data.Maybe as MaybeHT@@ -14,6 +16,8 @@ main = mapM_ (\(msg,io) -> putStr (msg++": ") >> io) $ concat $+ prefix "ReverseSpine" RevSpine.tests :+ prefix "ReverseElem" RevElem.tests : prefix "List" ListHT.tests : prefix "ListMatch" ListMatch.tests : prefix "Maybe" MaybeHT.tests :
src/Test/Data/List.hs view
@@ -1,5 +1,6 @@ module Test.Data.List where +import qualified Data.List.Reverse.StrictElement as Rev import qualified Data.List.HT.Private as ListHT import qualified Data.List as List import Control.Monad (liftM2, )@@ -11,13 +12,21 @@ -takeWhileRev :: (Ord a) => (a -> Bool) -> [a] -> Bool-takeWhileRev p xs =- ListHT.takeWhileRev p xs == reverse (takeWhile p (reverse xs))+takeWhileRev0 :: (Eq a) => (a -> Bool) -> [a] -> Bool+takeWhileRev0 p xs =+ ListHT.takeWhileRev0 p xs == Rev.takeWhile p xs -dropWhileRev :: (Ord a) => (a -> Bool) -> [a] -> Bool+takeWhileRev1 :: (Eq a) => (a -> Bool) -> [a] -> Bool+takeWhileRev1 p xs =+ ListHT.takeWhileRev1 p xs == Rev.takeWhile p xs++takeWhileRev2 :: (Eq a) => (a -> Bool) -> [a] -> Bool+takeWhileRev2 p xs =+ ListHT.takeWhileRev2 p xs == Rev.takeWhile p xs++dropWhileRev :: (Eq a) => (a -> Bool) -> [a] -> Bool dropWhileRev p xs =- ListHT.dropWhileRev p xs == reverse (dropWhile p (reverse xs))+ ListHT.dropWhileRev p xs == Rev.dropWhile p xs takeRev :: (Eq a) => Int -> [a] -> Bool@@ -28,7 +37,32 @@ dropRev n xs = ListHT.dropRev n xs == reverse (drop n (reverse xs)) +splitAtRev :: (Eq a) => Int -> [a] -> Bool+splitAtRev n xs =+ xs == uncurry (++) (ListHT.splitAtRev n xs) ++breakAfterAppend :: (Eq a) => (a -> Bool) -> [a] -> Bool+breakAfterAppend p xs =+ uncurry (++) (ListHT.breakAfter p xs) == xs++breakAfter0 :: (Eq a) => (a -> Bool) -> [a] -> Bool+breakAfter0 p xs =+ ListHT.breakAfterRec p xs == ListHT.breakAfterFoldr p xs++breakAfter1 :: (Eq a) => (a -> Bool) -> [a] -> Bool+breakAfter1 p xs =+ ListHT.breakAfterRec p xs == ListHT.breakAfterBreak p xs++breakAfter2 :: (Eq a) => (a -> Bool) -> [a] -> Bool+breakAfter2 p xs =+ ListHT.breakAfterRec p xs == ListHT.breakAfterTakeUntil p xs++breakAfterUntil :: (Eq a) => (a -> Bool) -> [a] -> Bool+breakAfterUntil p xs =+ ListHT.takeUntil p xs == fst (ListHT.breakAfter p xs)++ sieve :: Eq a => Int -> [a] -> Property sieve n x = n>0 ==>@@ -84,19 +118,36 @@ mapAdjacent x xs = ListHT.mapAdjacent subtract (scanl (+) x xs) == xs +mapAdjacentPointfree :: (Num a, Eq a) => [a] -> Bool+mapAdjacentPointfree xs =+ ListHT.mapAdjacent (+) xs == ListHT.mapAdjacentPointfree (+) xs + simple :: (Testable test) => (Int -> [Integer] -> test) -> IO () simple = quickCheck +elemCheck ::+ (Testable test) =>+ (Float -> [Float] -> test) -> IO ()+elemCheck = quickCheck + tests :: [(String, IO ())] tests =- ("takeWhileRev", quickCheck (\a -> takeWhileRev ((a::Integer)>=))) :- ("dropWhileRev", quickCheck (\a -> dropWhileRev ((a::Integer)>=))) :+ ("takeWhileRev0", elemCheck (\a -> takeWhileRev0 (a>=))) :+ ("takeWhileRev1", elemCheck (\a -> takeWhileRev1 (a>=))) :+ ("takeWhileRev2", elemCheck (\a -> takeWhileRev2 (a>=))) :+ ("dropWhileRev", elemCheck (\a -> dropWhileRev (a>=))) : ("takeRev", simple takeRev) : ("dropRev", simple dropRev) :+ ("splitAtRev", simple splitAtRev) :+ ("breakAfterAppend", elemCheck (\a -> breakAfterAppend (a>=))) :+ ("breakAfter0", elemCheck (\a -> breakAfter0 (a>=))) :+ ("breakAfter1", elemCheck (\a -> breakAfter1 (a>=))) :+ ("breakAfter2", elemCheck (\a -> breakAfter2 (a>=))) :+ ("breakAfterUntil", elemCheck (\a -> breakAfterUntil (a>=))) : ("sieve", simple sieve) : ("sliceHorizontal", simple sliceHorizontal) : ("sliceVertical", simple sliceVertical) :@@ -105,4 +156,6 @@ ("outerProduct", quickCheck (outerProduct :: [Integer] -> [Int] -> Bool)) : ("iterate", quickCheck (iterate (+) :: Integer -> Bool)) : ("mapAdjacent", quickCheck (mapAdjacent :: Integer -> [Integer] -> Bool)) :+ ("mapAdjacentPointfree",+ quickCheck (mapAdjacentPointfree :: [Integer] -> Bool)) : []
+ src/Test/Data/List/Reverse/StrictElement.hs view
@@ -0,0 +1,53 @@+module Test.Data.List.Reverse.StrictElement where++import qualified Data.List.Reverse.StrictElement as Rev+import qualified Data.List as List+import Data.Tuple.HT (mapPair, swap, )++import Test.QuickCheck (Testable, quickCheck, )++import Prelude hiding (takeWhile, dropWhile, span, )+++takeWhile :: (Ord a) => (a -> Bool) -> [a] -> Bool+takeWhile p xs =+ Rev.takeWhile p xs == reverse (List.takeWhile p (reverse xs))++dropWhile :: (Ord a) => (a -> Bool) -> [a] -> Bool+dropWhile p xs =+ Rev.dropWhile p xs == reverse (List.dropWhile p (reverse xs))++span :: (Ord a) => (a -> Bool) -> [a] -> Bool+span p xs =+ Rev.span p xs == swap (mapPair (reverse, reverse) (List.span p (reverse xs)))++spanTakeDrop :: (Ord a) => (a -> Bool) -> [a] -> Bool+spanTakeDrop p xs =+ Rev.span p xs == (Rev.dropWhile p xs, Rev.takeWhile p xs)++dropWhileInf :: (Ord a) => a -> [a] -> Bool+dropWhileInf x xs =+ let ys = List.take 1000 $ Rev.dropWhile (x/=) $ cycle $ x:xs+ in ys==ys++spanInf :: (Ord a) => a -> [a] -> Bool+spanInf x xs =+ let ys = List.take 1000 $ fst $ Rev.span (x/=) $ cycle $ x:xs+ in ys==ys+++simple ::+ (Testable test) =>+ (Float -> [Float] -> test) -> IO ()+simple = quickCheck+++tests :: [(String, IO ())]+tests =+ ("takeWhile", simple (\a -> takeWhile (a>=))) :+ ("dropWhile", simple (\a -> dropWhile (a>=))) :+ ("span", simple (\a -> span (a>=))) :+ ("spanTakeDrop", simple (\a -> spanTakeDrop (a>=))) :+ ("dropWhileInf", simple dropWhileInf) :+ ("spanInf", simple spanInf) :+ []
+ src/Test/Data/List/Reverse/StrictSpine.hs view
@@ -0,0 +1,62 @@+module Test.Data.List.Reverse.StrictSpine where++import qualified Data.List.Reverse.StrictSpine as Rev+import qualified Data.List.Match as Match+import qualified Data.List as List+import Data.Tuple.HT (mapFst, mapPair, swap, )++import Test.QuickCheck (Testable, quickCheck, )++import Prelude hiding (takeWhile, dropWhile, span, )+++takeWhile :: (Ord a) => (a -> Bool) -> [a] -> Bool+takeWhile p xs =+ Rev.takeWhile p xs == reverse (List.takeWhile p (reverse xs))++dropWhile :: (Ord a) => (a -> Bool) -> [a] -> Bool+dropWhile p xs =+ Rev.dropWhile p xs == reverse (List.dropWhile p (reverse xs))++span :: (Ord a) => (a -> Bool) -> [a] -> Bool+span p xs =+ Rev.span p xs == swap (mapPair (reverse, reverse) (List.span p (reverse xs)))++spanTakeDrop :: (Ord a) => (a -> Bool) -> [a] -> Bool+spanTakeDrop p xs =+ Rev.span p xs == (Rev.dropWhile p xs, Rev.takeWhile p xs)++takeWhileBottom :: (Ord a) => a -> [a] -> [a] -> Bool+takeWhileBottom x xs pad =+ let ys = Rev.takeWhile (x/=) $ Match.replicate pad undefined ++ x:xs+ in ys==ys++dropWhileBottom :: (Ord a) => a -> [a] -> [a] -> Bool+dropWhileBottom x xs pad =+ let n = length $ Rev.dropWhile (x/=) $ Match.replicate pad undefined ++ x:xs+ in n==n++spanBottom :: (Ord a) => a -> [a] -> [a] -> Bool+spanBottom x xs pad =+ let (n,ys) =+ mapFst length $ Rev.span (x/=) $+ Match.replicate pad undefined ++ x:xs+ in n==n && ys==ys+++simple ::+ (Testable test) =>+ (Float -> [Float] -> test) -> IO ()+simple = quickCheck+++tests :: [(String, IO ())]+tests =+ ("takeWhile", simple (\a -> takeWhile (a>=))) :+ ("dropWhile", simple (\a -> dropWhile (a>=))) :+ ("span", simple (\a -> span (a>=))) :+ ("spanTakeDrop", simple (\a -> spanTakeDrop (a>=))) :+ ("takeWhileBottom", simple takeWhileBottom) :+ ("dropWhileBottom", simple dropWhileBottom) :+ ("spanBottom", simple spanBottom) :+ []
utility-ht.cabal view
@@ -1,5 +1,5 @@ Name: utility-ht-Version: 0.0.11+Version: 0.0.12 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -27,6 +27,7 @@ Tested-With: GHC==7.0.2, GHC==7.2.2, GHC==7.4.1, GHC==7.8.2 Cabal-Version: >=1.10 Build-Type: Simple+Stability: Stable -- workaround for Cabal-1.10 Extra-Source-Files:@@ -44,7 +45,7 @@ Source-Repository this type: darcs location: http://code.haskell.org/~thielema/utility/- tag: 0.0.11+ tag: 0.0.12 Library Build-Depends:@@ -54,6 +55,7 @@ GHC-Options: -Wall Hs-Source-Dirs: src Exposed-Modules:+ Data.Bits.HT Data.Bool.HT Data.Eq.HT Data.Function.HT@@ -61,6 +63,8 @@ Data.List.HT Data.List.Key Data.List.Match+ Data.List.Reverse.StrictElement+ Data.List.Reverse.StrictSpine Data.Maybe.HT Data.Monoid.HT Data.Ord.HT@@ -70,6 +74,7 @@ Data.Tuple.Lazy Data.Tuple.Strict Control.Monad.HT+ Control.Applicative.HT Control.Functor.HT Data.Strictness.HT Text.Read.HT@@ -96,6 +101,8 @@ Other-Modules: Test.Data.List Test.Data.ListMatch+ Test.Data.List.Reverse.StrictElement+ Test.Data.List.Reverse.StrictSpine Test.Data.Maybe Test.Data.Function Test.Utility