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.Fold as Fold
17import qualified Streamly.Internal.Data.Unfold as UF
18import qualified Streamly.Internal.Data.Stream as S
19import qualified Streamly.Internal.Data.Stream as D
20import qualified Streamly.Internal.Data.StreamK as K
22import Control.Monad.Trans.State.Strict
23import Data.Functor.Identity
24import Prelude hiding (const, take, drop, concat, mapM)
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.fold Fold.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.fold Fold.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.both 1 (UF.function id)
76 in testUnfold unf undefined ([1] :: [Int])
80 let unf = UF.first 1 (UF.function id)
81 in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)])
85 let unf = UF.second 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 :: S.Stream 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 = (i, modify (+ 1) >> get)
172 in testUnfoldMD UF.replicateM 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
198-------------------------------------------------------------------------------
200-------------------------------------------------------------------------------
201enumerateFromNum :: Property
205 let unf = UF.take 50 UF.enumerateFromNum
206 in testUnfold unf (f :: Int) $
207 Prelude.take 50 $ Prelude.enumFrom f
209enumerateFromThenNum :: Property
210enumerateFromThenNum =
213 let unf = UF.take 50 UF.enumerateFromThenNum
214 in testUnfold unf (f :: Int, th) $
215 Prelude.take 50 $ Prelude.enumFromThen f th
217-------------------------------------------------------------------------------
218-- Test for Integral type
219-------------------------------------------------------------------------------
220enumerateFromIntegral :: Property
221enumerateFromIntegral =
224 let unf = UF.take 50 UF.enumerateFromIntegral
225 in testUnfold unf (f :: Integer) $
226 Prelude.take 50 $ Prelude.enumFrom f
228enumerateFromThenIntegral :: Property
229enumerateFromThenIntegral =
232 let unf = UF.take 50 UF.enumerateFromThenIntegral
233 in testUnfold unf (f :: Integer, th) $
234 Prelude.take 50 $ Prelude.enumFromThen f th
236enumerateFromThenToIntegral :: Property
237enumerateFromThenToIntegral =
240 let unf = UF.take 50 UF.enumerateFromThenToIntegral
241 in testUnfold unf (f :: Integer, th, to) $
242 Prelude.take 50 $ Prelude.enumFromThenTo f th to
244enumerateFromToIntegral :: Property
245enumerateFromToIntegral =
248 let unf = UF.take 50 UF.enumerateFromToIntegral
249 in testUnfold unf (f :: Integer, to) $
250 Prelude.take 50 $ Prelude.enumFromTo f to
252enumerateFromIntegralBounded :: Property
253enumerateFromIntegralBounded =
256 let unf = UF.take 50 UF.enumerateFromIntegralBounded
257 in testUnfold unf (f :: Int) $
258 Prelude.take 50 $ Prelude.enumFrom f
260enumerateFromThenIntegralBounded :: Property
261enumerateFromThenIntegralBounded =
264 let unf = UF.take 50 UF.enumerateFromThenIntegralBounded
265 in testUnfold unf (f :: Int, th) $
266 Prelude.take 50 $ Prelude.enumFromThen f th
268enumerateFromToIntegralBounded :: Property
269enumerateFromToIntegralBounded =
272 let unf = UF.take 50 UF.enumerateFromToIntegralBounded
273 in testUnfold unf (f :: Int, to) $
274 Prelude.take 50 $ Prelude.enumFromTo f to
276enumerateFromThenToIntegralBounded :: Property
277enumerateFromThenToIntegralBounded =
280 let unf = UF.take 50 UF.enumerateFromThenToIntegralBounded
281 in testUnfold unf (f :: Int, th, to) $
282 Prelude.take 50 $ Prelude.enumFromThenTo f th to
284enumerateFromSmallBounded :: Property
285enumerateFromSmallBounded =
288 let unf = UF.take 50 UF.enumerateFromSmallBounded
289 in testUnfold unf (f :: Char) $
290 Prelude.take 50 $ Prelude.enumFrom f
292enumerateFromThenSmallBounded :: Property
293enumerateFromThenSmallBounded =
296 let unf = UF.take 50 UF.enumerateFromThenSmallBounded
297 in testUnfold unf (f :: Char, th) $
298 Prelude.take 50 $ Prelude.enumFromThen f th
300enumerateFromToSmall :: Property
301enumerateFromToSmall =
304 let unf = UF.take 50 UF.enumerateFromToSmall
305 in testUnfold unf (f :: Char, to) $
306 Prelude.take 50 $ Prelude.enumFromTo f to
308enumerateFromThenToSmall :: Property
309enumerateFromThenToSmall =
312 let unf = UF.take 50 UF.enumerateFromThenToSmall
313 in testUnfold unf (f :: Char, th, to) $
314 Prelude.take 50 $ Prelude.enumFromThenTo f th to
316enumerateFromSmallBoundedOrd :: Property
317enumerateFromSmallBoundedOrd =
320 let unf = UF.take 3 UF.enumerateFromSmallBounded
321 in testUnfold unf (f :: Ordering) $
322 Prelude.take 3 $ Prelude.enumFrom f
324enumerateFromThenSmallBoundedOrd :: Property
325enumerateFromThenSmallBoundedOrd =
328 let unf = UF.take 3 UF.enumerateFromThenSmallBounded
329 in testUnfold unf (f :: Ordering, th) $
330 Prelude.take 3 $ Prelude.enumFromThen f th
332enumerateFromToSmallOrd :: Property
333enumerateFromToSmallOrd =
336 let unf = UF.take 3 UF.enumerateFromToSmall
337 in testUnfold unf (f :: Ordering, to) $
338 Prelude.take 3 $ Prelude.enumFromTo f to
340enumerateFromThenToSmallOrd :: Property
341enumerateFromThenToSmallOrd =
344 let unf = UF.take 3 UF.enumerateFromThenToSmall
345 in testUnfold unf (f :: Ordering, th, to) $
346 Prelude.take 3 $ Prelude.enumFromThenTo f th to
348-------------------------------------------------------------------------------
349enumerateFromSmallBoundedBool :: Property
350enumerateFromSmallBoundedBool =
353 let unf = UF.take 2 UF.enumerateFromSmallBounded
354 in testUnfold unf (f :: Bool) $
355 Prelude.take 2 $ Prelude.enumFrom f
357enumerateFromThenSmallBoundedBool :: Property
358enumerateFromThenSmallBoundedBool =
361 let unf = UF.take 2 UF.enumerateFromThenSmallBounded
362 in testUnfold unf (f :: Bool, th) $
363 Prelude.take 2 $ Prelude.enumFromThen f th
365enumerateFromToSmallBool :: Property
366enumerateFromToSmallBool =
369 let unf = UF.take 2 UF.enumerateFromToSmall
370 in testUnfold unf (f :: Bool, to) $
371 Prelude.take 2 $ Prelude.enumFromTo f to
373enumerateFromThenToSmallBool :: Property
374enumerateFromThenToSmallBool =
377 let unf = UF.take 2 UF.enumerateFromThenToSmall
378 in testUnfold unf (f :: Bool, th, to) $
379 Prelude.take 2 $ Prelude.enumFromThenTo f th to
380-------------------------------------------------------------------------------
381enumerateFromSmallBoundedUnit :: Property
382enumerateFromSmallBoundedUnit =
385 let unf = UF.take 1 UF.enumerateFromSmallBounded
386 in testUnfold unf (f :: ()) $
387 Prelude.take 1 $ Prelude.enumFrom f
389enumerateFromThenSmallBoundedUnit :: Property
390enumerateFromThenSmallBoundedUnit =
393 let unf = UF.take 1 UF.enumerateFromThenSmallBounded
394 in testUnfold unf (f :: (), th) $
395 Prelude.take 1 $ Prelude.enumFromThen f th
397enumerateFromToSmallUnit :: Property
398enumerateFromToSmallUnit =
401 let unf = UF.take 1 UF.enumerateFromToSmall
402 in testUnfold unf (f :: (), to) $
403 Prelude.take 1 $ Prelude.enumFromTo f to
405enumerateFromThenToSmallUnit :: Property
406enumerateFromThenToSmallUnit =
409 let unf = UF.take 1 UF.enumerateFromThenToSmall
410 in testUnfold unf (f :: (), th, to) $
411 Prelude.take 1 $ Prelude.enumFromThenTo f th to
413enumerateFromFractional :: Property
414enumerateFromFractional =
417 let unf = UF.take 50 UF.enumerateFromFractional
418 in testUnfold unf (f :: Double) $
419 Prelude.take 50 $ Prelude.enumFrom f
421enumerateFromThenFractional :: Property
422enumerateFromThenFractional =
425 let unf = UF.take 50 UF.enumerateFromThenFractional
426 in testUnfold unf (f :: Double, th) $
427 Prelude.take 50 $ Prelude.enumFromThen f th
429enumerateFromThenToFractional :: Property
430enumerateFromThenToFractional =
433 let unf = UF.take 50 UF.enumerateFromThenToFractional
434 in testUnfold unf (f :: Double, th, to) $
435 Prelude.take 50 $ Prelude.enumFromThenTo f th to
437enumerateFromToFractional :: Property
438enumerateFromToFractional =
441 let unf = UF.enumerateFromToFractional
442 in testUnfold unf (f :: Double, t) [f..(t :: Double)]
444-------------------------------------------------------------------------------
445-- Stream transformation
446-------------------------------------------------------------------------------
452 let unf = UF.postscan Fold.sum UF.fromList
453 mList = scanl1 (+) ls
454 in testUnfold unf ls mList
460 let fA = apply f :: Int -> Int
461 fM x = modify (+ 1) >> return (fA x)
462 unf = UF.mapM fM UF.fromList
463 mList = Prelude.map fA list
464 in testUnfoldMD unf list 0 (length list) mList
470 let fA = applyFun2 f :: [Int] -> Int -> Int
471 fM x y = modify (+ 1) >> return (fA x y)
472 unf = UF.mapM2 fM UF.fromList
473 mList = Prelude.map (fA list) list
474 in testUnfoldMD unf list 0 (length list) mList
481 (UF.take i UF.repeatM)
483 (Prelude.take i (Prelude.repeat 1))
485takeWhileM :: Property
491 then modify (+ 1) >> return True
493 unf = UF.takeWhileM fM UF.fromList
494 fL = Prelude.takeWhile (apply f) list
495 fS = Prelude.length fL
496 in testUnfoldMD unf list 0 fS fL
504 then modify (+ 1) >> return True
506 unf = UF.filterM fM UF.fromList
507 fL = Prelude.filter (apply f) list
508 fS = Prelude.length fL
509 in testUnfoldMD unf list 0 fS fL
515 let unf = UF.drop i UF.fromList
516 fL = Prelude.drop i list
517 in testUnfoldD unf list fL
519dropWhileM :: Property
525 then modify (+ 1) >> return True
527 unf = UF.dropWhileM fM UF.fromList
528 fL = Prelude.dropWhile (apply f) list
529 fS = Prelude.length list - Prelude.length fL
530 in testUnfoldMD unf list 0 fS fL
532-------------------------------------------------------------------------------
534-------------------------------------------------------------------------------
540 let unf1 = UF.enumerateFromToIntegral
541 unf2 = UF.enumerateFromToIntegral
542 fA = applyFun2 f :: Int -> Int -> Int
543 fM a b = modify (+ 1) >> return (fA a b)
544 unf = UF.zipWithM fM (UF.lmap fst unf1) (UF.lmap snd unf2)
545 lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
546 in testUnfoldMD unf ((1,10), (1,20)) 0 10 lst
550 let unfIn = UF.replicateM
551 unfOut = UF.map ((10,) . return) UF.enumerateFromToIntegral
552 unf = UF.many unfIn unfOut
553 lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
554 in testUnfoldD unf (1, 10) lst
558 let unf1 = UF.enumerateFromToIntegral
559 unf2 = UF.enumerateFromToIntegral
560 unf = crossProduct unf1 unf2
561 lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
562 in testUnfold unf (((0,10) ,(0,20)) :: ((Int, Int), (Int, Int))) lst
566 crossProduct u1 u2 = UF.cross (UF.lmap fst u1) (UF.lmap snd u2)
571 let u = UF.lmap (\_ -> (10, modify (+ 1) >> return b)) UF.replicateM
572 in modify (+ 1) >> return u
573 unf = UF.concatMapM inner UF.enumerateFromToIntegral
574 list = List.concatMap (replicate 10) [1 .. 10]
575 in testUnfoldMD unf (1, 10) 0 110 list
577-------------------------------------------------------------------------------
579-------------------------------------------------------------------------------
590 prop "discardFirst" discardFirst
591 prop "discardSecond" discardSecond
594testGeneration :: Spec
596 describe "Generation"
598 prop "fromStream" fromStream
599 prop "fromStreamK" fromStreamK
600 prop "fromStreamD" fromStreamD
603 prop "functionM" functionM
604 -- prop "function" function
605 -- prop "identity" identity
607 prop "unfoldrM" unfoldrM
608 -- prop "fromList" fromList
609 prop "fromListM" fromListM
610 -- prop "fromSVar" fromSVar
611 -- prop "fromProducer" fromProducer
612 prop "replicateM" replicateM
613 prop "repeatM" repeatM
614 prop "iterateM" iterateM
615 prop "fromIndicesM" fromIndicesM
616 ----------- Enumerate from Num ------------------------------------
617 prop "enumerateFromNum" enumerateFromNum
618 prop "enumerateFromThenNum" enumerateFromThenNum
619 ----------- Enumerate from Integral -------------------------------
620 prop "enumerateFromIntegral" enumerateFromIntegral
621 prop "enumerateFromThenIntegral" enumerateFromThenIntegral
622 prop "enumerateFromToIntegral" enumerateFromToIntegral
623 prop "enumerateFromThenToIntegral" enumerateFromThenToIntegral
625 prop "enumerateFromIntegralBounded" enumerateFromIntegralBounded
626 prop "enumerateFromThenIntegralBounded" enumerateFromThenIntegralBounded
627 prop "enumerateFromToIntegralBounded" enumerateFromToIntegralBounded
628 prop "enumerateFromThenToIntegralBounded" enumerateFromThenToIntegralBounded
629 ----------- Enumerate from Small Integral -------------------------
630 prop "enumerateFromSmallBounded" enumerateFromSmallBounded
631 prop "enumerateFromThenSmallBounded" enumerateFromThenSmallBounded
632 prop "enumerateFromToSmall" enumerateFromToSmall
633 prop "enumerateFromThenToSmall" enumerateFromThenToSmall
635 prop "enumerateFromSmallBoundedOrd" enumerateFromSmallBoundedOrd
636 prop "enumerateFromThenSmallBoundedOrd" enumerateFromThenSmallBoundedOrd
637 prop "enumerateFromToSmallOrd" enumerateFromToSmallOrd
638 prop "enumerateFromThenToSmallOrd" enumerateFromThenToSmallOrd
640 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedUnit
641 prop "enumerateFromThenSmallBoundedUnit" enumerateFromThenSmallBoundedUnit
642 prop "enumerateFromToSmallUnit" enumerateFromToSmallUnit
643 prop "enumerateFromThenToSmallUnit" enumerateFromThenToSmallUnit
645 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedBool
646 prop "enumerateFromThenSmallBoundedBool" enumerateFromThenSmallBoundedBool
647 prop "enumerateFromToSmallBool" enumerateFromToSmallBool
648 prop "enumerateFromThenToSmallBool" enumerateFromThenToSmallBool
650 prop "enumerateFromFractional" enumerateFromFractional
651 prop "enumerateFromThenFractional" enumerateFromThenFractional
652 prop "enumerateFromToFractional" enumerateFromToFractional
653 prop "enumerateFromThenToFractional" enumerateFromThenToFractional
655testTransformation :: Spec
657 describe "Transformation"
660 prop "postscan" postscan
663 prop "takeWhileM" takeWhileM
664 -- prop "takeWhile" takeWhile
666 -- prop "filter" filter
667 prop "filterM" filterM
669 -- prop "dropWhile" dropWhile
670 prop "dropWhileM" dropWhileM
672testCombination :: Spec
674 describe "Transformation"
676 prop "zipWithM" zipWithM
677 -- prop "zipWith" zipWith
678 -- prop "teeZipWith" teeZipWith
680 prop "concatMapM" concatMapM
681 prop "outerProduct" outerProduct
683 -- prop "apDiscardFst" apDiscardFst
684 -- prop "apDiscardSnd" apDiscardSnd
686-------------------------------------------------------------------------------
688-------------------------------------------------------------------------------
691moduleName = "Data.Unfold"
696 $ 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