3-- Copyright : (c) 2020 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
10module Main (main) where
12import Streamly.Internal.Data.Unfold (Unfold)
14import qualified Data.List as List
15import qualified Prelude
16import qualified Streamly.Internal.Data.Unfold as UF
17import qualified Streamly.Internal.Data.Stream.IsStream as S
18import qualified Streamly.Internal.Data.Stream.StreamD as D
19import qualified Streamly.Internal.Data.Stream.StreamK as K
21import Control.Monad.Trans.State.Strict
22import Data.Functor.Identity
23import Prelude hiding (const, take, drop, concat, mapM)
24import Streamly.Prelude (SerialT)
26import Test.Hspec.QuickCheck
28import Test.QuickCheck.Function
30-------------------------------------------------------------------------------
32-------------------------------------------------------------------------------
34-- | @testUnfoldM unf seed initial final xs@, runs an unfold under state monad
35-- using @initial@ as the initial state. @final@ is the expected state after
36-- running it and @xs@ is the list of elements the stream must produce.
38 (Eq s, Eq b) => Unfold (State s) a b -> a -> s -> s -> [b] -> Bool
39testUnfoldM unf seed si sf lst = evalState action si
44 x <- S.toList $ S.unfold unf seed
46 return $ x == lst && y == sf
48testUnfoldMD :: Unfold (State Int) a Int -> a -> Int -> Int -> [Int] -> Bool
49testUnfoldMD = testUnfoldM
51-- | This is similar to 'testUnfoldM' but without the state monad.
52testUnfold :: Eq b => Unfold Identity a b -> a -> [b] -> Bool
53testUnfold unf seed lst = runIdentity action
58 x <- S.toList $ S.unfold unf seed
61testUnfoldD :: Unfold Identity a Int -> a -> [Int] -> Bool
62testUnfoldD = testUnfold
64-------------------------------------------------------------------------------
66-------------------------------------------------------------------------------
70 let unf = UF.lmapM (\x -> modify (+ 1) >> return x) (UF.function id)
71 in testUnfoldMD unf 1 0 1 [1]
75 let unf = UF.supply 1 (UF.function id)
76 in testUnfold unf undefined ([1] :: [Int])
80 let unf = UF.supplyFirst 1 (UF.function id)
81 in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)])
85 let unf = UF.supplySecond 1 (UF.function id)
86 in testUnfold unf 2 ([(2, 1)] :: [(Int, Int)])
90 let unf = UF.discardFirst (UF.function id)
91 in testUnfold unf ((1, 2) :: (Int, Int)) [2]
95 let unf = UF.discardSecond (UF.function id)
96 in testUnfold unf ((1, 2) :: (Int, Int)) [1]
100 let unf = UF.swap (UF.function id)
101 in testUnfold unf ((1, 2) :: (Int, Int)) [(2, 1)]
103-------------------------------------------------------------------------------
105-------------------------------------------------------------------------------
107fromStream :: Property
113 (S.fromList list :: SerialT Identity Int)
116fromStreamD :: Property
119 $ \list -> testUnfoldD UF.fromStreamD (D.fromList list) (list :: [Int])
121fromStreamK :: Property
124 $ \list -> testUnfoldD UF.fromStreamK (K.fromList list) (list :: [Int])
128 let unf = UF.nilM put
129 in testUnfoldMD unf 1 0 1 []
133 let cns = UF.consM (\a -> modify (+ a) >> get)
134 unf = cns $ cns $ UF.nilM $ \a -> modify (+ a)
135 in testUnfoldMD unf 1 0 3 [1, 2]
139 let unf = UF.functionM (\a -> modify (+ a) >> get)
140 in testUnfoldMD unf 1 0 1 [1]
144 let unf = UF.fromEffect (modify (+ 1) >> get)
145 in testUnfoldMD unf (0 :: Int) 0 1 [1]
151 let genA = apply gen :: Int -> Maybe (Int, Int)
152 genM x = modify (+ 1) >> return (genA x)
153 list = Prelude.take 100 $ List.unfoldr genA 1
154 unf = UF.take 100 $ UF.unfoldrM genM
156 fs = if ll < 100 then ll + 1 else 100
157 in testUnfoldMD unf 1 0 fs list
163 let listM = Prelude.map (\x -> modify (+ 1) >> return x) list
164 in testUnfoldMD UF.fromListM listM 0 (length list) list
166replicateM :: Property
171 seed = modify (+ 1) >> get
172 in testUnfoldMD (UF.replicateM i) seed 0 ns [1 .. i]
176 testUnfoldMD (UF.take 10 UF.repeatM) (modify (+ 1) >> get) 0 10 [1 .. 10]
182 let nextA = apply next :: Int -> Int
183 nextM x = modify (+ 1) >> return (nextA x)
184 list = Prelude.take 100 $ List.iterate nextA 1
185 unf = UF.take 100 $ UF.iterateM nextM
186 in testUnfoldMD unf (modify (+ 10) >> return 1) 0 110 list
188fromIndicesM :: Property
192 let indFA = apply indF :: Int -> Int
193 indFM x = modify (+ 1) >> return (indFA x)
194 list = Prelude.take 100 $ Prelude.map indFA [1 ..]
195 unf = UF.take 100 $ UF.fromIndicesM indFM
196 in testUnfoldMD unf 1 0 (length list) list
198enumerateFromStepNum :: Property
199enumerateFromStepNum =
202 let unf = UF.take 10 $ UF.enumerateFromStepNum s
203 lst = Prelude.take 10 $ List.unfoldr (\x -> Just (x, x + s)) f
204 in testUnfoldD unf f lst
206#if MIN_VERSION_base(4,12,0)
207enumerateFromToFractional :: Property
208enumerateFromToFractional =
211 let unf = UF.enumerateFromToFractional (t :: Double)
212 in testUnfold unf (f :: Double) [f..(t :: Double)]
215enumerateFromStepIntegral :: Property
216enumerateFromStepIntegral =
219 let unf = UF.take 10 UF.enumerateFromStepIntegral
220 lst = Prelude.take 10 $ List.unfoldr (\x -> Just (x, x + s)) f
221 in testUnfoldD unf (f, s) lst
223enumerateFromToIntegral :: Property
224enumerateFromToIntegral =
227 let unf = UF.enumerateFromToIntegral t
228 in testUnfoldD unf f [f .. t]
230-------------------------------------------------------------------------------
231-- Stream transformation
232-------------------------------------------------------------------------------
238 let fA = apply f :: Int -> Int
239 fM x = modify (+ 1) >> return (fA x)
240 unf = UF.mapM fM UF.fromList
241 mList = Prelude.map fA list
242 in testUnfoldMD unf list 0 (length list) mList
244mapMWithInput :: Property
248 let fA = applyFun2 f :: [Int] -> Int -> Int
249 fM x y = modify (+ 1) >> return (fA x y)
250 unf = UF.mapMWithInput fM UF.fromList
251 mList = Prelude.map (fA list) list
252 in testUnfoldMD unf list 0 (length list) mList
259 (UF.take i UF.repeatM)
261 (Prelude.take i (Prelude.repeat 1))
263takeWhileM :: Property
269 then modify (+ 1) >> return True
271 unf = UF.takeWhileM fM UF.fromList
272 fL = Prelude.takeWhile (apply f) list
273 fS = Prelude.length fL
274 in testUnfoldMD unf list 0 fS fL
282 then modify (+ 1) >> return True
284 unf = UF.filterM fM UF.fromList
285 fL = Prelude.filter (apply f) list
286 fS = Prelude.length fL
287 in testUnfoldMD unf list 0 fS fL
293 let unf = UF.drop i UF.fromList
294 fL = Prelude.drop i list
295 in testUnfoldD unf list fL
297dropWhileM :: Property
303 then modify (+ 1) >> return True
305 unf = UF.dropWhileM fM UF.fromList
306 fL = Prelude.dropWhile (apply f) list
307 fS = Prelude.length list - Prelude.length fL
308 in testUnfoldMD unf list 0 fS fL
310-------------------------------------------------------------------------------
312-------------------------------------------------------------------------------
318 let unf1 = UF.enumerateFromToIntegral 10
319 unf2 = UF.enumerateFromToIntegral 20
320 fA = applyFun2 f :: Int -> Int -> Int
321 fM a b = modify (+ 1) >> return (fA a b)
322 unf = UF.zipWithM fM (UF.lmap fst unf1) (UF.lmap snd unf2)
323 lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
324 in testUnfoldMD unf (1, 1) 0 10 lst
328 let unfIn = UF.replicateM 10
329 unfOut = UF.map return $ UF.enumerateFromToIntegral 10
330 unf = UF.many unfOut unfIn
331 lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
332 in testUnfoldD unf 1 lst
336 let unf1 = UF.enumerateFromToIntegral 10
337 unf2 = UF.enumerateFromToIntegral 20
338 unf = crossProduct unf1 unf2
339 lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
340 in testUnfold unf ((0, 0) :: (Int, Int)) lst
344 crossProduct u1 u2 = UF.cross (UF.lmap fst u1) (UF.lmap snd u2)
349 let u = UF.lmap (\_ -> modify (+ 1) >> return b) (UF.replicateM 10)
350 in modify (+ 1) >> return u
351 unf = UF.concatMapM inner (UF.enumerateFromToIntegral 10)
352 list = List.concatMap (replicate 10) [1 .. 10]
353 in testUnfoldMD unf 1 0 110 list
355-------------------------------------------------------------------------------
357-------------------------------------------------------------------------------
366 prop "supplyFirst" supplyFirst
367 prop "supplySecond" supplySecond
368 prop "discardFirst" discardFirst
369 prop "discardSecond" discardSecond
372testGeneration :: Spec
374 describe "Generation"
376 prop "fromStream" fromStream
377 prop "fromStreamK" fromStreamK
378 prop "fromStreamD" fromStreamD
381 prop "functionM" functionM
382 -- prop "function" function
383 -- prop "identity" identity
385 prop "unfoldrM" unfoldrM
386 -- prop "fromList" fromList
387 prop "fromListM" fromListM
388 -- prop "fromSVar" fromSVar
389 -- prop "fromProducer" fromProducer
390 prop "replicateM" replicateM
391 prop "repeatM" repeatM
392 prop "iterateM" iterateM
393 prop "fromIndicesM" fromIndicesM
394 prop "enumerateFromStepIntegral" enumerateFromStepIntegral
395 prop "enumerateFromToIntegral" enumerateFromToIntegral
396 -- prop "enumerateFromIntegral" enumerateFromIntegral
397 prop "enumerateFromStepNum" enumerateFromStepNum
398 -- prop "numFrom" numFrom
399#if MIN_VERSION_base(4,12,0)
400 prop "enumerateFromToFractional" enumerateFromToFractional
403testTransformation :: Spec
405 describe "Transformation"
409 prop "mapMWithInput" mapMWithInput
410 prop "takeWhileM" takeWhileM
411 -- prop "takeWhile" takeWhile
413 -- prop "filter" filter
414 prop "filterM" filterM
416 -- prop "dropWhile" dropWhile
417 prop "dropWhileM" dropWhileM
419testCombination :: Spec
421 describe "Transformation"
423 prop "zipWithM" zipWithM
424 -- prop "zipWith" zipWith
425 -- prop "teeZipWith" teeZipWith
427 prop "concatMapM" concatMapM
428 prop "outerProduct" outerProduct
430 -- prop "apDiscardFst" apDiscardFst
431 -- prop "apDiscardSnd" apDiscardSnd
433-------------------------------------------------------------------------------
435-------------------------------------------------------------------------------
438moduleName = "Data.Unfold"
443 $ describe moduleName
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list