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.IsStream as S
19import qualified Streamly.Internal.Data.Stream.StreamD as D
20import qualified Streamly.Internal.Data.Stream.StreamK as K
22import Control.Monad.Trans.State.Strict
23import Data.Functor.Identity
24import Prelude hiding (const, take, drop, concat, mapM)
25import Streamly.Prelude (SerialT)
27import Test.Hspec.QuickCheck
29import Test.QuickCheck.Function
31-------------------------------------------------------------------------------
33-------------------------------------------------------------------------------
35-- | @testUnfoldM unf seed initial final xs@, runs an unfold under state monad
36-- using @initial@ as the initial state. @final@ is the expected state after
37-- running it and @xs@ is the list of elements the stream must produce.
39 (Eq s, Eq b) => Unfold (State s) a b -> a -> s -> s -> [b] -> Bool
40testUnfoldM unf seed si sf lst = evalState action si
45 x <- S.toList $ S.unfold unf seed
47 return $ x == lst && y == sf
49testUnfoldMD :: Unfold (State Int) a Int -> a -> Int -> Int -> [Int] -> Bool
50testUnfoldMD = testUnfoldM
52-- | This is similar to 'testUnfoldM' but without the state monad.
53testUnfold :: Eq b => Unfold Identity a b -> a -> [b] -> Bool
54testUnfold unf seed lst = runIdentity action
59 x <- S.toList $ S.unfold unf seed
62testUnfoldD :: Unfold Identity a Int -> a -> [Int] -> Bool
63testUnfoldD = testUnfold
65-------------------------------------------------------------------------------
67-------------------------------------------------------------------------------
71 let unf = UF.lmapM (\x -> modify (+ 1) >> return x) (UF.function id)
72 in testUnfoldMD unf 1 0 1 [1]
76 let unf = UF.both 1 (UF.function id)
77 in testUnfold unf undefined ([1] :: [Int])
81 let unf = UF.first 1 (UF.function id)
82 in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)])
86 let unf = UF.second 1 (UF.function id)
87 in testUnfold unf 2 ([(2, 1)] :: [(Int, Int)])
91 let unf = UF.discardFirst (UF.function id)
92 in testUnfold unf ((1, 2) :: (Int, Int)) [2]
96 let unf = UF.discardSecond (UF.function id)
97 in testUnfold unf ((1, 2) :: (Int, Int)) [1]
101 let unf = UF.swap (UF.function id)
102 in testUnfold unf ((1, 2) :: (Int, Int)) [(2, 1)]
104-------------------------------------------------------------------------------
106-------------------------------------------------------------------------------
108fromStream :: Property
114 (S.fromList list :: SerialT Identity Int)
117fromStreamD :: Property
120 $ \list -> testUnfoldD UF.fromStreamD (D.fromList list) (list :: [Int])
122fromStreamK :: Property
125 $ \list -> testUnfoldD UF.fromStreamK (K.fromList list) (list :: [Int])
129 let unf = UF.nilM put
130 in testUnfoldMD unf 1 0 1 []
134 let cns = UF.consM (\a -> modify (+ a) >> get)
135 unf = cns $ cns $ UF.nilM $ \a -> modify (+ a)
136 in testUnfoldMD unf 1 0 3 [1, 2]
140 let unf = UF.functionM (\a -> modify (+ a) >> get)
141 in testUnfoldMD unf 1 0 1 [1]
145 let unf = UF.fromEffect (modify (+ 1) >> get)
146 in testUnfoldMD unf (0 :: Int) 0 1 [1]
152 let genA = apply gen :: Int -> Maybe (Int, Int)
153 genM x = modify (+ 1) >> return (genA x)
154 list = Prelude.take 100 $ List.unfoldr genA 1
155 unf = UF.take 100 $ UF.unfoldrM genM
157 fs = if ll < 100 then ll + 1 else 100
158 in testUnfoldMD unf 1 0 fs list
164 let listM = Prelude.map (\x -> modify (+ 1) >> return x) list
165 in testUnfoldMD UF.fromListM listM 0 (length list) list
167replicateM :: Property
172 seed = modify (+ 1) >> get
173 in testUnfoldMD (UF.replicateM i) seed 0 ns [1 .. i]
177 testUnfoldMD (UF.take 10 UF.repeatM) (modify (+ 1) >> get) 0 10 [1 .. 10]
183 let nextA = apply next :: Int -> Int
184 nextM x = modify (+ 1) >> return (nextA x)
185 list = Prelude.take 100 $ List.iterate nextA 1
186 unf = UF.take 100 $ UF.iterateM nextM
187 in testUnfoldMD unf (modify (+ 10) >> return 1) 0 110 list
189fromIndicesM :: Property
193 let indFA = apply indF :: Int -> Int
194 indFM x = modify (+ 1) >> return (indFA x)
195 list = Prelude.take 100 $ Prelude.map indFA [1 ..]
196 unf = UF.take 100 $ UF.fromIndicesM indFM
197 in testUnfoldMD unf 1 0 (length list) list
199-------------------------------------------------------------------------------
201-------------------------------------------------------------------------------
202enumerateFromNum :: Property
206 let unf = UF.take 50 UF.enumerateFromNum
207 in testUnfold unf (f :: Int) $
208 Prelude.take 50 $ Prelude.enumFrom f
210enumerateFromThenNum :: Property
211enumerateFromThenNum =
214 let unf = UF.take 50 UF.enumerateFromThenNum
215 in testUnfold unf (f :: Int, th) $
216 Prelude.take 50 $ Prelude.enumFromThen f th
218-------------------------------------------------------------------------------
219-- Test for Integral type
220-------------------------------------------------------------------------------
221enumerateFromIntegral :: Property
222enumerateFromIntegral =
225 let unf = UF.take 50 UF.enumerateFromIntegral
226 in testUnfold unf (f :: Integer) $
227 Prelude.take 50 $ Prelude.enumFrom f
229enumerateFromThenIntegral :: Property
230enumerateFromThenIntegral =
233 let unf = UF.take 50 UF.enumerateFromThenIntegral
234 in testUnfold unf (f :: Integer, th) $
235 Prelude.take 50 $ Prelude.enumFromThen f th
237enumerateFromThenToIntegral :: Property
238enumerateFromThenToIntegral =
241 let unf = UF.take 50 UF.enumerateFromThenToIntegral
242 in testUnfold unf (f :: Integer, th, to) $
243 Prelude.take 50 $ Prelude.enumFromThenTo f th to
245enumerateFromToIntegral :: Property
246enumerateFromToIntegral =
249 let unf = UF.take 50 UF.enumerateFromToIntegral
250 in testUnfold unf (f :: Integer, to) $
251 Prelude.take 50 $ Prelude.enumFromTo f to
253enumerateFromIntegralBounded :: Property
254enumerateFromIntegralBounded =
257 let unf = UF.take 50 UF.enumerateFromIntegralBounded
258 in testUnfold unf (f :: Int) $
259 Prelude.take 50 $ Prelude.enumFrom f
261enumerateFromThenIntegralBounded :: Property
262enumerateFromThenIntegralBounded =
265 let unf = UF.take 50 UF.enumerateFromThenIntegralBounded
266 in testUnfold unf (f :: Int, th) $
267 Prelude.take 50 $ Prelude.enumFromThen f th
269enumerateFromToIntegralBounded :: Property
270enumerateFromToIntegralBounded =
273 let unf = UF.take 50 UF.enumerateFromToIntegralBounded
274 in testUnfold unf (f :: Int, to) $
275 Prelude.take 50 $ Prelude.enumFromTo f to
277enumerateFromThenToIntegralBounded :: Property
278enumerateFromThenToIntegralBounded =
281 let unf = UF.take 50 UF.enumerateFromThenToIntegralBounded
282 in testUnfold unf (f :: Int, th, to) $
283 Prelude.take 50 $ Prelude.enumFromThenTo f th to
285enumerateFromSmallBounded :: Property
286enumerateFromSmallBounded =
289 let unf = UF.take 50 UF.enumerateFromSmallBounded
290 in testUnfold unf (f :: Char) $
291 Prelude.take 50 $ Prelude.enumFrom f
293enumerateFromThenSmallBounded :: Property
294enumerateFromThenSmallBounded =
297 let unf = UF.take 50 UF.enumerateFromThenSmallBounded
298 in testUnfold unf (f :: Char, th) $
299 Prelude.take 50 $ Prelude.enumFromThen f th
301enumerateFromToSmall :: Property
302enumerateFromToSmall =
305 let unf = UF.take 50 UF.enumerateFromToSmall
306 in testUnfold unf (f :: Char, to) $
307 Prelude.take 50 $ Prelude.enumFromTo f to
309enumerateFromThenToSmall :: Property
310enumerateFromThenToSmall =
313 let unf = UF.take 50 UF.enumerateFromThenToSmall
314 in testUnfold unf (f :: Char, th, to) $
315 Prelude.take 50 $ Prelude.enumFromThenTo f th to
317enumerateFromSmallBoundedOrd :: Property
318enumerateFromSmallBoundedOrd =
321 let unf = UF.take 3 UF.enumerateFromSmallBounded
322 in testUnfold unf (f :: Ordering) $
323 Prelude.take 3 $ Prelude.enumFrom f
325enumerateFromThenSmallBoundedOrd :: Property
326enumerateFromThenSmallBoundedOrd =
329 let unf = UF.take 3 UF.enumerateFromThenSmallBounded
330 in testUnfold unf (f :: Ordering, th) $
331 Prelude.take 3 $ Prelude.enumFromThen f th
333enumerateFromToSmallOrd :: Property
334enumerateFromToSmallOrd =
337 let unf = UF.take 3 UF.enumerateFromToSmall
338 in testUnfold unf (f :: Ordering, to) $
339 Prelude.take 3 $ Prelude.enumFromTo f to
341enumerateFromThenToSmallOrd :: Property
342enumerateFromThenToSmallOrd =
345 let unf = UF.take 3 UF.enumerateFromThenToSmall
346 in testUnfold unf (f :: Ordering, th, to) $
347 Prelude.take 3 $ Prelude.enumFromThenTo f th to
349-------------------------------------------------------------------------------
350enumerateFromSmallBoundedBool :: Property
351enumerateFromSmallBoundedBool =
354 let unf = UF.take 2 UF.enumerateFromSmallBounded
355 in testUnfold unf (f :: Bool) $
356 Prelude.take 2 $ Prelude.enumFrom f
358enumerateFromThenSmallBoundedBool :: Property
359enumerateFromThenSmallBoundedBool =
362 let unf = UF.take 2 UF.enumerateFromThenSmallBounded
363 in testUnfold unf (f :: Bool, th) $
364 Prelude.take 2 $ Prelude.enumFromThen f th
366enumerateFromToSmallBool :: Property
367enumerateFromToSmallBool =
370 let unf = UF.take 2 UF.enumerateFromToSmall
371 in testUnfold unf (f :: Bool, to) $
372 Prelude.take 2 $ Prelude.enumFromTo f to
374enumerateFromThenToSmallBool :: Property
375enumerateFromThenToSmallBool =
378 let unf = UF.take 2 UF.enumerateFromThenToSmall
379 in testUnfold unf (f :: Bool, th, to) $
380 Prelude.take 2 $ Prelude.enumFromThenTo f th to
381-------------------------------------------------------------------------------
382enumerateFromSmallBoundedUnit :: Property
383enumerateFromSmallBoundedUnit =
386 let unf = UF.take 1 UF.enumerateFromSmallBounded
387 in testUnfold unf (f :: ()) $
388 Prelude.take 1 $ Prelude.enumFrom f
390enumerateFromThenSmallBoundedUnit :: Property
391enumerateFromThenSmallBoundedUnit =
394 let unf = UF.take 1 UF.enumerateFromThenSmallBounded
395 in testUnfold unf (f :: (), th) $
396 Prelude.take 1 $ Prelude.enumFromThen f th
398enumerateFromToSmallUnit :: Property
399enumerateFromToSmallUnit =
402 let unf = UF.take 1 UF.enumerateFromToSmall
403 in testUnfold unf (f :: (), to) $
404 Prelude.take 1 $ Prelude.enumFromTo f to
406enumerateFromThenToSmallUnit :: Property
407enumerateFromThenToSmallUnit =
410 let unf = UF.take 1 UF.enumerateFromThenToSmall
411 in testUnfold unf (f :: (), th, to) $
412 Prelude.take 1 $ Prelude.enumFromThenTo f th to
415#if MIN_VERSION_base(4,12,0)
416enumerateFromFractional :: Property
417enumerateFromFractional =
420 let unf = UF.take 50 UF.enumerateFromFractional
421 in testUnfold unf (f :: Double) $
422 Prelude.take 50 $ Prelude.enumFrom f
424enumerateFromThenFractional :: Property
425enumerateFromThenFractional =
428 let unf = UF.take 50 UF.enumerateFromThenFractional
429 in testUnfold unf (f :: Double, th) $
430 Prelude.take 50 $ Prelude.enumFromThen f th
432enumerateFromThenToFractional :: Property
433enumerateFromThenToFractional =
436 let unf = UF.take 50 UF.enumerateFromThenToFractional
437 in testUnfold unf (f :: Double, th, to) $
438 Prelude.take 50 $ Prelude.enumFromThenTo f th to
440enumerateFromToFractional :: Property
441enumerateFromToFractional =
444 let unf = UF.enumerateFromToFractional
445 in testUnfold unf (f :: Double, t) [f..(t :: Double)]
449-------------------------------------------------------------------------------
450-- Stream transformation
451-------------------------------------------------------------------------------
457 let unf = UF.postscan Fold.sum UF.fromList
458 mList = scanl1 (+) ls
459 in testUnfold unf ls mList
465 let fA = apply f :: Int -> Int
466 fM x = modify (+ 1) >> return (fA x)
467 unf = UF.mapM fM UF.fromList
468 mList = Prelude.map fA list
469 in testUnfoldMD unf list 0 (length list) mList
471mapMWithInput :: Property
475 let fA = applyFun2 f :: [Int] -> Int -> Int
476 fM x y = modify (+ 1) >> return (fA x y)
477 unf = UF.mapMWithInput fM UF.fromList
478 mList = Prelude.map (fA list) list
479 in testUnfoldMD unf list 0 (length list) mList
486 (UF.take i UF.repeatM)
488 (Prelude.take i (Prelude.repeat 1))
490takeWhileM :: Property
496 then modify (+ 1) >> return True
498 unf = UF.takeWhileM fM UF.fromList
499 fL = Prelude.takeWhile (apply f) list
500 fS = Prelude.length fL
501 in testUnfoldMD unf list 0 fS fL
509 then modify (+ 1) >> return True
511 unf = UF.filterM fM UF.fromList
512 fL = Prelude.filter (apply f) list
513 fS = Prelude.length fL
514 in testUnfoldMD unf list 0 fS fL
520 let unf = UF.drop i UF.fromList
521 fL = Prelude.drop i list
522 in testUnfoldD unf list fL
524dropWhileM :: Property
530 then modify (+ 1) >> return True
532 unf = UF.dropWhileM fM UF.fromList
533 fL = Prelude.dropWhile (apply f) list
534 fS = Prelude.length list - Prelude.length fL
535 in testUnfoldMD unf list 0 fS fL
537-------------------------------------------------------------------------------
539-------------------------------------------------------------------------------
545 let unf1 = UF.enumerateFromToIntegral
546 unf2 = UF.enumerateFromToIntegral
547 fA = applyFun2 f :: Int -> Int -> Int
548 fM a b = modify (+ 1) >> return (fA a b)
549 unf = UF.zipWithM fM (UF.lmap fst unf1) (UF.lmap snd unf2)
550 lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
551 in testUnfoldMD unf ((1,10), (1,20)) 0 10 lst
555 let unfIn = UF.replicateM 10
556 unfOut = UF.map return UF.enumerateFromToIntegral
557 unf = UF.many unfIn unfOut
558 lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
559 in testUnfoldD unf (1, 10) lst
563 let unf1 = UF.enumerateFromToIntegral
564 unf2 = UF.enumerateFromToIntegral
565 unf = crossProduct unf1 unf2
566 lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
567 in testUnfold unf (((0,10) ,(0,20)) :: ((Int, Int), (Int, Int))) lst
571 crossProduct u1 u2 = UF.cross (UF.lmap fst u1) (UF.lmap snd u2)
576 let u = UF.lmap (\_ -> modify (+ 1) >> return b) (UF.replicateM 10)
577 in modify (+ 1) >> return u
578 unf = UF.concatMapM inner UF.enumerateFromToIntegral
579 list = List.concatMap (replicate 10) [1 .. 10]
580 in testUnfoldMD unf (1, 10) 0 110 list
582-------------------------------------------------------------------------------
584-------------------------------------------------------------------------------
595 prop "discardFirst" discardFirst
596 prop "discardSecond" discardSecond
599testGeneration :: Spec
601 describe "Generation"
603 prop "fromStream" fromStream
604 prop "fromStreamK" fromStreamK
605 prop "fromStreamD" fromStreamD
608 prop "functionM" functionM
609 -- prop "function" function
610 -- prop "identity" identity
612 prop "unfoldrM" unfoldrM
613 -- prop "fromList" fromList
614 prop "fromListM" fromListM
615 -- prop "fromSVar" fromSVar
616 -- prop "fromProducer" fromProducer
617 prop "replicateM" replicateM
618 prop "repeatM" repeatM
619 prop "iterateM" iterateM
620 prop "fromIndicesM" fromIndicesM
621 ----------- Enumerate from Num ------------------------------------
622 prop "enumerateFromNum" enumerateFromNum
623 prop "enumerateFromThenNum" enumerateFromThenNum
624 ----------- Enumerate from Integral -------------------------------
625 prop "enumerateFromIntegral" enumerateFromIntegral
626 prop "enumerateFromThenIntegral" enumerateFromThenIntegral
627 prop "enumerateFromToIntegral" enumerateFromToIntegral
628 prop "enumerateFromThenToIntegral" enumerateFromThenToIntegral
630 prop "enumerateFromIntegralBounded" enumerateFromIntegralBounded
631 prop "enumerateFromThenIntegralBounded" enumerateFromThenIntegralBounded
632 prop "enumerateFromToIntegralBounded" enumerateFromToIntegralBounded
633 prop "enumerateFromThenToIntegralBounded" enumerateFromThenToIntegralBounded
634 ----------- Enumerate from Small Integral -------------------------
635 prop "enumerateFromSmallBounded" enumerateFromSmallBounded
636 prop "enumerateFromThenSmallBounded" enumerateFromThenSmallBounded
637 prop "enumerateFromToSmall" enumerateFromToSmall
638 prop "enumerateFromThenToSmall" enumerateFromThenToSmall
640 prop "enumerateFromSmallBoundedOrd" enumerateFromSmallBoundedOrd
641 prop "enumerateFromThenSmallBoundedOrd" enumerateFromThenSmallBoundedOrd
642 prop "enumerateFromToSmallOrd" enumerateFromToSmallOrd
643 prop "enumerateFromThenToSmallOrd" enumerateFromThenToSmallOrd
645 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedUnit
646 prop "enumerateFromThenSmallBoundedUnit" enumerateFromThenSmallBoundedUnit
647 prop "enumerateFromToSmallUnit" enumerateFromToSmallUnit
648 prop "enumerateFromThenToSmallUnit" enumerateFromThenToSmallUnit
650 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedBool
651 prop "enumerateFromThenSmallBoundedBool" enumerateFromThenSmallBoundedBool
652 prop "enumerateFromToSmallBool" enumerateFromToSmallBool
653 prop "enumerateFromThenToSmallBool" enumerateFromThenToSmallBool
655#if MIN_VERSION_base(4,12,0)
656 prop "enumerateFromFractional" enumerateFromFractional
657 prop "enumerateFromThenFractional" enumerateFromThenFractional
658 prop "enumerateFromToFractional" enumerateFromToFractional
659 prop "enumerateFromThenToFractional" enumerateFromThenToFractional
662testTransformation :: Spec
664 describe "Transformation"
667 prop "postscan" postscan
669 prop "mapMWithInput" mapMWithInput
670 prop "takeWhileM" takeWhileM
671 -- prop "takeWhile" takeWhile
673 -- prop "filter" filter
674 prop "filterM" filterM
676 -- prop "dropWhile" dropWhile
677 prop "dropWhileM" dropWhileM
679testCombination :: Spec
681 describe "Transformation"
683 prop "zipWithM" zipWithM
684 -- prop "zipWith" zipWith
685 -- prop "teeZipWith" teeZipWith
687 prop "concatMapM" concatMapM
688 prop "outerProduct" outerProduct
690 -- prop "apDiscardFst" apDiscardFst
691 -- prop "apDiscardSnd" apDiscardSnd
693-------------------------------------------------------------------------------
695-------------------------------------------------------------------------------
698moduleName = "Data.Unfold"
703 $ 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