packages feed

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 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))))   ]