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
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
414#if MIN_VERSION_base(4,12,0)
415enumerateFromFractional :: Property
416enumerateFromFractional =
419 let unf = UF.take 50 UF.enumerateFromFractional
420 in testUnfold unf (f :: Double) $
421 Prelude.take 50 $ Prelude.enumFrom f
423enumerateFromThenFractional :: Property
424enumerateFromThenFractional =
427 let unf = UF.take 50 UF.enumerateFromThenFractional
428 in testUnfold unf (f :: Double, th) $
429 Prelude.take 50 $ Prelude.enumFromThen f th
431enumerateFromThenToFractional :: Property
432enumerateFromThenToFractional =
435 let unf = UF.take 50 UF.enumerateFromThenToFractional
436 in testUnfold unf (f :: Double, th, to) $
437 Prelude.take 50 $ Prelude.enumFromThenTo f th to
439enumerateFromToFractional :: Property
440enumerateFromToFractional =
443 let unf = UF.enumerateFromToFractional
444 in testUnfold unf (f :: Double, t) [f..(t :: Double)]
448-------------------------------------------------------------------------------
449-- Stream transformation
450-------------------------------------------------------------------------------
456 let fA = apply f :: Int -> Int
457 fM x = modify (+ 1) >> return (fA x)
458 unf = UF.mapM fM UF.fromList
459 mList = Prelude.map fA list
460 in testUnfoldMD unf list 0 (length list) mList
462mapMWithInput :: Property
466 let fA = applyFun2 f :: [Int] -> Int -> Int
467 fM x y = modify (+ 1) >> return (fA x y)
468 unf = UF.mapMWithInput fM UF.fromList
469 mList = Prelude.map (fA list) list
470 in testUnfoldMD unf list 0 (length list) mList
477 (UF.take i UF.repeatM)
479 (Prelude.take i (Prelude.repeat 1))
481takeWhileM :: Property
487 then modify (+ 1) >> return True
489 unf = UF.takeWhileM fM UF.fromList
490 fL = Prelude.takeWhile (apply f) list
491 fS = Prelude.length fL
492 in testUnfoldMD unf list 0 fS fL
500 then modify (+ 1) >> return True
502 unf = UF.filterM fM UF.fromList
503 fL = Prelude.filter (apply f) list
504 fS = Prelude.length fL
505 in testUnfoldMD unf list 0 fS fL
511 let unf = UF.drop i UF.fromList
512 fL = Prelude.drop i list
513 in testUnfoldD unf list fL
515dropWhileM :: Property
521 then modify (+ 1) >> return True
523 unf = UF.dropWhileM fM UF.fromList
524 fL = Prelude.dropWhile (apply f) list
525 fS = Prelude.length list - Prelude.length fL
526 in testUnfoldMD unf list 0 fS fL
528-------------------------------------------------------------------------------
530-------------------------------------------------------------------------------
536 let unf1 = UF.enumerateFromToIntegral
537 unf2 = UF.enumerateFromToIntegral
538 fA = applyFun2 f :: Int -> Int -> Int
539 fM a b = modify (+ 1) >> return (fA a b)
540 unf = UF.zipWithM fM (UF.lmap fst unf1) (UF.lmap snd unf2)
541 lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
542 in testUnfoldMD unf ((1,10), (1,20)) 0 10 lst
546 let unfIn = UF.replicateM 10
547 unfOut = UF.map return UF.enumerateFromToIntegral
548 unf = UF.many unfOut unfIn
549 lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
550 in testUnfoldD unf (1, 10) lst
554 let unf1 = UF.enumerateFromToIntegral
555 unf2 = UF.enumerateFromToIntegral
556 unf = crossProduct unf1 unf2
557 lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
558 in testUnfold unf (((0,10) ,(0,20)) :: ((Int, Int), (Int, Int))) lst
562 crossProduct u1 u2 = UF.cross (UF.lmap fst u1) (UF.lmap snd u2)
567 let u = UF.lmap (\_ -> modify (+ 1) >> return b) (UF.replicateM 10)
568 in modify (+ 1) >> return u
569 unf = UF.concatMapM inner UF.enumerateFromToIntegral
570 list = List.concatMap (replicate 10) [1 .. 10]
571 in testUnfoldMD unf (1, 10) 0 110 list
573-------------------------------------------------------------------------------
575-------------------------------------------------------------------------------
584 prop "supplyFirst" supplyFirst
585 prop "supplySecond" supplySecond
586 prop "discardFirst" discardFirst
587 prop "discardSecond" discardSecond
590testGeneration :: Spec
592 describe "Generation"
594 prop "fromStream" fromStream
595 prop "fromStreamK" fromStreamK
596 prop "fromStreamD" fromStreamD
599 prop "functionM" functionM
600 -- prop "function" function
601 -- prop "identity" identity
603 prop "unfoldrM" unfoldrM
604 -- prop "fromList" fromList
605 prop "fromListM" fromListM
606 -- prop "fromSVar" fromSVar
607 -- prop "fromProducer" fromProducer
608 prop "replicateM" replicateM
609 prop "repeatM" repeatM
610 prop "iterateM" iterateM
611 prop "fromIndicesM" fromIndicesM
612 ----------- Enumerate from Num ------------------------------------
613 prop "enumerateFromNum" enumerateFromNum
614 prop "enumerateFromThenNum" enumerateFromThenNum
615 ----------- Enumerate from Integral -------------------------------
616 prop "enumerateFromIntegral" enumerateFromIntegral
617 prop "enumerateFromThenIntegral" enumerateFromThenIntegral
618 prop "enumerateFromToIntegral" enumerateFromToIntegral
619 prop "enumerateFromThenToIntegral" enumerateFromThenToIntegral
621 prop "enumerateFromIntegralBounded" enumerateFromIntegralBounded
622 prop "enumerateFromThenIntegralBounded" enumerateFromThenIntegralBounded
623 prop "enumerateFromToIntegralBounded" enumerateFromToIntegralBounded
624 prop "enumerateFromThenToIntegralBounded" enumerateFromThenToIntegralBounded
625 ----------- Enumerate from Small Integral -------------------------
626 prop "enumerateFromSmallBounded" enumerateFromSmallBounded
627 prop "enumerateFromThenSmallBounded" enumerateFromThenSmallBounded
628 prop "enumerateFromToSmall" enumerateFromToSmall
629 prop "enumerateFromThenToSmall" enumerateFromThenToSmall
631 prop "enumerateFromSmallBoundedOrd" enumerateFromSmallBoundedOrd
632 prop "enumerateFromThenSmallBoundedOrd" enumerateFromThenSmallBoundedOrd
633 prop "enumerateFromToSmallOrd" enumerateFromToSmallOrd
634 prop "enumerateFromThenToSmallOrd" enumerateFromThenToSmallOrd
636 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedUnit
637 prop "enumerateFromThenSmallBoundedUnit" enumerateFromThenSmallBoundedUnit
638 prop "enumerateFromToSmallUnit" enumerateFromToSmallUnit
639 prop "enumerateFromThenToSmallUnit" enumerateFromThenToSmallUnit
641 prop "enumerateFromSmallBoundedUnit" enumerateFromSmallBoundedBool
642 prop "enumerateFromThenSmallBoundedBool" enumerateFromThenSmallBoundedBool
643 prop "enumerateFromToSmallBool" enumerateFromToSmallBool
644 prop "enumerateFromThenToSmallBool" enumerateFromThenToSmallBool
646#if MIN_VERSION_base(4,12,0)
647 prop "enumerateFromFractional" enumerateFromFractional
648 prop "enumerateFromThenFractional" enumerateFromThenFractional
649 prop "enumerateFromToFractional" enumerateFromToFractional
650 prop "enumerateFromThenToFractional" enumerateFromThenToFractional
653testTransformation :: Spec
655 describe "Transformation"
659 prop "mapMWithInput" mapMWithInput
660 prop "takeWhileM" takeWhileM
661 -- prop "takeWhile" takeWhile
663 -- prop "filter" filter
664 prop "filterM" filterM
666 -- prop "dropWhile" dropWhile
667 prop "dropWhileM" dropWhileM
669testCombination :: Spec
671 describe "Transformation"
673 prop "zipWithM" zipWithM
674 -- prop "zipWith" zipWith
675 -- prop "teeZipWith" teeZipWith
677 prop "concatMapM" concatMapM
678 prop "outerProduct" outerProduct
680 -- prop "apDiscardFst" apDiscardFst
681 -- prop "apDiscardSnd" apDiscardSnd
683-------------------------------------------------------------------------------
685-------------------------------------------------------------------------------
688moduleName = "Data.Unfold"
693 $ 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