infinite-list 0.1 → 0.1.1
raw patch · 7 files changed
+423/−305 lines, 7 filesdep ~basedep ~ghc-primPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, ghc-prim
API changes (from Hackage documentation)
+ Data.List.Infinite: catMaybes :: Infinite (Maybe a) -> Infinite a
+ Data.List.Infinite: infix 0 ....
+ Data.List.Infinite: mapEither :: (a -> Either b c) -> Infinite a -> (Infinite b, Infinite c)
+ Data.List.Infinite: mapMaybe :: (a -> Maybe b) -> Infinite a -> Infinite b
+ Data.List.Infinite: partitionEithers :: Infinite (Either a b) -> (Infinite a, Infinite b)
Files
- CHANGELOG.md +11/−0
- README.md +7/−0
- infinite-list.cabal +22/−5
- src/Data/List/Infinite.hs +200/−154
- src/Data/List/Infinite/Internal.hs +3/−0
- test/Fusion.hs +0/−8
- test/Properties.hs +180/−138
CHANGELOG.md view
@@ -1,3 +1,14 @@+# 0.1.1++* Add `mapMaybe` and `catMaybes`.+* Add `mapEither` and `partitionEithers`.+* Decrease operator precedence for `(...)` and `(....)`.+* Add fusion rules for `genericTake`.+* Remove harmful fusion rules for `drop` and `dropWhile`.+ Cf. https://gitlab.haskell.org/ghc/ghc/-/issues/23021.+* Fix `instance Monad Infinite` on 32-bit machines.+ It was violating monad laws once the index exceeds 2^32.+ # 0.1 * Initial release.
README.md view
@@ -55,6 +55,13 @@ map f ~(a :| as) = f a :| fmap f as ``` +which is equivalent to++```haskell+map :: (a -> b) -> NonEmpty a -> NonEmpty b+map f x = (let a :| _ = x in f a) :| (let _ :| as = x in fmap f as)+```+ Because of it forcing the result to WHNF does not force any of the arguments, e. g., ``Data.List.NonEmpty.map undefined undefined `seq` 1`` returns `1`. This is not the case for normal lists: since there are two constructors, `map` has to inspect the argument before returning anything, and ``Data.List.map undefined undefined `seq` 1`` throws an error. While `Data.List.Infinite` has a single constructor, we believe that following the example of `Data.List.NonEmpty` is harmful for the majority of applications. Instead the laziness of the API is modeled on the laziness of respective operations on `Data.List`: a function `Data.List.Infinite.foo` operating over `Infinite a` is expected to have the same strictness properties as `Data.List.foo` operating over `[a]`. For instance, ``Data.List.Infinite.map undefined undefined `seq` 1`` diverges.
infinite-list.cabal view
@@ -1,13 +1,14 @@-cabal-version: 1.18+cabal-version: 2.2 name: infinite-list-version: 0.1-license: BSD3+version: 0.1.1+license: BSD-3-Clause license-file: LICENSE maintainer: andrew.lelechenko@gmail.com author: Bodigrim tested-with: ghc ==8.0.2 ghc ==8.2.2 ghc ==8.4.4 ghc ==8.6.5 ghc ==8.8.4- ghc ==8.10.7 ghc ==9.0.2 ghc ==9.2.5 ghc ==9.4.3+ ghc ==8.10.7 ghc ==9.0.2 ghc ==9.2.8 ghc ==9.4.8 ghc ==9.6.3+ ghc ==9.8.1 homepage: https://github.com/Bodigrim/infinite-list synopsis: Infinite lists@@ -50,7 +51,7 @@ build-depends: base >=4.9 && <5 if impl(ghc <8.2)- build-depends: ghc-prim+ build-depends: ghc-prim <1 test-suite infinite-properties type: exitcode-stdio-1.0@@ -65,6 +66,19 @@ tasty, tasty-quickcheck +test-suite infinite-properties-O0+ type: exitcode-stdio-1.0+ main-is: Properties.hs+ hs-source-dirs: test+ default-language: Haskell2010+ ghc-options: -Wall -O0+ build-depends:+ base,+ infinite-list,+ QuickCheck,+ tasty,+ tasty-quickcheck+ test-suite infinite-fusion type: exitcode-stdio-1.0 main-is: Fusion.hs@@ -91,3 +105,6 @@ base, infinite-list, tasty-bench++ if impl(ghc >=8.6)+ ghc-options: -fproc-alignment=64
src/Data/List/Infinite.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}-{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-}@@ -85,10 +84,14 @@ stripPrefix, -- * Searching+ filter, lookup, find,- filter,+ mapMaybe,+ catMaybes, partition,+ mapEither,+ partitionEithers, -- * Indexing (!!),@@ -152,12 +155,14 @@ import Data.Bits ((.&.)) import Data.Char (Char, isSpace) import Data.Coerce (coerce)+import Data.Either (Either, either) import Data.Eq (Eq, (/=), (==)) import qualified Data.Foldable as F import Data.Functor (Functor (..)) import qualified Data.List as List import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE+import Data.Maybe (maybe) import Data.Ord (Ord, Ordering (..), compare, (<), (<=), (>), (>=)) import qualified GHC.Exts import Numeric.Natural (Natural)@@ -173,7 +178,8 @@ import Data.List.Infinite.Zip -- | Right-associative fold of an infinite list, necessarily lazy in the accumulator.--- Any unconditional attempt to force the accumulator even to WHNF+-- Any unconditional attempt to force the accumulator even+-- to the weak head normal form (WHNF) -- will hang the computation. E. g., the following definition isn't productive: -- -- > import Data.List.NonEmpty (NonEmpty(..))@@ -182,6 +188,8 @@ -- One should use lazy patterns, e. g., -- -- > toNonEmpty = foldr (\a ~(x :| xs) -> a :| x : xs)+--+-- This is a catamorphism on infinite lists. foldr :: (a -> b -> b) -> Infinite a -> b foldr f = go where@@ -197,7 +205,14 @@ cons x (g cons) #-} --- | Convert to a list. Use 'cycle' to go in another direction.+-- | Paramorphism on infinite lists.+para :: forall a b. (a -> Infinite a -> b -> b) -> Infinite a -> b+para f = go+ where+ go :: Infinite a -> b+ go (x :< xs) = f x xs (go xs)++-- | Convert to a list. Use 'cycle' to go in the opposite direction. toList :: Infinite a -> [a] toList = foldr (:) {-# NOINLINE [0] toList #-}@@ -208,7 +223,7 @@ GHC.Exts.build (\cons -> const (foldr cons xs)) #-} --- | Generate infinite sequences, starting from a given element,+-- | Generate an infinite progression, starting from a given element, -- similar to @[x..]@. -- For better user experience consider enabling @{\-# LANGUAGE PostfixOperators #-\}@: --@@ -221,10 +236,16 @@ -- >>> :set -XPostfixOperators -- >>> Data.List.Infinite.take 10 (EQ...) -- [EQ,GT,EQ,GT,EQ,GT,EQ,GT,EQ,GT]+--+-- Remember that 'Int' is a finite type as well. One is unlikely to hit this+-- on a 64-bit architecture, but on a 32-bit machine it's fairly possible to traverse+-- @((0 :: 'Int') ...)@ far enough to encounter @0@ again. (...) :: Enum a => a -> Infinite a (...) = unsafeCycle . enumFrom {-# INLINE [0] (...) #-} +infix 0 ...+ {-# RULES "ellipsis3Int" (...) = ellipsis3Int "ellipsis3Word" (...) = ellipsis3Word@@ -248,7 +269,7 @@ ellipsis3Natural = iterate' (+ 1) {-# INLINE ellipsis3Natural #-} --- | Generate infinite sequences, starting from given elements,+-- | Generate an infinite arithmetic progression, starting from given elements, -- similar to @[x,y..]@. -- For better user experience consider enabling @{\-# LANGUAGE PostfixOperators #-\}@: --@@ -261,10 +282,16 @@ -- >>> :set -XPostfixOperators -- >>> Data.List.Infinite.take 10 ((EQ,GT)....) -- [EQ,GT,EQ,GT,EQ,GT,EQ,GT,EQ,GT]+--+-- Remember that 'Int' is a finite type as well: for a sufficiently large+-- step of progression @y - x@ one may observe @((x :: Int, y)....)@ cycling back+-- to emit @x@ fairly soon. (....) :: Enum a => (a, a) -> Infinite a (....) = unsafeCycle . uncurry enumFromThen {-# INLINE [0] (....) #-} +infix 0 ....+ {-# RULES "ellipsis4Int" (....) = ellipsis4Int "ellipsis4Word" (....) = ellipsis4Word@@ -322,15 +349,19 @@ -- | 'Control.Applicative.ZipList' cannot be made a lawful 'Monad', -- but 'Infinite', being a--- <https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable Representable>,+-- [@Representable@](https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable), -- can. Namely, 'Control.Monad.join' -- picks up a diagonal of an infinite matrix of 'Infinite' ('Infinite' @a@).--- This is mostly useful for parallel list comprehensions once--- @{\-# LANGUAGE MonadComprehensions #-\}@ is enabled.+-- Bear in mind that this instance gets slow+-- very soon because of linear indexing, so it is not recommended to be used+-- in practice. instance Monad Infinite where xs >>= f = go 0 xs where- go n (y :< ys) = f y !! n :< go (n + 1) ys+ go !n (y :< ys) = (f y `index` n) :< go (n + 1) ys+ index :: Infinite a -> Natural -> a+ index ys n = head (genericDrop n ys)+ {-# INLINE (>>=) #-} (>>) = (*>) -- | Get the first elements of an infinite list.@@ -379,6 +410,10 @@ #-} -- | Flatten out an infinite list of non-empty lists.+--+-- The peculiar type with 'NonEmpty' is to guarantee that 'concat'+-- is productive and results in an infinite list. Otherwise the+-- concatenation of infinitely many @[a]@ could still be a finite list. concat :: Infinite (NonEmpty a) -> Infinite a concat = foldr (\(x :| xs) acc -> x :< (xs `prependList` acc)) {-# NOINLINE [1] concat #-}@@ -390,6 +425,10 @@ #-} -- | First 'map' every element, then 'concat'.+--+-- The peculiar type with 'NonEmpty' is to guarantee that 'concatMap'+-- is productive and results in an infinite list. Otherwise the+-- concatenation of infinitely many @[b]@ could still be a finite list. concatMap :: (a -> NonEmpty b) -> Infinite a -> Infinite b concatMap f = foldr (\a acc -> let (x :| xs) = f a in x :< (xs `prependList` acc)) {-# NOINLINE [1] concatMap #-}@@ -417,6 +456,10 @@ -- | Insert a non-empty list between adjacent elements of an infinite list, -- and subsequently flatten it out.+--+-- The peculiar type with 'NonEmpty' is to guarantee that 'intercalate'+-- is productive and results in an infinite list. If separator is an empty list,+-- concatenation of infinitely many @[a]@ could still be a finite list. intercalate :: NonEmpty a -> Infinite [a] -> Infinite a intercalate ~(a :| as) = foldr (\xs -> prependList xs . (a :<) . prependList as) {-# NOINLINE [1] intercalate #-}@@ -430,7 +473,7 @@ -- | Transpose rows and columns of an argument. -- -- This is actually @distribute@ from--- <https://hackage.haskell.org/package/distributive/docs/Data-Distributive.html#t:Distributive Distributive>+-- [@Distributive@](https://hackage.haskell.org/package/distributive/docs/Data-Distributive.html#t:Distributive) -- type class in disguise. transpose :: Functor f => f (Infinite a) -> Infinite (f a) transpose xss = fmap head xss :< transpose (fmap tail xss)@@ -441,9 +484,12 @@ -- | Generate an infinite list of all non-empty subsequences of the argument. subsequences1 :: Infinite a -> Infinite (NonEmpty a)-subsequences1 (x :< xs) = (x :| []) :< foldr f (subsequences1 xs)+subsequences1 = foldr go where- f ys r = ys :< (x `NE.cons` ys) :< r+ go :: a -> Infinite (NonEmpty a) -> Infinite (NonEmpty a)+ go x sxs = (x :| []) :< foldr f sxs+ where+ f ys r = ys :< (x `NE.cons` ys) :< r -- | Generate an infinite list of all permutations of the argument. permutations :: Infinite a -> Infinite (Infinite a)@@ -461,12 +507,12 @@ where (us, zs) = interleaveList' (f . (y :<)) ys r --- |+-- | Fold an infinite list from the left and return a list of successive reductions,+-- starting from the initial accumulator:+-- -- > scanl f acc (x1 :< x2 :< ...) = acc :< f acc x1 :< f (f acc x1) x2 :< ... scanl :: (b -> a -> b) -> b -> Infinite a -> Infinite b-scanl f = go- where- go z ~(x :< xs) = z :< go (f z x) xs+scanl f z0 = (z0 :<) . flip (foldr (\x acc z -> let fzx = f z x in fzx :< acc fzx)) z0 scanlFB :: (elt' -> elt -> elt') -> (elt' -> lst -> lst) -> elt -> (elt' -> lst) -> elt' -> lst scanlFB f cons = \elt g -> oneShot (\x -> let elt' = f x elt in elt' `cons` g elt')@@ -486,9 +532,7 @@ -- | Same as 'scanl', but strict in accumulator. scanl' :: (b -> a -> b) -> b -> Infinite a -> Infinite b-scanl' f = go- where- go !z ~(x :< xs) = z :< go (f z x) xs+scanl' f z0 = (z0 :<) . flip (foldr (\x acc z -> let !fzx = f z x in fzx :< acc fzx)) z0 scanlFB' :: (elt' -> elt -> elt') -> (elt' -> lst -> lst) -> elt -> (elt' -> lst) -> elt' -> lst scanlFB' f cons = \elt g -> oneShot (\x -> let !elt' = f x elt in elt' `cons` g elt')@@ -506,24 +550,25 @@ tail (scanl' f a bs) #-} --- |+-- | Fold an infinite list from the left and return a list of successive reductions,+-- starting from the first element:+-- -- > scanl1 f (x0 :< x1 :< x2 :< ...) = x0 :< f x0 x1 :< f (f x0 x1) x2 :< ... scanl1 :: (a -> a -> a) -> Infinite a -> Infinite a scanl1 f (x :< xs) = scanl f x xs --- | If you are looking how to traverse with a state, look no further:+-- | Fold an infinite list from the left and return a list of successive reductions,+-- keeping accumulator in a state: -- -- > mapAccumL f acc0 (x1 :< x2 :< ...) = -- > let (acc1, y1) = f acc0 x1 in -- > let (acc2, y2) = f acc1 x2 in -- > ... -- > y1 :< y2 :< ...+--+-- If you are looking how to traverse with a state, look no further. mapAccumL :: (acc -> x -> (acc, y)) -> acc -> Infinite x -> Infinite y-mapAccumL f = go- where- go s (x :< xs) = y :< go s' xs- where- (s', y) = f s x+mapAccumL f = flip (foldr (\x acc s -> let (s', y) = f s x in y :< acc s')) mapAccumLFB :: (acc -> x -> (acc, y)) -> x -> (acc -> Infinite y) -> acc -> Infinite y mapAccumLFB f = \x r -> oneShot (\s -> let (s', y) = f s x in y :< r s')@@ -604,6 +649,9 @@ -- | Repeat a non-empty list ad infinitum. -- If you were looking for something like @fromList :: [a] -> Infinite a@, -- look no further.+--+-- It would be less annoying to take @[a]@ instead of 'NonEmpty' @a@,+-- but we strive to avoid partial functions. cycle :: NonEmpty a -> Infinite a cycle (x :| xs) = unsafeCycle (x : xs) {-# INLINE cycle #-}@@ -628,6 +676,8 @@ #-} -- | Build an infinite list from a seed value.+--+-- This is an anamorphism on infinite lists. unfoldr :: (b -> (a, b)) -> b -> Infinite a unfoldr f = go where@@ -637,7 +687,7 @@ -- | Generate an infinite list of @f@ 0, @f@ 1, @f@ 2... -- -- 'tabulate' and '(!!)' witness that 'Infinite' is--- <https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable Representable>.+-- [@Representable@](https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable). tabulate :: (Word -> a) -> Infinite a tabulate f = unfoldr (\n -> (f n, n + 1)) 0 {-# INLINE tabulate #-}@@ -645,70 +695,46 @@ -- | Take a prefix of given length. take :: Int -> Infinite a -> [a] take = GHC.Exts.inline genericTake--takeFB :: (elt -> lst -> lst) -> lst -> elt -> (Int -> lst) -> Int -> lst-takeFB cons nil x xs = \m -> if m <= 1 then x `cons` nil else x `cons` xs (m - 1)- {-# INLINE [1] take #-} -{-# INLINE [0] takeFB #-}+{-# INLINE [1] genericTake #-} +{-# INLINE [0] genericTakeFB #-}+ {-# RULES-"take" [~1] forall n xs.- take n xs =+"take"+ take =+ genericTake+"genericTake" [~1] forall n xs.+ genericTake n xs = GHC.Exts.build ( \cons nil -> if n >= 1- then foldr (takeFB cons nil) xs n+ then foldr (genericTakeFB cons nil) xs n else nil )-"takeList" [1] forall n xs.- foldr (takeFB (:) []) xs n =- take n xs+"genericTakeList" [1] forall n xs.+ foldr (genericTakeFB (:) []) xs n =+ genericTake n xs #-} -- | Take a prefix of given length. genericTake :: Integral i => i -> Infinite a -> [a] genericTake n | n < 1 = const []- | otherwise = unsafeTake n- where- unsafeTake 1 (x :< _) = [x]- unsafeTake m (x :< xs) = x : unsafeTake (m - 1) xs+ | otherwise = flip (foldr (\hd f m -> hd : (if m <= 1 then [] else f (m - 1)))) n +genericTakeFB :: Integral i => (elt -> lst -> lst) -> lst -> elt -> (i -> lst) -> i -> lst+genericTakeFB cons nil x xs = \m -> if m <= 1 then x `cons` nil else x `cons` xs (m - 1)+ -- | Drop a prefix of given length. drop :: Int -> Infinite a -> Infinite a drop = GHC.Exts.inline genericDrop -dropFB :: (elt -> lst -> lst) -> elt -> (Int -> lst) -> Int -> lst-dropFB cons x xs = \m -> if m < 1 then x `cons` xs m else xs (m - 1)--{-# INLINE [1] drop #-}--{-# INLINE [0] dropFB #-}--{-# RULES-"drop" [~1] forall n xs.- drop n xs =- build- ( \cons ->- if n >= 1- then foldr (dropFB cons) xs n- else foldr cons xs- )-"dropList" [1] forall n xs.- foldr (dropFB (:<)) xs n =- drop n xs- #-}- -- | Drop a prefix of given length. genericDrop :: Integral i => i -> Infinite a -> Infinite a-genericDrop n- | n < 1 = id- | otherwise = unsafeDrop n- where- unsafeDrop 1 (_ :< xs) = xs- unsafeDrop m (_ :< xs) = unsafeDrop (m - 1) xs+genericDrop = flip (para (\hd tl f m -> if m < 1 then hd :< tl else f (m - 1)))+{-# INLINEABLE genericDrop #-} -- | Split an infinite list into a prefix of given length and the rest. splitAt :: Int -> Infinite a -> ([a], Infinite a)@@ -718,18 +744,12 @@ genericSplitAt :: Integral i => i -> Infinite a -> ([a], Infinite a) genericSplitAt n | n < 1 = ([],)- | otherwise = unsafeSplitAt n- where- unsafeSplitAt 1 (x :< xs) = ([x], xs)- unsafeSplitAt m (x :< xs) = first (x :) (unsafeSplitAt (m - 1) xs)+ | otherwise = flip (para (\hd tl f m -> if m <= 1 then ([hd], tl) else first (hd :) (f (m - 1)))) n+{-# INLINEABLE genericSplitAt #-} -- | Take the longest prefix satisfying a predicate. takeWhile :: (a -> Bool) -> Infinite a -> [a]-takeWhile p = go- where- go (x :< xs)- | p x = x : go xs- | otherwise = []+takeWhile p = foldr (\x xs -> if p x then x : xs else []) takeWhileFB :: (elt -> Bool) -> (elt -> lst -> lst) -> lst -> elt -> lst -> lst takeWhileFB p cons nil = \x r -> if p x then x `cons` r else nil@@ -752,27 +772,7 @@ -- This function isn't productive (e. g., 'head' . 'dropWhile' @f@ won't terminate), -- if all elements of the input list satisfy the predicate. dropWhile :: (a -> Bool) -> Infinite a -> Infinite a-dropWhile p = go- where- go xxs@(x :< xs)- | p x = go xs- | otherwise = xxs--dropWhileFB :: (elt -> Bool) -> (elt -> lst -> lst) -> elt -> (Bool -> lst) -> (Bool -> lst)-dropWhileFB p cons = \x r drp -> if drp && p x then r True else x `cons` r False--{-# NOINLINE [1] dropWhile #-}--{-# INLINE [0] dropWhileFB #-}--{-# RULES-"dropWhile" [~1] forall p xs.- dropWhile p xs =- build (\cons -> foldr (dropWhileFB p cons) xs True)-"dropWhileList" [1] forall p xs.- foldr (dropWhileFB p (:<)) xs True =- dropWhile p xs- #-}+dropWhile p = para (\x xs -> if p x then id else const (x :< xs)) -- | Split an infinite list into the longest prefix satisfying a predicate and the rest. --@@ -780,11 +780,7 @@ -- (e. g., 'head' . 'snd' . 'span' @f@ won't terminate), -- if all elements of the input list satisfy the predicate. span :: (a -> Bool) -> Infinite a -> ([a], Infinite a)-span p = go- where- go xxs@(x :< xs)- | p x = first (x :) (go xs)- | otherwise = ([], xxs)+span p = para (\x xs -> if p x then first (x :) else const ([], x :< xs)) -- | Split an infinite list into the longest prefix /not/ satisfying a predicate and the rest. --@@ -797,10 +793,12 @@ -- | If a list is a prefix of an infinite list, strip it and return the rest. -- Otherwise return 'Nothing'. stripPrefix :: Eq a => [a] -> Infinite a -> Maybe (Infinite a)-stripPrefix [] ys = Just ys-stripPrefix (x : xs) (y :< ys)- | x == y = stripPrefix xs ys- | otherwise = Nothing+stripPrefix [] = Just+stripPrefix (p : ps) = flip (para alg) (p :| ps)+ where+ alg x xs acc (y :| ys)+ | x == y = maybe (Just xs) acc (NE.nonEmpty ys)+ | otherwise = Nothing -- | Group consecutive equal elements. group :: Eq a => Infinite a -> Infinite (NonEmpty a)@@ -808,6 +806,9 @@ -- | Overloaded version of 'group'. groupBy :: (a -> a -> Bool) -> Infinite a -> Infinite (NonEmpty a)+-- Quite surprisingly, 'groupBy' is not a simple catamorphism.+-- Since @f@ is not guaranteed to be transitive, it's a full-blown+-- histomorphism, at which point a manual recursion becomes much more readable. groupBy f = go where go (x :< xs) = (x :| ys) :< go zs@@ -846,10 +847,10 @@ -- | Check whether a list is a prefix of an infinite list. isPrefixOf :: Eq a => [a] -> Infinite a -> Bool-isPrefixOf [] _ = True-isPrefixOf (x : xs) (y :< ys)- | x == y = isPrefixOf xs ys- | otherwise = False+isPrefixOf [] = const True+isPrefixOf (p : ps) = flip (foldr alg) (p :| ps)+ where+ alg x acc (y :| ys) = x == y && maybe True acc (NE.nonEmpty ys) -- | Find the first pair, whose first component is equal to the first argument, -- and return the second component.@@ -866,6 +867,13 @@ -- -- This function isn't productive (e. g., 'head' . 'filter' @f@ won't terminate), -- if no elements of the input list satisfy the predicate.+--+-- A common objection is that since it could happen that no elements of the input+-- satisfy the predicate, the return type should be @[a]@ instead of 'Infinite' @a@.+-- This would not however make 'filter' any more productive. Note that such+-- hypothetical 'filter' could not ever generate @[]@ constructor, only @(:)@, so+-- we would just have a more lax type gaining nothing instead. Same reasoning applies+-- to other filtering \/ partitioning \/ searching functions. filter :: (a -> Bool) -> Infinite a -> Infinite a filter f = foldr (\a -> if f a then (a :<) else id) @@ -906,13 +914,10 @@ -- to avoid 'Prelude.error' on negative arguments. -- -- This is actually @index@ from--- <https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable Representable>+-- [@Representable@](https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#t:Representable) -- type class in disguise. (!!) :: Infinite a -> Word -> a-(!!) = flip go- where- go 0 (x :< _) = x- go !m (_ :< ys) = go (m - 1) ys+(!!) = foldr (\x acc m -> if m == 0 then x else acc (m - 1)) infixl 9 !! @@ -931,20 +936,14 @@ -- | Return an index of the first element, satisfying a predicate. -- If there is nothing to be found, this function will hang indefinitely. findIndex :: (a -> Bool) -> Infinite a -> Word-findIndex f = go 0- where- go !n (x :< xs)- | f x = n- | otherwise = go (n + 1) xs+findIndex f = flip (foldr (\x acc !m -> if f x then m else acc (m + 1))) 0 -- | Return indices of all elements, satisfying a predicate. -- -- This function isn't productive (e. g., 'head' . 'elemIndices' @f@ won't terminate), -- if no elements of the input list satisfy the predicate. findIndices :: (a -> Bool) -> Infinite a -> Infinite Word-findIndices f = go 0- where- go !n (x :< xs) = (if f x then (n :<) else id) (go (n + 1) xs)+findIndices f = flip (foldr (\x acc !m -> (if f x then (m :<) else id) (acc (m + 1)))) 0 -- | Unzip an infinite list of tuples. unzip :: Infinite (a, b) -> (Infinite a, Infinite b)@@ -976,30 +975,49 @@ unzip7 = foldr (\(a, b, c, d, e, f, g) ~(as, bs, cs, ds, es, fs, gs) -> (a :< as, b :< bs, c :< cs, d :< ds, e :< es, f :< fs, g :< gs)) {-# INLINE unzip7 #-} --- | Split an infinite string into lines, by @\\n@.+-- | Split an infinite string into lines, by @\\n@. Empty lines are preserved.+--+-- In contrast to their counterparts from "Data.List", it holds that+-- 'unlines' @.@ 'lines' @=@ 'id'. lines :: Infinite Char -> Infinite [Char]-lines xs = l :< lines xs'+lines = foldr go where- (l, ~(_ :< xs')) = break (== '\n') xs+ go '\n' xs = [] :< xs+ go c ~(x :< xs) = (c : x) :< xs -- | Concatenate lines together with @\\n@.+--+-- In contrast to their counterparts from "Data.List", it holds that+-- 'unlines' @.@ 'lines' @=@ 'id'. unlines :: Infinite [Char] -> Infinite Char unlines = foldr (\l xs -> l `prependList` ('\n' :< xs)) -- | Split an infinite string into words, by any 'isSpace' symbol.+-- Leading spaces are removed and, as underlined by the return type,+-- repeated spaces are treated as a single delimiter. words :: Infinite Char -> Infinite (NonEmpty Char)-words xs = (u :| us) :< words vs+-- This is fundamentally a zygomorphism with 'isSpace' . 'head' as the small algebra.+-- But manual implementation via catamorphism requires twice less calls of 'isSpace'.+words = uncurry repack . foldr go where- u :< ys = dropWhile isSpace xs- (us, vs) = break isSpace ys+ repack zs acc = maybe acc (:< acc) (NE.nonEmpty zs) + go x ~(zs, acc) = (zs', acc')+ where+ s = isSpace x+ zs' = if s then [] else x : zs+ acc' = if s then repack zs acc else acc+ wordsFB :: (NonEmpty Char -> lst -> lst) -> Infinite Char -> lst-wordsFB cons = go+wordsFB cons = uncurry repack . foldr go where- go xs = (u :| us) `cons` go vs+ repack zs acc = maybe acc (`cons` acc) (NE.nonEmpty zs)++ go x ~(zs, acc) = (zs', acc') where- u :< ys = dropWhile isSpace xs- (us, vs) = break isSpace ys+ s = isSpace x+ zs' = if s then [] else x : zs+ acc' = if s then repack zs acc else acc {-# NOINLINE [1] words #-} @@ -1011,6 +1029,10 @@ #-} -- | Concatenate words together with a space.+--+-- The function is meant to be a counterpart of with 'words'.+-- If you need to concatenate together 'Infinite' @[@'Char'@]@,+-- use 'intercalate' @(@'pure' @' ')@. unwords :: Infinite (NonEmpty Char) -> Infinite Char unwords = foldr (\(l :| ls) acc -> l :< ls `prependList` (' ' :< acc)) @@ -1032,14 +1054,7 @@ -- | Overloaded version of 'nub'. nubBy :: (a -> a -> Bool) -> Infinite a -> Infinite a-nubBy eq = go []- where- go seen (x :< xs)- | elemBy x seen = go seen xs- | otherwise = x :< go (x : seen) xs-- elemBy _ [] = False- elemBy y (x : xs) = eq x y || elemBy y xs+nubBy eq = flip (foldr (\x acc seen -> if List.any (`eq` x) seen then acc seen else x :< acc (x : seen))) [] -- | Remove all occurrences of an element from an infinite list. delete :: Eq a => a -> Infinite a -> Infinite a@@ -1047,11 +1062,7 @@ -- | Overloaded version of 'delete'. deleteBy :: (a -> b -> Bool) -> a -> Infinite b -> Infinite b-deleteBy eq x = go- where- go (y :< ys)- | eq x y = ys- | otherwise = y :< go ys+deleteBy eq x = para (\y ys acc -> if eq x y then ys else y :< acc) -- | Take an infinite list and remove the first occurrence of every element -- of a finite list.@@ -1079,11 +1090,7 @@ -- | Overloaded version of 'insert'. insertBy :: (a -> a -> Ordering) -> a -> Infinite a -> Infinite a-insertBy cmp x = go- where- go yys@(y :< ys) = case cmp x y of- GT -> y :< go ys- _ -> x :< yys+insertBy cmp x = para (\y ys acc -> case cmp x y of GT -> y :< acc; _ -> x :< y :< ys) -- | Return all elements of an infinite list, which are simultaneously -- members of a finite list.@@ -1097,3 +1104,42 @@ -- | Prepend a list to an infinite list. prependList :: [a] -> Infinite a -> Infinite a prependList = flip (F.foldr (:<))++-- | Apply a function to every element of an infinite list and collect 'Just' results.+--+-- This function isn't productive (e. g., 'head' . 'mapMaybe' @f@ won't terminate),+-- if no elements of the input list result in 'Just'.+--+-- @since 0.1.1+mapMaybe :: (a -> Maybe b) -> Infinite a -> Infinite b+mapMaybe = foldr . (maybe id (:<) .)++-- | Keep only 'Just' elements.+--+-- This function isn't productive (e. g., 'head' . 'catMaybes' won't terminate),+-- if no elements of the input list are 'Just'.+--+-- @since 0.1.1+catMaybes :: Infinite (Maybe a) -> Infinite a+catMaybes = foldr (maybe id (:<))++-- | Apply a function to every element of an infinite list and+-- separate 'Data.Either.Left' and 'Data.Either.Right' results.+--+-- This function isn't productive (e. g., 'head' . 'Data.Tuple.fst' .+-- 'mapEither' @f@ won't terminate),+-- if no elements of the input list result in 'Data.Either.Left' or 'Data.Either.Right'.+--+-- @since 0.1.1+mapEither :: (a -> Either b c) -> Infinite a -> (Infinite b, Infinite c)+mapEither = foldr . (either (first . (:<)) (second . (:<)) .)++-- | Separate 'Data.Either.Left' and 'Data.Either.Right' elements.+--+-- This function isn't productive (e. g., 'head' . 'Data.Tuple.fst' . 'partitionEithers'+-- won't terminate),+-- if no elements of the input list are 'Data.Either.Left' or 'Data.Either.Right'.+--+-- @since 0.1.1+partitionEithers :: Infinite (Either a b) -> (Infinite a, Infinite b)+partitionEithers = foldr (either (first . (:<)) (second . (:<)))
src/Data/List/Infinite/Internal.hs view
@@ -9,6 +9,9 @@ ) where -- | Type of infinite lists.+--+-- In terms of recursion schemes, 'Infinite' @a@ is a fix point of the base functor @(a,)@,+-- 'Data.List.Infinite.foldr' is a catamorphism and 'Data.List.Infinite.unfoldr' is an anamorphism. data Infinite a = a :< Infinite a infixr 5 :<
test/Fusion.hs view
@@ -67,15 +67,9 @@ takeRepeat :: Int -> [Int] takeRepeat x = I.take x (I.repeat x) -takeDropRepeat :: Int -> [Int]-takeDropRepeat x = I.take x (I.drop x (I.repeat x))- takeWhileIterate :: Int -> [Int] takeWhileIterate x = I.takeWhile (< 10) (I.iterate (+ 1) x) -takeWhileDropWhileIterate :: Int -> [Int]-takeWhileDropWhileIterate x = I.takeWhile (< 20) $ I.dropWhile (< 10) (I.iterate (+ 1) x)- foldrCycle :: NonEmpty Int -> [Int] foldrCycle xs = I.foldr (:) (I.cycle xs) @@ -261,9 +255,7 @@ , $(inspectTest $ 'foldrScanl `hasNoType` ''Word) , $(inspectTest $ 'foldrScanl' `hasNoType` ''Word) , $(inspectTest $ 'takeRepeat `hasNoType` ''Infinite)- , $(inspectTest $ 'takeDropRepeat `hasNoType` ''Infinite) , $(inspectTest $ 'takeWhileIterate `hasNoType` ''Infinite)- , $(inspectTest $ 'takeWhileDropWhileIterate `hasNoType` ''Infinite) , $(inspectTest $ 'foldrCycle `hasNoType` ''Infinite) , $(inspectTest $ 'foldrWordsCycle `hasNoType` ''NonEmpty) , $(inspectTest $ 'mapAccumLRepeat `hasNoType` ''Word)
test/Properties.hs view
@@ -7,7 +7,9 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE ViewPatterns #-} -{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -Wno-orphans #-}+{-# OPTIONS_GHC -Wno-unrecognised-warning-flags #-}+{-# OPTIONS_GHC -Wno-x-partial #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} {-# HLINT ignore "Use <$>" #-}@@ -23,13 +25,17 @@ import Control.Applicative import Control.Monad import Data.Bifunctor+import Data.Bits+import Data.Either 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 Data.Word (Word32) import Numeric.Natural+import Prelude hiding (Applicative(..)) instance Arbitrary a => Arbitrary (Infinite a) where arbitrary = (:<) <$> arbitrary <*> arbitrary@@ -47,426 +53,462 @@ mapMapFusion :: Infinite Int -> Infinite Int mapMapFusion xs = I.map fromIntegral (I.map fromIntegral xs :: Infinite Word) +mapEither :: (a -> Either b c) -> [a] -> ([b], [c])+mapEither f = foldr (either (first . (:)) (second . (:)) . f) ([], [])+ main :: IO () main = defaultMain $ testGroup "All" [ testProperty "head" $ \(Blind (xs :: Infinite Int)) ->- I.head xs == L.head (trim xs)+ I.head xs === L.head (trim xs) , testProperty "tail" $ \(Blind (xs :: Infinite Int)) ->- trim (I.tail xs) == L.tail (trim1 xs)+ trim (I.tail xs) === L.tail (trim1 xs) , testProperty "uncons" $ \(Blind (xs :: Infinite Int)) ->- Just (fmap trim (I.uncons xs)) == L.uncons (trim1 xs)+ 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)+ 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)+ trim (fmap f xs) === fmap f (trim xs) , testProperty "<$" $ \(x :: Word) (Blind (xs :: Infinite Int)) ->- trim (x <$ xs) == trim (fmap (const x) xs)+ 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))+ 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)+ trim (xs *> ys) === trim ((id <$ xs) <*> ys) , testProperty "<*" $ \(Blind (xs :: Infinite Int)) (Blind (ys :: Infinite Word)) ->- trim (xs <* ys) == trim (liftA2 const xs ys)+ 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)+ trim (return x >>= k) === trim (k x) , testProperty ">>= 2" $ \(Blind (xs :: Infinite Int)) ->- trim (xs >>= return) == trim xs+ 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)+ trim (xs >>= (k >=> h)) === trim ((xs >>= k) >>= h) , testProperty ">>" $ \(Blind (xs :: Infinite Int)) (Blind (ys :: Infinite Word)) ->- trim (xs >> ys) == trim ys+ 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))+ 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))+ 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)+ I.take 19 (I.intersperse x xs) === L.intersperse x (trim xs) , testProperty "intersperse laziness 1" $- I.head (I.intersperse undefined ('q' :< undefined)) == 'q'+ I.head (I.intersperse undefined ('q' :< undefined)) === 'q' , testProperty "intersperse laziness 2" $- I.take 2 (I.intersperse 'w' ('q' :< undefined)) == "qw"+ 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)+ 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"+ I.take 3 (I.intercalate undefined ("foo" :< undefined)) === "foo" , testProperty "intercalate laziness 2" $- I.take 6 (I.intercalate (NE.fromList "bar") ("foo" :< undefined)) == "foobar"+ 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+ 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+ 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'+ 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)+ 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)+ 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"+ I.head (I.transpose ['a' :< undefined, 'b' :< undefined]) === "ab" , testProperty "transpose laziness 2" $- I.head (I.transpose (('a' :< undefined) :| ['b' :< undefined])) == 'a' :| "b"+ 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)+ I.take 16 (I.subsequences xs) === L.subsequences (I.take 4 xs) , testProperty "subsequences laziness 1" $- I.head (I.subsequences undefined) == ""+ I.head (I.subsequences undefined) === "" , testProperty "subsequences laziness 2" $- I.take 2 (I.subsequences ('q' :< undefined)) == ["", "q"]+ 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)+ 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"]+ 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..])+ 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..])+ trim (x I....) === L.take 10 (L.cycle [x..]) , testProperty "... Word" $ \(x :: Word) ->- trim (x I....) == L.take 10 (L.cycle [x..])+ 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..])+ trim (x I....) === L.take 10 (L.cycle [x..]) , testProperty "... Integer" $ \(x :: Integer) ->- trim (x I....) == L.take 10 (L.cycle [x..])+ 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..])+ 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..])+ 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..])+ 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..])+ 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..])+ 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..])+ 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+ 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)+ trim1 (I.scanl f s xs) === L.scanl f s (trim xs) , testProperty "scanl laziness" $- I.head (I.scanl undefined 'q' undefined) == 'q'+ 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)+ trim1 (I.scanl' f s xs) === L.scanl' f s (trim xs) , testProperty "scanl' laziness" $- I.head (I.scanl' undefined 'q' undefined) == 'q'+ 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)+ trim (I.scanl1 f xs) === L.scanl1 f (trim xs) , testProperty "scanl1 laziness" $- I.head (I.scanl1 undefined ('q' :< undefined)) == 'q'+ 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))+ 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'+ 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)+ trim (I.iterate f s) === L.take 10 (L.iterate f s) , testProperty "iterate laziness" $- I.head (I.iterate undefined 'q') == 'q'+ 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)+ trim (I.iterate' f s) === L.take 10 (L.iterate f s) , testProperty "iterate' laziness" $- I.head (I.iterate' undefined 'q') == 'q'+ I.head (I.iterate' undefined 'q') === 'q' , testProperty "repeat" $ \(s :: Int) ->- trim (I.repeat s) == L.replicate 10 s+ 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))+ trim (I.cycle xs) === L.take 10 (L.cycle (NE.toList xs)) , testProperty "cycle laziness" $- I.head (I.cycle ('q' :| undefined)) == 'q'+ 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)+ trim (I.unfoldr f s) === L.take 10 (L.unfoldr (Just . f) s) , testProperty "unfoldr laziness" $- I.head (I.unfoldr (, undefined) 'q') == 'q'+ 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)+ L.take 10 (I.take n xs) === L.take n (trim xs) , testProperty "take laziness 1" $- I.take 0 undefined == ""+ I.take 0 undefined === "" , testProperty "take laziness 2" $- I.take 1 ('q' :< undefined) == "q"+ 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)+ trim (I.drop n xs) === L.drop n (I.take (max n 0 + 10) xs)+ , testProperty "drop laziness" $+ I.head (I.drop 0 ('q' :< undefined)) === 'q' , testProperty "splitAt" $ \n (Blind (xs :: Infinite Int)) ->- bimap (L.take 10) trim (I.splitAt n xs) ==+ 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) == ""+ fst (I.splitAt 0 undefined) === "" , testProperty "splitAt laziness 2" $- fst (I.splitAt 1 ('q' :< undefined)) == "q"+ 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)+ L.take 10 (L.takeWhile f (I.foldr (:) 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'+ 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 (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 (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+ 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+ 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+ 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'+ L.head (fst (I.span (/= '\n') ('q' :< undefined))) === 'q' , testProperty "break laziness" $- L.head (fst (I.break (== '\n') ('q' :< undefined))) == 'q'+ 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))+ 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)+ I.isPrefixOf xs ys === L.isPrefixOf xs (I.take (length xs + 10) ys) , testProperty "isPrefixOf laziness 1" $- not (I.isPrefixOf ('q' : undefined) ('w' :< undefined))+ I.isPrefixOf "" undefined , testProperty "isPrefixOf laziness 2" $+ not (I.isPrefixOf ('q' : undefined) ('w' :< undefined))+ , testProperty "isPrefixOf laziness 3" $ 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)+ 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)+ 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)+ 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)+ 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)+ 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)+ 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)+ 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)+ (\(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)+ (\(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)+ (\(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)+ (\(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)+ (\(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))+ 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'+ 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))+ 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'+ 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))+ trim (I.unlines xs) === L.take 10 (L.unlines (trim xs)) , testProperty "unlines laziness" $- I.take 2 (I.unlines ("q" :< undefined)) == "q\n"+ 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)))+ trim (I.unwords xs) === L.take 10 (L.unwords (L.map NE.toList (I.foldr (:) xs))) , testProperty "unwords laziness" $- I.take 2 (I.unwords (('q' :| []) :< undefined)) == "q "+ I.take 2 (I.unwords (('q' :| []) :< undefined)) === "q "+ , testProperty "unlines . lines" $+ \(Blind (xs :: Infinite Char)) ->+ I.take 100 xs === I.take 100 (I.unlines (I.lines xs)) , testProperty "group" $ \(Blind (ys :: Infinite Ordering)) ->- trim (I.group ys) == L.take 10 (NE.group (I.foldr (:) ys))+ trim (I.group ys) === L.take 10 (NE.group (I.foldr (:) ys))+ , testProperty "groupBy" $+ \(curry . applyFun -> f :: Ordering -> Ordering -> Bool) (Blind ys) ->+ all (\x -> not $ all (f x) [minBound..maxBound]) [minBound..maxBound] ==>+ trim (I.groupBy f ys) === L.take 10 (NE.groupBy f (I.foldr (:) ys)) , testProperty "group laziness" $- NE.head (I.head (I.group ('q' :< undefined))) == 'q'+ 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))+ fmap getLarge (I.take 3 (I.nub ys)) === fmap getLarge (L.take 3 (L.nub (I.foldr (:) ys))) , testProperty "nub laziness" $- I.head (I.nub ('q' :< undefined)) == 'q'+ 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))+ 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'+ 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))+ 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"+ 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)+ trim (xs I.\\ ys) === L.take 10 (I.foldr (:) xs L.\\ ys) , testProperty "\\\\ laziness" $- I.head (('q' :< undefined) I.\\ []) == 'q'+ 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)+ 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'+ 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)+ 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'+ 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)+ 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"]+ 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))+ 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'+ 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)+ 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'+ 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)+ 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)+ 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))+ us === I.take (length us) (I.filter f (I.prependList xs ys))+ , testProperty "mapMaybe" $+ \(applyFun -> f :: Int -> Maybe Word) xs (Blind ys) ->+ let us = mapMaybe f xs in+ us === I.take (length us) (I.mapMaybe f (I.prependList xs ys))+ , testProperty "catMaybes" $+ \(xs :: [Maybe Word]) (Blind ys) ->+ let us = catMaybes xs in+ us === I.take (length us) (I.catMaybes (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'+ us === I.take (length us) us' .&&. vs === I.take (length vs) vs'+ , testProperty "mapEither" $+ \(applyFun -> f :: Int -> Either Word Char) xs (Blind ys) ->+ let (us, vs) = mapEither f xs in+ let (us', vs') = I.mapEither f (I.prependList xs ys) in+ us === I.take (length us) us' .&&. vs === I.take (length vs) vs'+ , testProperty "partitionEithers" $+ \(xs :: [Either Word Char]) (Blind ys) ->+ let (us, vs) = partitionEithers xs in+ let (us', vs') = I.partitionEithers (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+ xs I.!! n === I.foldr (:) xs L.!! fromIntegral n , testProperty "tabulate" $ \(applyFun -> f :: Word -> Char) n ->- I.tabulate f I.!! n == f 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)+ 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+ map fromIntegral (I.take (length is) (I.elemIndices x zs)) === is++ , testProperty ">>= 32bit" $+ let ix = maxBound :: Word32 in+ finiteBitSize (0 :: Word) /= 32 ||+ I.head (I.tail (I.genericDrop ix (I.repeat () >>= const (False :< I.repeat True)))) ]