module Data.List.HT.Private where
import Data.List as List (find, transpose, unfoldr, isPrefixOf,
findIndices, foldl', mapAccumL, )
import Data.Maybe as Maybe (fromMaybe, catMaybes, isJust, mapMaybe, )
import Data.Maybe.HT (toMaybe, )
import Control.Monad.HT ((<=<), )
import Control.Monad (guard, msum, mplus, )
import Control.Applicative ((<$>), (<*>), )
import Data.Tuple.HT (mapPair, mapFst, mapSnd, forcePair, swap, )
import qualified Control.Functor.HT as Func
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, )
inits :: [a] -> [[a]]
inits = map reverse . scanl (flip (:)) []
initsLazy :: [a] -> [[a]]
initsLazy xt =
[] :
case xt of
[] -> []
x:xs -> map (x:) (initsLazy xs)
inits98 :: [a] -> [[a]]
inits98 [] = [[]]
inits98 (x:xs) = [[]] ++ map (x:) (inits98 xs)
inits98' :: [a] -> [[a]]
inits98' =
foldr (\x prefixes -> [] : map (x:) prefixes) [[]]
tails :: [a] -> [[a]]
tails xt =
uncurry (:) $
case xt of
[] -> ([],[])
_:xs -> (xt, tails xs)
tails' :: [a] -> [[a]]
tails' = fst . breakAfter null . iterate tail
tails98 :: [a] -> [[a]]
tails98 [] = [[]]
tails98 xxs@(_:xs) = xxs : tails98 xs
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy = Key.groupBy
group :: (Eq a) => [a] -> [[a]]
group = groupBy (==)
unzip :: [(a,b)] -> ([a],[b])
unzip =
forcePair .
foldr (\ (x,y) ~(xs,ys) -> (x:xs,y:ys)) ([],[])
partition :: (a -> Bool) -> [a] -> ([a], [a])
partition p =
forcePair .
foldr
(\x ~(y,z) ->
if p x
then (x : y, z)
else (y, x : z))
([],[])
span, break :: (a -> Bool) -> [a] -> ([a],[a])
span p =
let recourse xt =
forcePair $
fromMaybe ([],xt) $
do (x,xs) <- viewL xt
guard $ p x
return $ mapFst (x:) $ recourse xs
in recourse
break p = span (not . p)
chop :: (a -> Bool) -> [a] -> [[a]]
chop p =
uncurry (:) .
foldr (\ x ~(y,ys) -> if p x then ([],y:ys) else ((x:y),ys) ) ([],[])
chop' :: (a -> Bool) -> [a] -> [[a]]
chop' p =
let recourse =
uncurry (:) .
mapSnd (switchL [] (const recourse)) .
break p
in recourse
chopAtRun :: (a -> Bool) -> [a] -> [[a]]
chopAtRun p =
let recourse [] = [[]]
recourse y =
let (z,zs) = break p (dropWhile p y)
in z : recourse zs
in recourse
breakAfter :: (a -> Bool) -> [a] -> ([a], [a])
breakAfter = breakAfterRec
breakAfterRec :: (a -> Bool) -> [a] -> ([a], [a])
breakAfterRec p =
let recourse [] = ([],[])
recourse (x:xs) =
mapFst (x:) $
if p x
then ([],xs)
else recourse xs
in forcePair . recourse
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
takeUntil :: (a -> Bool) -> [a] -> [a]
takeUntil p = foldr (\x ys -> x : if p x then [] else ys) []
segmentAfter :: (a -> Bool) -> [a] -> [[a]]
segmentAfter p =
uncurry (:) .
foldr
(\x ~(y,ys) ->
mapFst (x:) $
if p x then ([],y:ys) else (y,ys))
([],[])
segmentAfter' :: (a -> Bool) -> [a] -> [[a]]
segmentAfter' p =
foldr (\ x ~yt@(y:ys) -> if p x then [x]:yt else (x:y):ys) [[]]
propSegmentAfterConcat :: Eq a => (a -> Bool) -> [a] -> Bool
propSegmentAfterConcat p xs =
concat (segmentAfter p xs) == xs
propSegmentAfterNumSeps :: (a -> Bool) -> [a] -> Bool
propSegmentAfterNumSeps p xs =
length (filter p xs) == length (tail (segmentAfter p xs))
propSegmentAfterLasts :: (a -> Bool) -> [a] -> Bool
propSegmentAfterLasts p =
all (p . last) . init . segmentAfter p
propSegmentAfterInits :: (a -> Bool) -> [a] -> Bool
propSegmentAfterInits p =
all (all (not . p) . init) . init . segmentAfter p
propSegmentAfterInfinite :: (a -> Bool) -> a -> [a] -> Bool
propSegmentAfterInfinite p x =
flip seq True . (!!100) . concat . segmentAfter p . cycle . (x:)
segmentBefore :: (a -> Bool) -> [a] -> [[a]]
segmentBefore p =
uncurry (:) .
foldr
(\ x ~(y,ys) ->
let xs = x:y
in if p x then ([],xs:ys) else (xs,ys))
([],[])
segmentBefore' :: (a -> Bool) -> [a] -> [[a]]
segmentBefore' p =
uncurry (:) .
(\xst ->
fromMaybe ([],xst) $ do
((x:xs):xss) <- Just xst
guard $ not $ p x
return (x:xs, xss)) .
groupBy (\_ x -> not $ p x)
segmentBefore'' :: (a -> Bool) -> [a] -> [[a]]
segmentBefore'' p =
(\xst ->
case xst of
~(xs:xss) ->
tail xs : xss) .
groupBy (\_ x -> not $ p x) .
(error "segmentBefore: dummy element" :)
propSegmentBeforeConcat :: Eq a => (a -> Bool) -> [a] -> Bool
propSegmentBeforeConcat p xs =
concat (segmentBefore p xs) == xs
propSegmentBeforeNumSeps :: (a -> Bool) -> [a] -> Bool
propSegmentBeforeNumSeps p xs =
length (filter p xs) == length (tail (segmentBefore p xs))
propSegmentBeforeHeads :: (a -> Bool) -> [a] -> Bool
propSegmentBeforeHeads p =
all (p . head) . tail . segmentBefore p
propSegmentBeforeTails :: (a -> Bool) -> [a] -> Bool
propSegmentBeforeTails p =
all (all (not . p) . tail) . tail . segmentBefore p
propSegmentBeforeInfinite :: (a -> Bool) -> a -> [a] -> Bool
propSegmentBeforeInfinite p x =
flip seq True . (!!100) . concat . segmentBefore p . cycle . (x:)
propSegmentBeforeGroupBy0 :: Eq a => (a -> Bool) -> [a] -> Bool
propSegmentBeforeGroupBy0 p xs =
segmentBefore p xs == segmentBefore' p xs
propSegmentBeforeGroupBy1 :: Eq a => (a -> Bool) -> [a] -> Bool
propSegmentBeforeGroupBy1 p xs =
segmentBefore p xs == segmentBefore'' p xs
segmentBeforeMaybe ::
(a -> Maybe b) ->
[a] -> ([a], [(b, [a])])
segmentBeforeMaybe f =
forcePair .
foldr
(\ x ~(y,ys) ->
case f x of
Just b -> ([],(b,y):ys)
Nothing -> (x:y,ys))
([],[])
segmentAfterMaybe ::
(a -> Maybe b) ->
[a] -> ([([a], b)], [a])
segmentAfterMaybe f =
swap .
uncurry (mapAccumL (\as0 (b,as1) -> (as1, (as0,b)))) .
segmentBeforeMaybe f
removeEach :: [a] -> [(a, [a])]
removeEach =
map (\(ys, pivot, zs) -> (pivot,ys++zs)) . splitEverywhere
splitEverywhere :: [a] -> [([a], a, [a])]
splitEverywhere xs =
map
(\(y, zs0) ->
case zs0 of
z:zs -> (y,z,zs)
[] -> error "splitEverywhere: empty list")
(init (zip (inits xs) (tails xs)))
splitLast :: [a] -> ([a], a)
splitLast [] = error "splitLast: empty list"
splitLast [x] = ([], x)
splitLast (x:xs) =
let (xs', lastx) = splitLast xs in (x:xs', lastx)
propSplitLast :: Eq a => [a] -> Bool
propSplitLast xs =
splitLast xs == (init xs, last xs)
viewL :: [a] -> Maybe (a, [a])
viewL (x:xs) = Just (x,xs)
viewL [] = Nothing
viewR :: [a] -> Maybe ([a], a)
viewR =
foldr (\x -> Just . forcePair . maybe ([],x) (mapFst (x:))) Nothing
propViewR :: Eq a => [a] -> Bool
propViewR xs =
maybe True
((init xs, last xs) == )
(viewR xs)
switchL :: b -> (a -> [a] -> b) -> [a] -> b
switchL n _ [] = n
switchL _ j (x:xs) = j x xs
switchL' :: b -> (a -> [a] -> b) -> [a] -> b
switchL' n j =
maybe n (uncurry j) . viewL
switchR :: b -> ([a] -> a -> b) -> [a] -> b
switchR n j =
maybe n (uncurry j) . viewR
propSwitchR :: Eq a => [a] -> Bool
propSwitchR xs =
switchR True (\ixs lxs -> ixs == init xs && lxs == last xs) xs
takeRev :: Int -> [a] -> [a]
takeRev n xs = Match.drop (drop n xs) xs
dropRev :: Int -> [a] -> [a]
dropRev n xs = Match.take (drop n xs) xs
splitAtRev :: Int -> [a] -> ([a], [a])
splitAtRev n xs = Match.splitAt (drop n xs) xs
dropWhileRev :: (a -> Bool) -> [a] -> [a]
dropWhileRev p =
concat . init . segmentAfter (not . p)
takeWhileRev0 :: (a -> Bool) -> [a] -> [a]
takeWhileRev0 p =
last . segmentAfter (not . p)
takeWhileRev1 :: (a -> Bool) -> [a] -> [a]
takeWhileRev1 p =
(\mx ->
case mx of
Just (_, xs@((True,_):_)) -> map snd xs
_ -> []) .
viewR . Key.aux groupBy (==) p
takeWhileRev2 :: (a -> Bool) -> [a] -> [a]
takeWhileRev2 p =
foldl (\xs x -> if p x then xs++[x] else []) []
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)
partitionMaybe :: (a -> Maybe b) -> [a] -> ([b], [a])
partitionMaybe f =
forcePair .
foldr
(\x -> maybe (mapSnd (x:)) (\y -> mapFst (y:)) (f x))
([],[])
takeWhileJust :: [Maybe a] -> [a]
takeWhileJust =
foldr (\x acc -> maybe [] (:acc) x) []
dropWhileNothing :: (a -> Maybe b) -> [a] -> Maybe (b, [a])
dropWhileNothing f =
msum . map (Func.mapFst f <=< viewL) . tails
dropWhileNothingRec :: (a -> Maybe b) -> [a] -> Maybe (b, [a])
dropWhileNothingRec f =
let go [] = Nothing
go (a:xs) = (flip (,) xs <$> f a) `mplus` go xs
in go
breakJust :: (a -> Maybe b) -> [a] -> ([a], Maybe (b, [a]))
breakJust f =
let go [] = ([], Nothing)
go (a:xs) =
case f a of
Nothing -> mapFst (a:) $ go xs
Just b -> ([], Just (b, xs))
in go
breakJustRemoveEach :: (a -> Maybe b) -> [a] -> ([a], Maybe (b, [a]))
breakJustRemoveEach f xs =
switchL (xs, Nothing) const $
mapMaybe (\(ys,a,zs) -> (\b -> (ys, Just (b,zs))) <$> f a) $
splitEverywhere xs
breakJustPartial :: (a -> Maybe b) -> [a] -> ([a], Maybe (b, [a]))
breakJustPartial f xs =
let (ys,zs) = break (isJust . f) xs
in (ys,
mapFst (maybe (error "breakJust: unexpected Nothing") id . f) <$>
viewL zs)
unzipEithers :: [Either a b] -> ([a], [b])
unzipEithers =
forcePair .
foldr (either (\x -> mapFst (x:)) (\y -> mapSnd (y:))) ([],[])
sieve, sieve', sieve'', sieve''' :: Int -> [a] -> [a]
sieve k =
unfoldr (\xs -> toMaybe (not (null xs)) (head xs, drop k xs))
sieve' k = map head . sliceVertical k
sieve'' k x = map (x!!) [0,k..(length x1)]
sieve''' k = map head . takeWhile (not . null) . iterate (drop k)
propSieve :: Eq a => Int -> [a] -> Bool
propSieve n x =
sieve n x == sieve' n x &&
sieve n x == sieve'' n x
sliceHorizontal, sliceHorizontal', sliceHorizontal'', sliceHorizontal''' ::
Int -> [a] -> [[a]]
sliceHorizontal n =
map (sieve n) . take n . iterate (drop 1)
sliceHorizontal' n =
foldr (\x ys -> let y = last ys in Match.take ys ((x:y):ys)) (replicate n [])
sliceHorizontal'' n =
reverse . foldr (\x ~(y:ys) -> ys ++ [x:y]) (replicate n [])
sliceHorizontal''' n =
take n . transpose . takeWhile (not . null) . iterate (drop n)
propSliceHorizontal :: Eq a => Int -> [a] -> Bool
propSliceHorizontal n x =
sliceHorizontal n x == sliceHorizontal' n x &&
sliceHorizontal n x == sliceHorizontal'' n x &&
sliceHorizontal n x == sliceHorizontal''' n x
sliceVertical, sliceVertical' :: Int -> [a] -> [[a]]
sliceVertical n =
map (take n) . takeWhile (not . null) . iterate (drop n)
sliceVertical' n =
unfoldr (\x -> toMaybe (not (null x)) (splitAt n x))
propSliceVertical :: Eq a => Int -> [a] -> Bool
propSliceVertical n x =
take 100000 (sliceVertical n x) == take 100000 (sliceVertical' n x)
propSlice :: Eq a => Int -> [a] -> Bool
propSlice n x =
sliceHorizontal n x == transpose (sliceVertical n x) &&
sliceVertical n x == transpose (sliceHorizontal n x)
search :: (Eq a) => [a] -> [a] -> [Int]
search sub str = findIndices (isPrefixOf sub) (tails str)
replace :: Eq a => [a] -> [a] -> [a] -> [a]
replace src dst =
let recourse [] = []
recourse str@(s:ss) =
fromMaybe
(s : recourse ss)
(fmap ((dst++) . recourse) $
maybePrefixOf src str)
in recourse
markSublists :: (Eq a) => [a] -> [a] -> [Maybe [a]]
markSublists sub ys =
let ~(hd', rest') =
foldr (\c ~(hd, rest) ->
let xs = c:hd
in case maybePrefixOf sub xs of
Just suffix -> ([], Nothing : Just suffix : rest)
Nothing -> (xs, rest)) ([],[]) ys
in Just hd' : rest'
replace' :: (Eq a) => [a] -> [a] -> [a] -> [a]
replace' src dst xs =
concatMap (fromMaybe dst) (markSublists src xs)
propReplaceId :: (Eq a) => [a] -> [a] -> Bool
propReplaceId xs ys =
replace xs xs ys == ys
propReplaceCycle :: (Eq a) => [a] -> [a] -> Bool
propReplaceCycle xs ys =
replace xs ys (cycle xs) == cycle ys
replace'' :: (Eq a) => [a] -> [a] -> [a] -> [a]
replace'' src dst =
foldr (\x xs -> let y=x:xs
in if isPrefixOf src y
then dst ++ drop (length src) y
else y) []
multiReplace :: Eq a => [([a], [a])] -> [a] -> [a]
multiReplace dict =
let recourse [] = []
recourse str@(s:ss) =
fromMaybe
(s : recourse ss)
(msum $
map (\(src,dst) ->
fmap ((dst++) . recourse) $
maybePrefixOf src str) dict)
in recourse
multiReplace' :: Eq a => [([a], [a])] -> [a] -> [a]
multiReplace' dict =
let recourse [] = []
recourse str@(s:ss) =
maybe
(s : recourse ss)
(\(src, dst) -> dst ++ recourse (Match.drop src str))
(find (flip isPrefixOf str . fst) dict)
in recourse
propMultiReplaceSingle :: Eq a => [a] -> [a] -> [a] -> Bool
propMultiReplaceSingle src dst x =
replace src dst x == multiReplace [(src,dst)] x
shear :: [[a]] -> [[a]]
shear =
map catMaybes .
shearTranspose .
transposeFill
transposeFill :: [[a]] -> [[Maybe a]]
transposeFill =
unfoldr (\xs ->
toMaybe (not (null xs))
(mapSnd (Rev.dropWhile null) $ unzipCons xs))
unzipCons :: [[a]] -> ([Maybe a], [[a]])
unzipCons =
unzip .
map ((\my -> (fmap fst my, maybe [] snd my)) . viewL)
unzipConsSkew :: [[a]] -> ([Maybe a], [[a]])
unzipConsSkew =
let aux [] [] = ([],[])
aux xs ys = mapSnd (xs:) $ prep ys
prep =
forcePair .
switchL ([],[])
(\y ys ->
let my = viewL y
in mapFst (fmap fst my :) $
aux (maybe [] snd my) ys)
in prep
shear' :: [[a]] -> [[a]]
shear' xs@(_:_) =
let (y:ys,zs) = unzip (map (splitAt 1) xs)
zipConc (a:as) (b:bs) = (a++b) : zipConc as bs
zipConc [] bs = bs
zipConc as [] = as
in y : zipConc ys (shear' (Rev.dropWhile null zs))
shear' [] = []
shearTranspose :: [[a]] -> [[a]]
shearTranspose =
foldr zipConsSkew []
zipConsSkew :: [a] -> [[a]] -> [[a]]
zipConsSkew xt yss =
uncurry (:) $
case xt of
x:xs -> ([x], zipCons xs yss)
[] -> ([], yss)
zipCons :: [a] -> [[a]] -> [[a]]
zipCons (x:xs) yt =
let (y,ys) = switchL ([],[]) (,) yt
in (x:y) : zipCons xs ys
zipCons [] ys = ys
zipCons' :: [a] -> [[a]] -> [[a]]
zipCons' (x:xs) (y:ys) = (x:y) : zipCons' xs ys
zipCons' [] ys = ys
zipCons' xs [] = map (:[]) xs
outerProduct :: (a -> b -> c) -> [a] -> [b] -> [[c]]
outerProduct f xs ys = map (flip map ys . f) xs
takeWhileMulti :: [a -> Bool] -> [a] -> [a]
takeWhileMulti [] _ = []
takeWhileMulti _ [] = []
takeWhileMulti aps@(p:ps) axs@(x:xs) =
if p x
then x : takeWhileMulti aps xs
else takeWhileMulti ps axs
takeWhileMulti' :: [a -> Bool] -> [a] -> [a]
takeWhileMulti' ps xs =
concatMap fst (tail
(scanl (flip span . snd) (undefined,xs) ps))
propTakeWhileMulti :: (Eq a) => [a -> Bool] -> [a] -> Bool
propTakeWhileMulti ps xs =
takeWhileMulti ps xs == takeWhileMulti' ps xs
foldl'r, foldl'rStrict, foldl'rNaive ::
(b -> a -> b) -> b -> (c -> d -> d) -> d -> [(a,c)] -> (b,d)
foldl'r f b0 g d0 =
mapFst ($b0) .
foldr (\(a,c) ~(k,d) -> (\b -> k $! f b a, g c d)) (id,d0)
foldl'rStrict f b0 g d0 =
mapFst ($b0) .
foldr (\(a,c) ~(k,d) -> ((,) $! (\b -> k $! f b a)) $! g c d) (id,d0)
foldl'rNaive f b g d xs =
mapPair (foldl' f b, foldr g d) $ unzip xs
propFoldl'r :: (Eq b, Eq d) =>
(b -> a -> b) -> b -> (c -> d -> d) -> d -> [(a,c)] -> Bool
propFoldl'r f b g d xs =
foldl'r f b g d xs == foldl'rNaive f b g d xs
lengthAtLeast :: Int -> [a] -> Bool
lengthAtLeast n =
if n<=0
then const True
else not . null . drop (n1)
lengthAtMost :: Int -> [a] -> Bool
lengthAtMost n =
if n<0
then const False
else null . drop n
lengthAtMost0 :: Int -> [a] -> Bool
lengthAtMost0 n = (n>=) . length . take (n+1)
iterateUntilCycle :: (Eq a) => (a -> a) -> a -> [a]
iterateUntilCycle f a =
let as = iterate f a
in (a:) $ map fst $
takeWhile (uncurry (/=)) $
zip (tail as) (concatMap (\ai->[ai,ai]) as)
iterateUntilCycleP :: (Eq a) => (a -> a) -> a -> [a]
iterateUntilCycleP f a =
let as = iterate f a
in map fst $
takeWhile (\(a1,(a20,a21)) -> a1/=a20 && a1/=a21) $
zip as (pairs (tail as))
pairs :: [t] -> [(t, t)]
pairs [] = []
pairs (_:[]) = error "pairs: odd number of elements"
pairs (x0:x1:xs) = (x0,x1) : pairs xs
rotate, rotate', rotate'' :: Int -> [a] -> [a]
rotate n x =
Match.take x (drop (mod n (length x)) (cycle x))
rotate' n x =
uncurry (flip (++))
(splitAt (mod n (length x)) x)
rotate'' n x =
Match.take x (drop n (cycle x))
propRotate :: Eq a => Int -> [a] -> Bool
propRotate n x =
rotate n x == rotate' n x &&
rotate n x == rotate'' n x
mergeBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]
mergeBy = Key.mergeBy
allEqual :: Eq a => [a] -> Bool
allEqual = and . mapAdjacent (==)
isAscending :: (Ord a) => [a] -> Bool
isAscending = and . isAscendingLazy
isAscendingLazy :: (Ord a) => [a] -> [Bool]
isAscendingLazy = mapAdjacent (<=)
mapAdjacent :: (a -> a -> b) -> [a] -> [b]
mapAdjacent f xs = zipWith f xs (tail xs)
mapAdjacentPointfree :: (a -> a -> b) -> [a] -> [b]
mapAdjacentPointfree f = zipWith f <*> tail
mapAdjacent1 :: (a -> a -> b -> c) -> a -> [(a,b)] -> [c]
mapAdjacent1 f a xs =
zipWith (\a0 (a1,b) -> f a0 a1 b) (a : map fst xs) xs
range :: Num a => Int -> [a]
range n = take n (iterate (+1) 0)
padLeft :: a -> Int -> [a] -> [a]
padLeft c n xs = replicate (n length xs) c ++ xs
padRight, padRight1 :: a -> Int -> [a] -> [a]
padRight c n xs = take n $ xs ++ repeat c
padRight1 c n xs = xs ++ replicate (n length xs) c
iterateAssociative :: (a -> a -> a) -> a -> [a]
iterateAssociative op a =
foldr (\pow xs -> pow : concatMap (\x -> [x, op x pow]) xs)
undefined (iterate (\x -> op x x) a)
iterateLeaky :: (a -> a -> a) -> a -> [a]
iterateLeaky op x =
let merge (a:as) b = a : merge b as
merge _ _ = error "iterateLeaky: an empty list cannot occur"
sqrs = map (\y -> op y y) z
z = x : merge sqrs (map (op x) sqrs)
in z