-- | -- Copyright: (c) 2022 Bodigrim -- Licence: BSD3 {-# LANGUAGE PostfixOperators #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} {-# HLINT ignore "Use <$>" #-} {-# HLINT ignore "Monad law, left identity" #-} {-# HLINT ignore "Monad law, right identity" #-} module Main where import Test.QuickCheck.Function import Test.Tasty import Test.Tasty.QuickCheck as QC import Control.Applicative import Control.Monad import Data.Bifunctor import qualified Data.List as L import Data.List.Infinite (Infinite(..)) import qualified Data.List.Infinite as I import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE import Data.Maybe import Numeric.Natural instance Arbitrary a => Arbitrary (Infinite a) where arbitrary = (:<) <$> arbitrary <*> arbitrary shrink = const [] instance Arbitrary a => Arbitrary (NonEmpty a) where arbitrary = (:|) <$> arbitrary <*> arbitrary trim :: Infinite a -> [a] trim = I.take 10 trim1 :: Infinite a -> [a] trim1 = I.take 11 mapMapFusion :: Infinite Int -> Infinite Int mapMapFusion xs = I.map fromIntegral (I.map fromIntegral xs :: Infinite Word) main :: IO () main = defaultMain $ testGroup "All" [ testProperty "head" $ \(Blind (xs :: Infinite Int)) -> I.head xs == L.head (trim xs) , testProperty "tail" $ \(Blind (xs :: Infinite Int)) -> trim (I.tail xs) == L.tail (trim1 xs) , testProperty "uncons" $ \(Blind (xs :: Infinite Int)) -> Just (fmap trim (I.uncons xs)) == L.uncons (trim1 xs) , testProperty "map" $ \(applyFun -> f :: Int -> Word) (Blind (xs :: Infinite Int)) -> trim (I.map f xs) == L.map f (trim xs) , testProperty "fmap" $ \(applyFun -> f :: Int -> Int) (Blind (xs :: Infinite Int)) -> trim (fmap f xs) == fmap f (trim xs) , testProperty "<$" $ \(x :: Word) (Blind (xs :: Infinite Int)) -> trim (x <$ xs) == trim (fmap (const x) xs) , testProperty "pure" $ \(applyFun -> f :: Int -> Word) (x :: Int) -> trim (pure f <*> pure x) == trim (pure (f x)) , testProperty "*>" $ \(Blind (xs :: Infinite Int)) (Blind (ys :: Infinite Word)) -> trim (xs *> ys) == trim ((id <$ xs) <*> ys) , testProperty "<*" $ \(Blind (xs :: Infinite Int)) (Blind (ys :: Infinite Word)) -> trim (xs <* ys) == trim (liftA2 const xs ys) , testProperty ">>= 1" $ \x ((I.cycle .) . applyFun -> k :: Int -> Infinite Word) -> trim (return x >>= k) == trim (k x) , testProperty ">>= 2" $ \(Blind (xs :: Infinite Int)) -> trim (xs >>= return) == trim xs , testProperty ">>= 3" $ \(Blind xs) ((I.cycle .) . applyFun -> k :: Int -> Infinite Word) ((I.cycle .) . applyFun -> h :: Word -> Infinite Char) -> trim (xs >>= (k >=> h)) == trim ((xs >>= k) >>= h) , testProperty ">>" $ \(Blind (xs :: Infinite Int)) (Blind (ys :: Infinite Word)) -> trim (xs >> ys) == trim ys , testProperty "concat" $ \(Blind (xs :: Infinite (NonEmpty Int))) -> trim (I.concat xs) == L.take 10 (L.concatMap NE.toList (I.toList xs)) , testProperty "concatMap" $ \(applyFun -> f :: Int -> NonEmpty Word) (Blind xs) -> trim (I.concatMap f xs) == L.take 10 (L.concatMap (NE.toList . f) (I.toList xs)) , testProperty "intersperse" $ \(x :: Int) (Blind xs) -> I.take 19 (I.intersperse x xs) == L.intersperse x (trim xs) , testProperty "intersperse laziness 1" $ I.head (I.intersperse undefined ('q' :< undefined)) == 'q' , testProperty "intersperse laziness 2" $ I.take 2 (I.intersperse 'w' ('q' :< undefined)) == "qw" , testProperty "intercalate" $ \(x :: NonEmpty Int) (Blind xs) -> I.take (sum (map length (trim xs)) + 9 * length x) (I.intercalate x xs) == L.intercalate (NE.toList x) (trim xs) , testProperty "intercalate laziness 1" $ I.take 3 (I.intercalate undefined ("foo" :< undefined)) == "foo" , testProperty "intercalate laziness 2" $ I.take 6 (I.intercalate (NE.fromList "bar") ("foo" :< undefined)) == "foobar" , testProperty "interleave 1" $ \(Blind (xs :: Infinite Int)) (Blind ys) -> trim (I.map snd (I.filter fst (I.zip (I.cycle (True :| [False])) (I.interleave xs ys)))) == trim xs , testProperty "interleave 2" $ \(Blind (xs :: Infinite Int)) (Blind ys) -> trim (I.map snd (I.filter fst (I.zip (I.cycle (False :| [True])) (I.interleave xs ys)))) == trim ys , testProperty "interleave laziness" $ I.head (I.interleave ('a' :< undefined) undefined) == 'a' , testProperty "transpose []" $ \(fmap getBlind -> xss :: [Infinite Int]) -> not (null xss) ==> trim (I.transpose xss) == L.transpose (map trim xss) , testProperty "transpose NE" $ \(fmap getBlind -> xss :: NonEmpty (Infinite Int)) -> NE.fromList (trim (I.transpose xss)) == NE.transpose (NE.map (NE.fromList . trim) xss) , testProperty "transpose laziness 1" $ I.head (I.transpose ['a' :< undefined, 'b' :< undefined]) == "ab" , testProperty "transpose laziness 2" $ I.head (I.transpose (('a' :< undefined) :| ['b' :< undefined])) == 'a' :| "b" , testProperty "subsequences" $ \(Blind (xs :: Infinite Int)) -> I.take 16 (I.subsequences xs) == L.subsequences (I.take 4 xs) , testProperty "subsequences laziness 1" $ I.head (I.subsequences undefined) == "" , testProperty "subsequences laziness 2" $ I.take 2 (I.subsequences ('q' :< undefined)) == ["", "q"] , testProperty "permutations" $ \(Blind (xs :: Infinite Int)) -> map (I.take 4) (I.take 24 (I.permutations xs)) == L.permutations (I.take 4 xs) , testProperty "permutations laziness" $ I.take 6 (I.map (I.take 3) (I.permutations ('q' :< 'w' :< 'e' :< undefined))) == ["qwe","wqe","ewq","weq","eqw","qew"] , testProperty "... Bool" $ \(x :: Bool) -> trim (x I....) === L.take 10 (L.cycle [x..]) , testProperty "... Int" $ \(x :: Int) -> trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty "... Int maxBound" $ \(NonNegative (x' :: Int)) -> let x = maxBound - x' in trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty "... Word" $ \(x :: Word) -> trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty "... Word maxBound" $ \(NonNegative (x' :: Word)) -> let x = maxBound - x' in trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty "... Integer" $ \(x :: Integer) -> trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty "... Natural" $ \(NonNegative (x' :: Integer)) -> let x = fromInteger x' :: Natural in trim (x I....) == L.take 10 (L.cycle [x..]) , testProperty ".... Bool" $ \(x :: Bool) y -> trim ((x, y) I.....) == L.take 10 (L.cycle [x, y..]) , testProperty ".... Int" $ \(x :: Int) y -> trim ((x, y) I.....) == L.take 10 (L.cycle [x, y..]) .&&. trim ((maxBound + x, y) I.....) == L.take 10 (L.cycle [maxBound + x, y..]) && trim ((x, maxBound + y) I.....) == L.take 10 (L.cycle [x, maxBound + y..]) && trim ((maxBound + x, maxBound + y) I.....) == L.take 10 (L.cycle [maxBound + x, maxBound + y..]) , testProperty ".... Word" $ \(x :: Word) y -> trim ((x, y) I.....) == L.take 10 (L.cycle [x, y..]) .&&. trim ((maxBound + x, y) I.....) == L.take 10 (L.cycle [maxBound + x, y..]) && trim ((x, maxBound + y) I.....) == L.take 10 (L.cycle [x, maxBound + y..]) && trim ((maxBound + x, maxBound + y) I.....) == L.take 10 (L.cycle [maxBound + x, maxBound + y..]) , testProperty ".... Integer" $ \(x :: Integer) y -> trim ((x, y) I.....) == L.take 10 (L.cycle [x, y..]) , testProperty ".... Natural" $ \(NonNegative (x' :: Integer)) (NonNegative (y' :: Integer)) -> let x = fromInteger x' :: Natural in let y = fromInteger y' in trim ((x, y) I.....) == L.take 10 (L.cycle [x, y..]) , testProperty "toList" $ \(Blind (xs :: Infinite Int)) -> L.take 10 (I.toList xs) == trim xs , testProperty "scanl" $ \(curry . applyFun -> f :: Word -> Int -> Word) s (Blind xs) -> trim1 (I.scanl f s xs) == L.scanl f s (trim xs) , testProperty "scanl laziness" $ I.head (I.scanl undefined 'q' undefined) == 'q' , testProperty "scanl'" $ \(curry . applyFun -> f :: Word -> Int -> Word) s (Blind xs) -> trim1 (I.scanl' f s xs) == L.scanl' f s (trim xs) , testProperty "scanl' laziness" $ I.head (I.scanl' undefined 'q' undefined) == 'q' , testProperty "scanl1" $ \(curry . applyFun -> f :: Int -> Int -> Int) (Blind xs) -> trim (I.scanl1 f xs) == L.scanl1 f (trim xs) , testProperty "scanl1 laziness" $ I.head (I.scanl1 undefined ('q' :< undefined)) == 'q' , testProperty "mapAccumL" $ \(curry . applyFun -> f :: Bool -> Int -> (Bool, Word)) (Blind xs) -> trim (I.mapAccumL f False xs) == snd (L.mapAccumL f False (trim xs)) , testProperty "mapAccumL laziness" $ I.head (I.mapAccumL (\_ x -> (undefined, x)) undefined ('q' :< undefined)) == 'q' , testProperty "iterate" $ \(applyFun -> f :: Int -> Int) s -> trim (I.iterate f s) == L.take 10 (L.iterate f s) , testProperty "iterate laziness" $ I.head (I.iterate undefined 'q') == 'q' , testProperty "iterate'" $ \(applyFun -> f :: Int -> Int) s -> trim (I.iterate' f s) == L.take 10 (L.iterate f s) , testProperty "iterate' laziness" $ I.head (I.iterate' undefined 'q') == 'q' , testProperty "repeat" $ \(s :: Int) -> trim (I.repeat s) == L.replicate 10 s , testProperty "cycle" $ \(xs :: NonEmpty Int) -> trim (I.cycle xs) == L.take 10 (L.cycle (NE.toList xs)) , testProperty "cycle laziness" $ I.head (I.cycle ('q' :| undefined)) == 'q' , testProperty "unfoldr" $ \(applyFun -> f :: Word -> (Int, Word)) s -> trim (I.unfoldr f s) == L.take 10 (L.unfoldr (Just . f) s) , testProperty "unfoldr laziness" $ I.head (I.unfoldr (, undefined) 'q') == 'q' , testProperty "take" $ \n (Blind (xs :: Infinite Int)) -> L.take 10 (I.take n xs) == L.take n (trim xs) , testProperty "take laziness 1" $ I.take 0 undefined == "" , testProperty "take laziness 2" $ I.take 1 ('q' :< undefined) == "q" , testProperty "drop" $ \n (Blind (xs :: Infinite Int)) -> trim (I.drop n xs) == L.drop n (I.take (max n 0 + 10) xs) , testProperty "splitAt" $ \n (Blind (xs :: Infinite Int)) -> bimap (L.take 10) trim (I.splitAt n xs) == first (L.take 10) (L.splitAt n (I.take (max n 0 + 10) xs)) , testProperty "splitAt laziness 1" $ fst (I.splitAt 0 undefined) == "" , testProperty "splitAt laziness 2" $ fst (I.splitAt 1 ('q' :< undefined)) == "q" , testProperty "takeWhile" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> let ys = L.take 10 (I.takeWhile f xs) in L.take 10 (L.takeWhile f (I.take (length ys + 10) xs)) == L.take 10 (I.takeWhile f xs) , testProperty "takeWhile laziness 1" $ L.null (I.takeWhile (const False) ('q' :< undefined)) , testProperty "takeWhile laziness 2" $ L.head (I.takeWhile (const True) ('q' :< undefined)) == 'q' , testProperty "fst . span" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> let ys = L.take 10 (fst (I.span f xs)) in L.take 10 (L.takeWhile f (I.take (length ys + 10) xs)) == L.take 10 (fst (I.span f xs)) , testProperty "fst . break" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> let ys = L.take 10 (fst (I.break f xs)) in L.take 10 (L.takeWhile (not . f) (I.take (length ys + 10) xs)) == L.take 10 (fst (I.break f xs)) , testProperty "dropWhile" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> trim (L.foldr (:<) (I.dropWhile f xs) (I.takeWhile f xs)) == trim xs , testProperty "snd . span" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> trim (L.foldr (:<) (snd (I.span f xs)) (I.takeWhile f xs)) == trim xs , testProperty "snd . break" $ \(applyFun -> f :: Ordering -> Bool) (Blind xs) -> trim (L.foldr (:<) (snd (I.break f xs)) (I.takeWhile (not . f) xs)) == trim xs , testProperty "span laziness" $ L.head (fst (I.span (/= '\n') ('q' :< undefined))) == 'q' , testProperty "break laziness" $ L.head (fst (I.break (== '\n') ('q' :< undefined))) == 'q' , testProperty "stripPrefix" $ \(xs :: [Int]) (Blind (ys :: Infinite Int)) -> fmap trim (I.stripPrefix xs ys) == fmap (L.take 10) (L.stripPrefix xs (I.take (length xs + 10) ys)) , testProperty "stripPrefix laziness 1" $ isNothing (I.stripPrefix ('q' : undefined) ('w' :< undefined)) , testProperty "stripPrefix laziness 2" $ isJust (I.stripPrefix "foo" ('f' :< 'o' :< 'o' :< undefined)) , testProperty "isPrefixOf" $ \(xs :: [Int]) (Blind (ys :: Infinite Int)) -> I.isPrefixOf xs ys == L.isPrefixOf xs (I.take (length xs + 10) ys) , testProperty "isPrefixOf laziness 1" $ not (I.isPrefixOf ('q' : undefined) ('w' :< undefined)) , testProperty "isPrefixOf laziness 2" $ I.isPrefixOf "foo" ('f' :< 'o' :< 'o' :< undefined) , testProperty "zip" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) -> trim (I.zip xs1 xs2) == L.zip (trim xs1) (trim xs2) , testProperty "zip3" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) (Blind (xs3 :: Infinite Bool)) -> trim (I.zip3 xs1 xs2 xs3) == L.zip3 (trim xs1) (trim xs2) (trim xs3) , testProperty "zip4" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) (Blind (xs3 :: Infinite Bool)) (Blind (xs4 :: Infinite Char)) -> trim (I.zip4 xs1 xs2 xs3 xs4) == L.zip4 (trim xs1) (trim xs2) (trim xs3) (trim xs4) , testProperty "zip5" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) (Blind (xs3 :: Infinite Bool)) (Blind (xs4 :: Infinite Char)) (Blind (xs5 :: Infinite Ordering)) -> trim (I.zip5 xs1 xs2 xs3 xs4 xs5) == L.zip5 (trim xs1) (trim xs2) (trim xs3) (trim xs4) (trim xs5) , testProperty "zip6" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) (Blind (xs3 :: Infinite Bool)) (Blind (xs4 :: Infinite Char)) (Blind (xs5 :: Infinite Ordering)) (Blind (xs6 :: Infinite String)) -> trim (I.zip6 xs1 xs2 xs3 xs4 xs5 xs6) == L.zip6 (trim xs1) (trim xs2) (trim xs3) (trim xs4) (trim xs5) (trim xs6) , testProperty "zip7" $ \(Blind (xs1 :: Infinite Int)) (Blind (xs2 :: Infinite Word)) (Blind (xs3 :: Infinite Bool)) (Blind (xs4 :: Infinite Char)) (Blind (xs5 :: Infinite Ordering)) (Blind (xs6 :: Infinite String)) (Blind (xs7 :: Infinite Integer)) -> trim (I.zip7 xs1 xs2 xs3 xs4 xs5 xs6 xs7) == L.zip7 (trim xs1) (trim xs2) (trim xs3) (trim xs4) (trim xs5) (trim xs6) (trim xs7) , testProperty "unzip" $ \(Blind (xs :: Infinite (Int, Word))) -> bimap trim trim (I.unzip xs) == L.unzip (trim xs) , testProperty "unzip3" $ \(Blind (xs :: Infinite (Int, Word, Bool))) -> (\(xs1, xs2, xs3) -> (trim xs1, trim xs2, trim xs3)) (I.unzip3 xs) == L.unzip3 (trim xs) , testProperty "unzip4" $ \(Blind (xs :: Infinite (Int, Word, Bool, Char))) -> (\(xs1, xs2, xs3, xs4) -> (trim xs1, trim xs2, trim xs3, trim xs4)) (I.unzip4 xs) == L.unzip4 (trim xs) , testProperty "unzip5" $ \(Blind (xs :: Infinite (Int, Word, Bool, Char, Ordering))) -> (\(xs1, xs2, xs3, xs4, xs5) -> (trim xs1, trim xs2, trim xs3, trim xs4, trim xs5)) (I.unzip5 xs) == L.unzip5 (trim xs) , testProperty "unzip6" $ \(Blind (xs :: Infinite (Int, Word, Bool, Char, Ordering, String))) -> (\(xs1, xs2, xs3, xs4, xs5, xs6) -> (trim xs1, trim xs2, trim xs3, trim xs4, trim xs5, trim xs6)) (I.unzip6 xs) == L.unzip6 (trim xs) , testProperty "unzip7" $ \(Blind (xs :: Infinite (Int, Word, Bool, Char, Ordering, String, Integer))) -> (\(xs1, xs2, xs3, xs4, xs5, xs6, xs7) -> (trim xs1, trim xs2, trim xs3, trim xs4, trim xs5, trim xs6, trim xs7)) (I.unzip7 xs) == L.unzip7 (trim xs) , testProperty "lines" $ \(Blind (xs :: Infinite Char)) -> I.take 3 (I.lines xs) == L.take 3 (L.lines (I.foldr (:) xs)) , testProperty "lines laziness 1" $ L.head (I.head (I.lines ('q' :< undefined))) == 'q' , testProperty "lines laziness 2" $ L.null (I.head (I.lines ('\n' :< undefined))) , testProperty "words" $ \(Blind (xs :: Infinite Char)) -> I.take 3 (I.map NE.toList (I.words xs)) == L.take 3 (L.words (I.foldr (:) xs)) , testProperty "words laziness" $ NE.head (I.head (I.words ('q' :< undefined))) == 'q' , testProperty "unlines" $ \(Blind (xs :: Infinite [Char])) -> trim (I.unlines xs) == L.take 10 (L.unlines (trim xs)) , testProperty "unlines laziness" $ I.take 2 (I.unlines ("q" :< undefined)) == "q\n" , testProperty "unwords" $ \(Blind (xs :: Infinite (NonEmpty Char))) -> trim (I.unwords xs) == L.take 10 (L.unwords (L.map NE.toList (trim xs))) , testProperty "unwords laziness" $ I.take 2 (I.unwords (('q' :| []) :< undefined)) == "q " , testProperty "group" $ \(Blind (ys :: Infinite Ordering)) -> trim (I.group ys) == L.take 10 (NE.group (I.foldr (:) ys)) , testProperty "group laziness" $ NE.head (I.head (I.group ('q' :< undefined))) == 'q' , testProperty "nub" $ \(Blind (ys :: Infinite (Large Int))) -> I.take 3 (I.nub ys) == L.take 3 (L.nub (I.foldr (:) ys)) , testProperty "nub laziness" $ I.head (I.nub ('q' :< undefined)) == 'q' , testProperty "delete" $ \(x :: Ordering) (Blind xs) -> trim (I.delete x xs) == L.take 10 (L.delete x (I.foldr (:) xs)) , testProperty "delete laziness" $ I.head (I.delete 'q' ('w' :< undefined)) == 'w' , testProperty "insert" $ \(x :: Int) (Blind xs) -> trim (I.insert x xs) == L.take 10 (L.insert x (I.foldr (:) xs)) , testProperty "insert laziness" $ I.take 2 (I.insert 'q' ('w' :< undefined)) == "qw" , testProperty "\\\\" $ \(Blind (xs :: Infinite Ordering)) ys -> trim (xs I.\\ ys) == L.take 10 (I.foldr (:) xs L.\\ ys) , testProperty "\\\\ laziness" $ I.head (('q' :< undefined) I.\\ []) == 'q' , testProperty "union" $ \xs (Blind (ys :: Infinite Ordering)) -> I.take 3 (I.union xs ys) == L.take 3 (xs `L.union` I.foldr (:) ys) , testProperty "union laziness" $ I.head (I.union ('q' : undefined) undefined) == 'q' , testProperty "intersect" $ \(Blind (xs :: Infinite Ordering)) ys -> not (null ys) ==> I.head (I.intersect xs ys) == L.head (I.foldr (:) xs `L.intersect` ys) , testProperty "intersect laziness" $ I.head (I.intersect ('q' :< undefined) ('q' : undefined)) == 'q' , testProperty "inits" $ \(Blind (xs :: Infinite Int)) -> I.take 21 (I.inits xs) == L.inits (I.take 20 xs) , testProperty "inits laziness 1" $ L.null (I.head (I.inits undefined)) , testProperty "inits laziness 2" $ I.take 2 (I.inits ('q' :< undefined)) == ["", "q"] , testProperty "inits1" $ \(Blind (xs :: Infinite Int)) -> map NE.toList (trim (I.inits1 xs)) == L.tail (L.inits (trim xs)) , testProperty "tails" $ \(Blind (xs :: Infinite Int)) -> map trim (trim (I.tails xs)) === map (L.take 10) (L.take 10 (L.tails (I.take 20 xs))) , testProperty "tails laziness" $ I.head (I.head (I.tails ('q' :< undefined))) == 'q' , testProperty "lookup" $ \(xs :: [(Int, Word)]) y zs -> let pairs = NE.fromList (xs ++ (y : zs)) in Just (I.lookup (fst y) (I.cycle pairs)) == L.lookup (fst y) (NE.toList pairs) , testProperty "lookup laziness" $ I.lookup True ((True, 'q') :< undefined) == 'q' , testProperty "find" $ \(xs :: [(Int, Word)]) y zs -> let pairs = NE.fromList (xs ++ (y : zs)) in Just (I.find ((== snd y) . snd) (I.cycle pairs)) == L.find ((== snd y) . snd) (NE.toList pairs) , testProperty "find laziness" $ I.find odd (1 :< undefined) == (1 :: Int) , testProperty "filter" $ \(applyFun -> f :: Int -> Bool) xs (Blind ys) -> let us = L.filter f xs in us == I.take (length us) (I.filter f (I.prependList xs ys)) , testProperty "partition" $ \(applyFun -> f :: Int -> Bool) xs (Blind ys) -> let (us, vs) = L.partition f xs in let (us', vs') = I.partition f (I.prependList xs ys) in us == I.take (length us) us' && vs == I.take (length vs) vs' , testProperty "!!" $ \(Blind (xs :: Infinite Int)) n -> xs I.!! n == I.foldr (:) xs L.!! fromIntegral n , testProperty "tabulate" $ \(applyFun -> f :: Word -> Char) n -> I.tabulate f I.!! n == f n , testProperty "elemIndex" $ \xs (x :: Int) (Blind ys) -> let zs = I.prependList xs (x :< ys) in Just (fromIntegral (I.elemIndex x zs)) == L.elemIndex x (I.foldr (:) zs) , testProperty "elemIndices" $ \xs (x :: Ordering) (Blind ys) -> let zs = I.prependList xs (x :< ys) in let is = L.elemIndices x (xs ++ [x]) in map fromIntegral (I.take (length is) (I.elemIndices x zs)) == is ]