@@ -9,9 +9,12 @@
99--
1010module Main (main) where
1111
12+import Streamly.Internal.Data.Unfold (Unfold)
13+
1214import qualified Streamly.Internal.Data.Unfold as UF
1315import qualified Streamly.Internal.Data.Stream.IsStream as S
14−import qualified Prelude as P
16+import qualified Prelude
17+import qualified Data.List as List
1518
1619import Control.Monad.Trans.State.Strict
1720import Data.Functor.Identity
@@ -22,208 +25,191 @@ import Test.Hspec.QuickCheck
2225import Test.QuickCheck
2326import Test.QuickCheck.Function
2427
25−fromStream :: Property
26−fromStream =
27− property $ \n -> do
28− let strm = S.fromList n :: SerialT IO Int
29− n1 <- S.toList $ S.unfold UF.fromStream strm
30− n1 `shouldBe` (n :: [Int])
28+-- We check for side effects in most cases
29+
30+-------------------------------------------------------------------------------
31+-- Helper functions
32+-------------------------------------------------------------------------------
33+
34+testUnfoldA ::
35+ (Eq s, Eq b) => Unfold (State s) a b -> s -> s -> a -> [b] -> Bool
36+testUnfoldA unf si sf seed lst = evalState action si
3137
32−nilM :: Bool
33−nilM = evalState action undefined
3438 where
39+
3540 action = do
36− x <- S.toList $ S.unfold (UF.nilM put) (1 :: Int)
41+ x <- S.toList $ S.unfold unf seed
3742 y <- get
38− return $ x == ([] :: [Int]) && y == 1
43+ return $ x == lst && y == sf
44+
45+testUnfoldAD :: Unfold (State Int) a Int -> Int -> Int -> a -> [Int] -> Bool
46+testUnfoldAD = testUnfoldA
47+
48+testUnfold :: Eq b => Unfold Identity a b -> a -> [b] -> Bool
49+testUnfold unf seed lst = runIdentity action
50+
51+ where
3952
40−consM :: Bool
41−consM = evalState action 0
42− where
4353 action = do
44− x <-
45− S.toList $
46− S.unfold
47− (UF.consM (\a -> modify (+ a) >> get) $
48− UF.consM (\a -> modify (+ a) >> get) $ UF.nilM put)
49− 1
50− y <- get
51− return $ x == ([1, 2] :: [Int]) && y == 1
54+ x <- S.toList $ S.unfold unf seed
55+ return $ x == lst
56+
57+testUnfoldD :: Unfold Identity a Int -> a -> [Int] -> Bool
58+testUnfoldD = testUnfold
59+
60+-------------------------------------------------------------------------------
61+-- Stream generation
62+-------------------------------------------------------------------------------
63+
64+fromStream :: Property
65+fromStream =
66+ property
67+ $ \n ->
68+ testUnfoldD UF.fromStream (S.fromList n :: SerialT Identity Int) n
69+
70+nilM :: Bool
71+nilM =
72+ let unf = UF.nilM put
73+ in testUnfoldAD unf 0 1 1 []
74+
75+consM :: Bool
76+consM =
77+ let cns = UF.consM (\a -> modify (+ a) >> get)
78+ unf = cns $ cns $ UF.nilM $ \a -> modify (+ a)
79+ in testUnfoldAD unf 0 3 1 [1, 2]
5280
5381effect :: Bool
54−effect = evalState action undefined
55− where
56− action = do
57− x <- S.toList $ S.unfold (UF.effect (put (1 :: Int))) undefined
58− y <- get
59− return $ x == [()] && y == 1
82+effect =
83+ let unf = UF.effect (modify (+ 1) >> get)
84+ in testUnfoldAD unf 0 1 undefined [1]
6085
6186singletonM :: Bool
62−singletonM = evalState action undefined
63− where
64− action = do
65− x <- S.toList $ S.unfold (UF.singletonM put) (1 :: Int)
66− y <- get
67− return $ x == [()] && y == 1
87+singletonM =
88+ let unf = UF.singletonM (\a -> modify (+ a) >> get)
89+ in testUnfoldAD unf 0 1 1 [1]
6890
6991const :: Bool
70−const = evalState action 0
71− where
72− action = do
73− x <-
74− S.toList $
75− S.take 10 $ S.unfold (UF.const (modify (+ 1) >> get)) undefined
76− y <- get
77− let rList = [1..10] :: [Int]
78− return $ x == rList && y == 10
92+const =
93+ let unf = UF.take 10 $ UF.const (modify (+ 1) >> get)
94+ in testUnfoldAD unf 0 10 (0 :: Int) [1 .. 10]
7995
8096fromListM :: Property
81−fromListM = property $ \x -> evalState (action x) 0
82− where
83− action x = do
84− let list = P.map (\a -> modify (+ a) >> return a) (x :: [Int])
85− x1 <- S.toList $ S.unfold UF.fromListM list
86− y <- get
87− return $ x == x1 && y == foldr (+) 0 x
97+fromListM =
98+ property
99+ $ \n ->
100+ let lst = Prelude.map (\x -> modify (+ 1) >> return x) n
101+ in testUnfoldAD UF.fromListM 0 (length n) lst n
88102
89103replicateM :: Property
90104replicateM =
91− property $ \x ->
92− runIdentity $ do
93− x1 <- S.toList $ S.unfold (UF.replicateM x) (return ())
94− let x2 = P.replicate x ()
95− return $ x1 == x2
105+ property
106+ $ \i ->
107+ let ns = max 0 i + 1
108+ seed = modify (+ 1) >> get
109+ in testUnfoldAD (UF.replicateM i) 0 ns seed [1 .. i]
96110
97−repeatM :: Property
111+repeatM :: Bool
98112repeatM =
99− property $ \x ->
100− runIdentity $ do
101− x1 <- S.toList $ S.take x $ S.unfold UF.repeatM (return ())
102− let x2 = P.take x $ P.repeat ()
103− return $ x1 == x2
113+ testUnfoldAD (UF.take 10 UF.repeatM) 0 10 (modify (+ 1) >> get) [1 .. 10]
104114
105115take :: Property
106116take =
107− property $ \x ->
108− runIdentity $ do
109− x1 <- S.toList $ S.unfold (UF.take x UF.repeatM) (return ())
110− x2 <- S.toList $ S.take x $ S.unfold UF.repeatM (return ())
111− return $ x1 == x2
117+ property
118+ $ \i ->
119+ testUnfoldD
120+ (UF.take i UF.repeatM)
121+ (return 1)
122+ (Prelude.take i (Prelude.repeat 1))
112123
113124takeWhileM :: Property
114−takeWhileM = property $ \f x -> evalState (action f x) 0
115− where
116− action f x = do
117− let f' z = if apply f z
118− then modify (+ 1) >> return True
119− else return False
120− x1 <-
121− S.toList $ S.unfold (UF.takeWhileM f' UF.fromListM) (P.map return x)
122− let x2 = P.takeWhile (apply f) (x :: [Int])
123− y1 <- get
124− let y2 = P.length x2
125− return $ x1 == x2 && y1 == y2
125+takeWhileM =
126+ property
127+ $ \f n ->
128+ let fM x =
129+ if apply f x
130+ then modify (+ 1) >> return True
131+ else return False
132+ unf = UF.takeWhileM fM UF.fromList
133+ fL = Prelude.takeWhile (apply f) n
134+ fS = Prelude.length fL
135+ in testUnfoldAD unf 0 fS n fL
126136
127137filterM :: Property
128−filterM = property $ \f x -> evalState (action f x) 0
129− where
130− action f x = do
131− let f' z = if apply f z
132− then modify (+ 1) >> return True
133− else return False
134− x1 <-
135− S.toList $ S.unfold (UF.filterM f' UF.fromListM) (P.map return x)
136− let x2 = P.filter (apply f) (x :: [Int])
137− y1 <- get
138− let y2 = P.length x2
139− return $ x1 == x2 && y1 == y2
138+filterM =
139+ property
140+ $ \f n ->
141+ let fM x =
142+ if apply f x
143+ then modify (+ 1) >> return True
144+ else return False
145+ unf = UF.filterM fM UF.fromList
146+ fL = Prelude.filter (apply f) n
147+ fS = Prelude.length fL
148+ in testUnfoldAD unf 0 fS n fL
140149
141150drop :: Property
142151drop =
143− property $ \x y ->
144− runIdentity $ do
145− x1 <- S.toList
146− $ S.unfold (UF.drop x (UF.replicateM (x + y))) (return ())
147− x2 <- S.toList
148− $ S.drop x $ S.unfold (UF.replicateM (x + y)) (return ())
149− return $ x1 == x2
152+ property
153+ $ \i n ->
154+ let unf = UF.drop i UF.fromList
155+ fL = Prelude.drop i n
156+ in testUnfoldD unf n fL
150157
151158dropWhileM :: Property
152−dropWhileM = property $ \f x -> evalState (action f x) 0
153− where
154− action f x = do
155− let f' z = if apply f z
156− then modify (+ 1) >> return True
157− else return False
158− x1 <-
159− S.toList $ S.unfold (UF.dropWhileM f' UF.fromListM) (P.map return x)
160− let x2 = P.dropWhile (apply f) (x :: [Int])
161− y1 <- get
162− let y2 = P.length x - P.length x2
163− return $ x1 == x2 && y1 == y2
159+dropWhileM =
160+ property
161+ $ \f n ->
162+ let fM x =
163+ if apply f x
164+ then modify (+ 1) >> return True
165+ else return False
166+ unf = UF.dropWhileM fM UF.fromList
167+ fL = Prelude.dropWhile (apply f) n
168+ fS = Prelude.length n - Prelude.length fL
169+ in testUnfoldAD unf 0 fS n fL
164170
165171enumerateFromStepIntegral :: Property
166172enumerateFromStepIntegral =
167− property $ \x y ->
168− runIdentity $ do
169− x1 <-
170− S.toList $
171− S.unfold (UF.take y UF.enumerateFromStepIntegral) (0, x)
172− let x2 = P.take y $ P.map (x *) [0 .. y]
173− return $ x1 == x2
173+ property
174+ $ \f s ->
175+ let unf = UF.take 10 UF.enumerateFromStepIntegral
176+ lst = Prelude.take 10 $ List.unfoldr (\x -> Just (x, x + s)) f
177+ in testUnfoldD unf (f, s) lst
174178
175179enumerateFromToIntegral :: Property
176180enumerateFromToIntegral =
177− property $ \x ->
178− runIdentity $ do
179− x1 <- S.toList $ S.unfold (UF.enumerateFromToIntegral x) 0
180− let x2 = [0 .. x] :: [Int]
181− return $ x1 == x2
181+ property
182+ $ \f t ->
183+ let unf = UF.enumerateFromToIntegral t
184+ in testUnfoldD unf f [f .. t]
182185
183186zipWithM :: Property
184−zipWithM = property $ \x -> evalState (action x) (0 :: Int)
185− where
186− action x = do
187− let f a b = modify (+ 1) >> return (a + b)
188− x1 <-
189− S.toList $
190− S.unfold
191− (UF.zipWithM
192− f
193− (UF.enumerateFromToIntegral x)
194− (UF.enumerateFromToIntegral x))
195− (1, 1)
196− let x2 = P.zipWith (+) ([1 .. x] :: [Int]) ([1 .. x] :: [Int])
197− y <- get
198− return $ x1 == x2 && y == max 0 x
199−
200−concat :: Property
187+zipWithM =
188+ property
189+ $ \f ->
190+ let unf1 = UF.enumerateFromToIntegral 10
191+ unf2 = UF.enumerateFromToIntegral 20
192+ fA = applyFun2 f :: Int -> Int -> Int
193+ fM a b = modify (+ 1) >> return (fA a b)
194+ unf = UF.zipWithM fM unf1 unf2
195+ lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
196+ in testUnfoldAD unf 0 10 (1, 1) lst
197+
198+concat :: Bool
201199concat =
202− property $ \x y ->
203− runIdentity $ do
204− x1 <-
205− S.toList $
206− S.unfold
207− (UF.concat
208− (UF.enumerateFromToIntegral (x :: Int))
209− (UF.enumerateFromToIntegral (y :: Int)))
210− 0
211− let x2 = P.concat $ P.map (\k -> [k..y]) [0 .. x]
212− return $ x1 == x2
213−
214−outerProduct :: Property
200+ let unfIn = UF.replicateM 10
201+ unfOut = UF.map return $ UF.enumerateFromToIntegral 10
202+ unf = UF.concat unfOut unfIn
203+ lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
204+ in testUnfoldD unf 1 lst
205+
206+outerProduct :: Bool
215207outerProduct =
216− property $ \x y ->
217− runIdentity $ do
218− x1 <-
219− S.toList $
220− S.unfold
221− (UF.outerProduct
222− (UF.enumerateFromToIntegral (x :: Int))
223− (UF.enumerateFromToIntegral (y :: Int)))
224− (0, 0)
225− let x2 = [(a, b) | a <- [0 .. x], b <- [0 .. y]]
226− return $ x1 == x2
208+ let unf1 = UF.enumerateFromToIntegral 10
209+ unf2 = UF.enumerateFromToIntegral 20
210+ unf = UF.outerProduct unf1 unf2
211+ lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
212+ in testUnfold unf ((0, 0) :: (Int, Int)) lst
227213
228214main :: IO ()
229215main = hspec $