mirror of
https://github.com/composewell/streamly.git
synced 2024-09-11 11:37:22 +03:00
Add stream generation functions to Data.Stream
This commit is contained in:
parent
b528bae8ce
commit
98d3ea9d27
@ -13,10 +13,8 @@ module Stream.Common
|
||||
( MonadAsync
|
||||
|
||||
-- Generation
|
||||
, enumerateFromTo
|
||||
, replicate
|
||||
, unfoldrM
|
||||
, fromListM
|
||||
, fromFoldableM
|
||||
|
||||
, append
|
||||
, append2
|
||||
@ -32,7 +30,6 @@ module Stream.Common
|
||||
, sourceUnfoldrAction
|
||||
, sourceConcatMapId
|
||||
, sourceFromFoldable
|
||||
, sourceFromFoldableM
|
||||
|
||||
-- Benchmark stream elimination
|
||||
, benchIOSink
|
||||
@ -78,15 +75,12 @@ import Streamly.Prelude (foldl', scanl')
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as Stream
|
||||
import qualified Streamly.Prelude as Stream
|
||||
import Streamly.Benchmark.Prelude
|
||||
( composeN, sourceUnfoldr, sourceUnfoldr, sourceFromFoldable
|
||||
, sourceFromFoldableM, sourceUnfoldrAction, sourceConcatMapId, benchIOSink
|
||||
( composeN, sourceConcatMapId, benchIOSink
|
||||
, concatStreamsWith, concatPairsWith
|
||||
)
|
||||
#else
|
||||
import Control.DeepSeq (NFData)
|
||||
import Streamly.Internal.Data.Stream (unfold)
|
||||
import qualified Streamly.Internal.Data.Stream as Stream
|
||||
import qualified Streamly.Internal.Data.Unfold as Unfold
|
||||
#endif
|
||||
|
||||
import Gauge
|
||||
@ -118,41 +112,25 @@ append2 = Stream.append2
|
||||
drain :: Monad m => Stream m a -> m ()
|
||||
drain = Stream.fold Fold.drain
|
||||
|
||||
{-# INLINE enumerateFromTo #-}
|
||||
enumerateFromTo :: Monad m => Int -> Int -> Stream m Int
|
||||
#ifdef USE_PRELUDE
|
||||
enumerateFromTo = Stream.enumerateFromTo
|
||||
#else
|
||||
enumerateFromTo from to = Stream.unfold Unfold.enumerateFromTo (from, to)
|
||||
#endif
|
||||
|
||||
{-# INLINE replicate #-}
|
||||
replicate :: Monad m => Int -> a -> Stream m a
|
||||
#ifdef USE_PRELUDE
|
||||
replicate = Stream.replicate
|
||||
#else
|
||||
replicate n = Stream.unfold (Unfold.replicateM n) . return
|
||||
#endif
|
||||
|
||||
{-# INLINE unfoldrM #-}
|
||||
unfoldrM :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> Stream m a
|
||||
#ifdef USE_PRELUDE
|
||||
unfoldrM = Stream.unfoldrM
|
||||
#else
|
||||
unfoldrM step = Stream.unfold (Unfold.unfoldrM step)
|
||||
#endif
|
||||
|
||||
{-# INLINE fromListM #-}
|
||||
fromListM :: MonadAsync m => [m a] -> Stream m a
|
||||
#ifdef USE_PRELUDE
|
||||
fromListM = Stream.fromListM
|
||||
#else
|
||||
fromListM = Stream.unfold Unfold.fromListM
|
||||
fromListM = Stream.sequence . Stream.fromList
|
||||
#endif
|
||||
|
||||
{-# INLINE fromFoldableM #-}
|
||||
fromFoldableM :: MonadAsync m => [m a] -> Stream m a
|
||||
#ifdef USE_PRELUDE
|
||||
fromFoldableM = Stream.fromFoldableM
|
||||
#else
|
||||
fromFoldableM = Stream.sequence . Stream.fromFoldable
|
||||
#endif
|
||||
|
||||
{-# INLINE sourceUnfoldrM #-}
|
||||
sourceUnfoldrM :: MonadAsync m => Int -> Int -> Stream m Int
|
||||
sourceUnfoldrM count start = unfoldrM step start
|
||||
sourceUnfoldrM count start = Stream.unfoldrM step start
|
||||
|
||||
where
|
||||
|
||||
@ -161,10 +139,9 @@ sourceUnfoldrM count start = unfoldrM step start
|
||||
then return Nothing
|
||||
else return (Just (cnt, cnt + 1))
|
||||
|
||||
#ifndef USE_PRELUDE
|
||||
{-# INLINE sourceUnfoldr #-}
|
||||
sourceUnfoldr :: Monad m => Int -> Int -> Stream m Int
|
||||
sourceUnfoldr count start = unfold (Unfold.unfoldr step) start
|
||||
sourceUnfoldr count start = Stream.unfoldr step start
|
||||
|
||||
where
|
||||
|
||||
@ -175,7 +152,7 @@ sourceUnfoldr count start = unfold (Unfold.unfoldr step) start
|
||||
|
||||
{-# INLINE sourceUnfoldrAction #-}
|
||||
sourceUnfoldrAction :: (Monad m1, Monad m) => Int -> Int -> Stream m (m1 Int)
|
||||
sourceUnfoldrAction value n = unfold (Unfold.unfoldr step) n
|
||||
sourceUnfoldrAction value n = Stream.unfoldr step n
|
||||
|
||||
where
|
||||
|
||||
@ -188,10 +165,7 @@ sourceUnfoldrAction value n = unfold (Unfold.unfoldr step) n
|
||||
sourceFromFoldable :: Int -> Int -> Stream m Int
|
||||
sourceFromFoldable value n = Stream.fromFoldable [n..n+value]
|
||||
|
||||
{-# INLINE sourceFromFoldableM #-}
|
||||
sourceFromFoldableM :: Monad m => Int -> Int -> Stream m Int
|
||||
sourceFromFoldableM value n = Stream.fromFoldableM (fmap return [n..n+value])
|
||||
|
||||
#ifndef USE_PRELUDE
|
||||
{-# INLINE benchIOSink #-}
|
||||
benchIOSink
|
||||
:: (NFData b)
|
||||
|
@ -22,7 +22,7 @@
|
||||
module Stream.Exceptions (benchmarks) where
|
||||
|
||||
import Control.Exception (SomeException, Exception, throwIO)
|
||||
import Stream.Common (drain, enumerateFromTo)
|
||||
import Stream.Common (drain)
|
||||
import Streamly.Internal.Data.Stream.Serial (SerialT)
|
||||
import System.IO (Handle, hClose, hPutChar)
|
||||
|
||||
@ -36,7 +36,6 @@ import qualified Streamly.Internal.FileSystem.Handle as IFH
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as Stream
|
||||
#else
|
||||
import qualified Streamly.Internal.Data.Stream as Stream
|
||||
import qualified Streamly.Internal.Data.Unfold as Unfold
|
||||
#endif
|
||||
|
||||
import Gauge hiding (env)
|
||||
@ -59,7 +58,7 @@ replicateM :: Common.MonadAsync m => Int -> m a -> SerialT m a
|
||||
#ifdef USE_PRELUDE
|
||||
replicateM = Stream.replicateM
|
||||
#else
|
||||
replicateM = Stream.unfold . Unfold.replicateM
|
||||
replicateM n = Stream.sequence . Stream.replicate n
|
||||
#endif
|
||||
|
||||
data BenchException
|
||||
@ -79,7 +78,7 @@ retryNoneSimple length from =
|
||||
|
||||
where
|
||||
|
||||
source = enumerateFromTo from (from + length)
|
||||
source = Stream.enumerateFromTo from (from + length)
|
||||
|
||||
retryNone :: Int -> Int -> IO ()
|
||||
retryNone length from = do
|
||||
@ -121,7 +120,7 @@ retryUnknown length from = do
|
||||
|
||||
where
|
||||
|
||||
source = enumerateFromTo from (from + length)
|
||||
source = Stream.enumerateFromTo from (from + length)
|
||||
|
||||
|
||||
o_1_space_serial_exceptions :: Int -> [Benchmark]
|
||||
|
@ -32,15 +32,14 @@ import Test.Inspection
|
||||
import qualified Streamly.Internal.Data.Stream.StreamD as D
|
||||
#endif
|
||||
|
||||
import Streamly.Benchmark.Prelude (benchIO)
|
||||
import qualified Stream.Common as Common
|
||||
#ifdef USE_PRELUDE
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as S
|
||||
import Streamly.Benchmark.Prelude hiding
|
||||
(benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2, toNullAp
|
||||
, monadThen, toNullM, toNullM3, filterAllInM, filterAllOutM, filterSome
|
||||
, breakAfterSome, toListM, toListSome)
|
||||
import Streamly.Benchmark.Prelude
|
||||
( sourceFoldMapM, sourceFoldMapWith, sourceFoldMapWithM
|
||||
, sourceFoldMapWithStream, concatFoldableWith, concatForFoldableWith)
|
||||
#else
|
||||
import Streamly.Benchmark.Prelude (benchIO)
|
||||
import qualified Streamly.Internal.Data.Stream as S
|
||||
#endif
|
||||
import qualified Streamly.Internal.Data.Unfold as UF
|
||||
@ -214,7 +213,7 @@ inspect $ 'concatMapPure `hasNoType` ''SPEC
|
||||
{-# INLINE concatMapRepl #-}
|
||||
concatMapRepl :: Int -> Int -> Int -> IO ()
|
||||
concatMapRepl outer inner n =
|
||||
drain $ S.concatMap (Common.replicate inner) (sourceUnfoldrM outer n)
|
||||
drain $ S.concatMap (S.replicate inner) (sourceUnfoldrM outer n)
|
||||
|
||||
#ifdef INSPECTION
|
||||
inspect $ hasNoTypeClasses 'concatMapRepl
|
||||
@ -423,7 +422,7 @@ o_n_space_monad value =
|
||||
, benchIO "(>>=) (sqrt n x sqrt n) (toListSome)" $
|
||||
toListSome value
|
||||
, benchIO "naive prime sieve (n/4)"
|
||||
(\n -> S.fold Fold.sum $ sieve $ enumerateFromTo 2 (value `div` 4 + n))
|
||||
(\n -> S.fold Fold.sum $ sieve $ S.enumerateFromTo 2 (value `div` 4 + n))
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -13,26 +13,23 @@ module Stream.Generate (benchmarks) where
|
||||
|
||||
import Data.Functor.Identity (Identity)
|
||||
|
||||
import qualified GHC.Exts as GHC
|
||||
import qualified Stream.Common as Common
|
||||
#ifdef USE_PRELUDE
|
||||
import qualified GHC.Exts as GHC
|
||||
import Streamly.Benchmark.Prelude (sourceFromFoldableM, absTimes)
|
||||
import qualified Streamly.Prelude as S
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as Stream
|
||||
import qualified Prelude
|
||||
#else
|
||||
import qualified Streamly.Internal.Data.Stream as Stream
|
||||
#endif
|
||||
import qualified Prelude
|
||||
|
||||
import Gauge
|
||||
import Streamly.Benchmark.Common
|
||||
import Streamly.Internal.Data.Stream.Serial (SerialT)
|
||||
#ifdef USE_PRELUDE
|
||||
import Streamly.Prelude (MonadAsync)
|
||||
import Stream.Common hiding (MonadAsync, replicate, enumerateFromTo)
|
||||
import Streamly.Benchmark.Prelude hiding
|
||||
(benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2, toNullAp
|
||||
, monadThen, toNullM, toNullM3, filterAllInM, filterAllOutM, filterSome
|
||||
, breakAfterSome, toListM, toListSome)
|
||||
import Stream.Common hiding (MonadAsync)
|
||||
#else
|
||||
import Stream.Common
|
||||
#endif
|
||||
@ -49,7 +46,14 @@ import Prelude hiding (repeat, replicate, iterate)
|
||||
-- fromList
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
#ifdef USE_PRELUDE
|
||||
{-# INLINE sourceFromList #-}
|
||||
sourceFromList :: Monad m => Int -> Int -> SerialT m Int
|
||||
sourceFromList value n = Stream.fromList [n..n+value]
|
||||
|
||||
{-# INLINE sourceFromListM #-}
|
||||
sourceFromListM :: MonadAsync m => Int -> Int -> SerialT m Int
|
||||
sourceFromListM value n = fromListM (fmap return [n..n+value])
|
||||
|
||||
{-# INLINE sourceIsList #-}
|
||||
sourceIsList :: Int -> Int -> SerialT Identity Int
|
||||
sourceIsList value n = GHC.fromList [n..n+value]
|
||||
@ -57,7 +61,6 @@ sourceIsList value n = GHC.fromList [n..n+value]
|
||||
{-# INLINE sourceIsString #-}
|
||||
sourceIsString :: Int -> Int -> SerialT Identity Char
|
||||
sourceIsString value n = GHC.fromString (Prelude.replicate (n + value) 'a')
|
||||
#endif
|
||||
|
||||
{-# INLINE readInstance #-}
|
||||
readInstance :: String -> SerialT Identity Int
|
||||
@ -76,56 +79,83 @@ readInstanceList str =
|
||||
[(x,"")] -> x
|
||||
_ -> error "readInstance: no parse"
|
||||
|
||||
#ifdef USE_PRELUDE
|
||||
{-# INLINE repeat #-}
|
||||
repeat :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
repeat count = S.take count . S.repeat
|
||||
|
||||
{-# INLINE repeatM #-}
|
||||
repeatM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
|
||||
repeatM count = S.take count . S.repeatM . return
|
||||
repeat :: Monad m => Int -> Int -> SerialT m Int
|
||||
repeat count = Stream.take count . Stream.repeat
|
||||
|
||||
{-# INLINE replicate #-}
|
||||
replicate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
replicate = S.replicate
|
||||
replicate :: Monad m => Int -> Int -> SerialT m Int
|
||||
replicate = Stream.replicate
|
||||
|
||||
{-# INLINE replicateM #-}
|
||||
replicateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
|
||||
replicateM count = S.replicateM count . return
|
||||
-------------------------------------------------------------------------------
|
||||
-- enumerate
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
{-# INLINE sourceIntFromTo #-}
|
||||
sourceIntFromTo :: Monad m => Int -> Int -> SerialT m Int
|
||||
sourceIntFromTo value n = Stream.enumerateFromTo n (n + value)
|
||||
|
||||
{-# INLINE sourceIntFromThenTo #-}
|
||||
sourceIntFromThenTo :: Monad m => Int -> Int -> SerialT m Int
|
||||
sourceIntFromThenTo value n = Stream.enumerateFromThenTo n (n + 1) (n + value)
|
||||
|
||||
{-# INLINE sourceFracFromTo #-}
|
||||
sourceFracFromTo :: Monad m => Int -> Int -> SerialT m Double
|
||||
sourceFracFromTo value n =
|
||||
Stream.enumerateFromTo (fromIntegral n) (fromIntegral (n + value))
|
||||
|
||||
{-# INLINE sourceFracFromThenTo #-}
|
||||
sourceFracFromThenTo :: Monad m => Int -> Int -> SerialT m Double
|
||||
sourceFracFromThenTo value n = Stream.enumerateFromThenTo (fromIntegral n)
|
||||
(fromIntegral n + 1.0001) (fromIntegral (n + value))
|
||||
|
||||
{-# INLINE sourceIntegerFromStep #-}
|
||||
sourceIntegerFromStep :: Monad m => Int -> Int -> SerialT m Integer
|
||||
sourceIntegerFromStep value n =
|
||||
Stream.take value $ Stream.enumerateFromThen (fromIntegral n) (fromIntegral n + 1)
|
||||
|
||||
{-# INLINE enumerateFrom #-}
|
||||
enumerateFrom :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerateFrom count = S.take count . S.enumerateFrom
|
||||
enumerateFrom :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerateFrom count = Stream.take count . Stream.enumerateFrom
|
||||
|
||||
{-# INLINE enumerateFromTo #-}
|
||||
enumerateFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerateFromTo :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerateFromTo = sourceIntFromTo
|
||||
|
||||
{-# INLINE enumerateFromThen #-}
|
||||
enumerateFromThen :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerateFromThen count inp = S.take count $ S.enumerateFromThen inp (inp + 1)
|
||||
enumerateFromThen :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerateFromThen count inp = Stream.take count $ Stream.enumerateFromThen inp (inp + 1)
|
||||
|
||||
{-# INLINE enumerateFromThenTo #-}
|
||||
enumerateFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerateFromThenTo :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerateFromThenTo = sourceIntFromThenTo
|
||||
|
||||
-- n ~ 1
|
||||
{-# INLINE enumerate #-}
|
||||
enumerate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerate count n = S.take (count + n) S.enumerate
|
||||
enumerate :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerate count n = Stream.take (count + n) Stream.enumerate
|
||||
|
||||
-- n ~ 1
|
||||
{-# INLINE enumerateTo #-}
|
||||
enumerateTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
enumerateTo count n = S.enumerateTo (minBound + count + n)
|
||||
enumerateTo :: Monad m => Int -> Int -> SerialT m Int
|
||||
enumerateTo count n = Stream.enumerateTo (minBound + count + n)
|
||||
|
||||
{-# INLINE iterate #-}
|
||||
iterate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
iterate count = S.take count . S.iterate (+1)
|
||||
iterate :: Monad m => Int -> Int -> SerialT m Int
|
||||
iterate count = Stream.take count . Stream.iterate (+1)
|
||||
|
||||
{-# INLINE iterateM #-}
|
||||
iterateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
|
||||
iterateM count = S.take count . S.iterateM (return . (+1)) . return
|
||||
iterateM :: MonadAsync m => Int -> Int -> SerialT m Int
|
||||
iterateM count = Stream.take count . Stream.iterateM (return . (+1)) . return
|
||||
|
||||
#ifdef USE_PRELUDE
|
||||
{-# INLINE repeatM #-}
|
||||
repeatM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
|
||||
repeatM count = S.take count . S.repeatM . return
|
||||
|
||||
{-# INLINE replicateM #-}
|
||||
replicateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
|
||||
replicateM count = S.replicateM count . return
|
||||
|
||||
{-# INLINE fromIndices #-}
|
||||
fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
|
||||
@ -151,37 +181,37 @@ o_1_space_generation value =
|
||||
[ bgroup "generation"
|
||||
[ benchIOSrc "unfoldr" (sourceUnfoldr value)
|
||||
, benchIOSrc "unfoldrM" (sourceUnfoldrM value)
|
||||
#ifdef USE_PRELUDE
|
||||
, benchIOSrc "repeat" (repeat value)
|
||||
, benchIOSrc "repeatM" (repeatM value)
|
||||
, benchIOSrc "replicate" (replicate value)
|
||||
, benchIOSrc "replicateM" (replicateM value)
|
||||
, benchIOSrc "iterate" (iterate value)
|
||||
, benchIOSrc "iterateM" (iterateM value)
|
||||
, benchIOSrc "fromIndices" (fromIndices value)
|
||||
, benchIOSrc "fromIndicesM" (fromIndicesM value)
|
||||
, benchIOSrc "intFromTo" (sourceIntFromTo value)
|
||||
, benchIOSrc "intFromThenTo" (sourceIntFromThenTo value)
|
||||
, benchIOSrc "integerFromStep" (sourceIntegerFromStep value)
|
||||
, benchIOSrc "fracFromThenTo" (sourceFracFromThenTo value)
|
||||
, benchIOSrc "fracFromTo" (sourceFracFromTo value)
|
||||
, benchIOSrc "fromList" (sourceFromList value)
|
||||
, benchIOSrc "fromListM" (sourceFromListM value)
|
||||
, benchPureSrc "IsList.fromList" (sourceIsList value)
|
||||
, benchPureSrc "IsString.fromString" (sourceIsString value)
|
||||
, benchIOSrc "fromListM" (sourceFromListM value)
|
||||
, benchIOSrc "enumerateFrom" (enumerateFrom value)
|
||||
, benchIOSrc "enumerateFromTo" (enumerateFromTo value)
|
||||
, benchIOSrc "enumerateFromThen" (enumerateFromThen value)
|
||||
, benchIOSrc "enumerateFromThenTo" (enumerateFromThenTo value)
|
||||
, benchIOSrc "enumerate" (enumerate value)
|
||||
, benchIOSrc "enumerateTo" (enumerateTo value)
|
||||
#ifdef USE_PRELUDE
|
||||
, benchIOSrc "repeatM" (repeatM value)
|
||||
, benchIOSrc "replicateM" (replicateM value)
|
||||
, benchIOSrc "fromIndices" (fromIndices value)
|
||||
, benchIOSrc "fromIndicesM" (fromIndicesM value)
|
||||
#endif
|
||||
|
||||
-- These essentially test cons and consM
|
||||
, benchIOSrc "fromFoldable" (sourceFromFoldable value)
|
||||
, benchIOSrc "fromFoldableM" (sourceFromFoldableM value)
|
||||
|
||||
#ifdef USE_PRELUDE
|
||||
, benchIOSrc "fromFoldableM" (sourceFromFoldableM value)
|
||||
, benchIOSrc "absTimes" $ absTimes value
|
||||
#endif
|
||||
, Common.benchIOSrc "mfix_10" (mfixUnfold 10)
|
||||
|
@ -42,7 +42,7 @@ import Prelude hiding (reverse, tail)
|
||||
{-# INLINE sourceUnfoldrState #-}
|
||||
sourceUnfoldrState :: Common.MonadAsync m =>
|
||||
Int -> Int -> SerialT (StateT Int m) Int
|
||||
sourceUnfoldrState value n = Common.unfoldrM step n
|
||||
sourceUnfoldrState value n = Stream.unfoldrM step n
|
||||
where
|
||||
step cnt =
|
||||
if cnt > n + value
|
||||
|
@ -32,11 +32,7 @@ import qualified Prelude
|
||||
import qualified Stream.Common as Common
|
||||
import qualified Streamly.Internal.Data.Unfold as Unfold
|
||||
#ifdef USE_PRELUDE
|
||||
import Streamly.Benchmark.Prelude hiding
|
||||
( benchIOSrc, sourceUnfoldrM, apDiscardFst, apDiscardSnd, apLiftA2, toNullAp
|
||||
, monadThen, toNullM, toNullM3, filterAllInM, filterAllOutM, filterSome
|
||||
, breakAfterSome, toListM, toListSome, transformMapM, transformComposeMapM
|
||||
, transformTeeMapM, transformZipMapM, mapN, mapM)
|
||||
import Streamly.Benchmark.Prelude (benchIO)
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as Stream
|
||||
import Streamly.Internal.Data.Time.Units
|
||||
#else
|
||||
@ -247,7 +243,7 @@ o_n_space_mapping :: Int -> [Benchmark]
|
||||
o_n_space_mapping value =
|
||||
[ bgroup "mapping"
|
||||
[ benchIO "naive prime sieve"
|
||||
(\n -> Stream.fold FL.sum $ sieveScan $ Common.enumerateFromTo 2 (value + n))
|
||||
(\n -> Stream.fold FL.sum $ sieveScan $ Stream.enumerateFromTo 2 (value + n))
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -14,6 +14,7 @@ module Streamly.Internal.Data.Stream.Bottom
|
||||
-- * Generation
|
||||
fromPure
|
||||
, fromEffect
|
||||
, fromList
|
||||
, timesWith
|
||||
, absTimesWith
|
||||
, relTimesWith
|
||||
@ -64,6 +65,7 @@ import Streamly.Internal.System.IO (defaultChunkSize)
|
||||
|
||||
import qualified Streamly.Internal.Data.Array.Unboxed.Type as A
|
||||
import qualified Streamly.Internal.Data.Fold as Fold
|
||||
import qualified Streamly.Internal.Data.Stream.Common as Common
|
||||
import qualified Streamly.Internal.Data.Stream.StreamK as K
|
||||
import qualified Streamly.Internal.Data.Stream.StreamD as D
|
||||
|
||||
@ -87,6 +89,20 @@ import Streamly.Internal.Data.Stream.Type
|
||||
-- >>> import qualified Streamly.Internal.Data.Parser as Parser
|
||||
-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Generation
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- |
|
||||
-- >>> fromList = Prelude.foldr Stream.cons Stream.nil
|
||||
--
|
||||
-- Construct a stream from a list of pure values. This is more efficient than
|
||||
-- 'fromFoldable'.
|
||||
--
|
||||
{-# INLINE fromList #-}
|
||||
fromList :: Monad m => [a] -> Stream m a
|
||||
fromList = fromStreamK . Common.fromList
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Generation - Time related
|
||||
------------------------------------------------------------------------------
|
||||
@ -100,8 +116,8 @@ import Streamly.Internal.Data.Stream.Type
|
||||
-- terms of CPU usage. Any granularity lower than 1 ms is treated as 1 ms.
|
||||
--
|
||||
-- >>> import Control.Concurrent (threadDelay)
|
||||
-- >>> import Streamly.Internal.Data.Stream.Generate as Stream (timesWith)
|
||||
-- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.timesWith 0.01
|
||||
-- >>> f = Fold.drainBy (\x -> print x >> threadDelay 1000000)
|
||||
-- >>> Stream.fold f $ Stream.take 3 $ Stream.timesWith 0.01
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
@ -119,7 +135,8 @@ timesWith g = fromStreamD $ D.times g
|
||||
-- expensive in terms of CPU usage. Any granularity lower than 1 ms is treated
|
||||
-- as 1 ms.
|
||||
--
|
||||
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimesWith 0.01
|
||||
-- >>> f = Fold.drainBy print
|
||||
-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimesWith 0.01
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
@ -137,7 +154,8 @@ absTimesWith = fmap (uncurry addToAbsTime64) . timesWith
|
||||
-- clock is more expensive in terms of CPU usage. Any granularity lower than 1
|
||||
-- ms is treated as 1 ms.
|
||||
--
|
||||
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimesWith 0.01
|
||||
-- >>> f = Fold.drainBy print
|
||||
-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimesWith 0.01
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
@ -172,7 +190,7 @@ foldContinue f s = D.foldContinue f $ toStreamD s
|
||||
-- 'Fold' can terminate early without consuming the full stream. See the
|
||||
-- documentation of individual 'Fold's for termination behavior.
|
||||
--
|
||||
-- >>> Stream.fold Fold.sum (Stream.unfold Unfold.enumerateFromTo (1, 100))
|
||||
-- >>> Stream.fold Fold.sum (Stream.enumerateFromTo 1 100)
|
||||
-- 5050
|
||||
--
|
||||
-- Folds never fail, therefore, they produce a default value even when no input
|
||||
@ -224,7 +242,7 @@ foldBreak fl strm = fmap f $ K.foldBreak fl (toStreamK strm)
|
||||
--
|
||||
-- Same as 'fmap'.
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ fmap (+1) $ Stream.unfold Unfold.fromList [1,2,3]
|
||||
-- >>> Stream.fold Fold.toList $ fmap (+1) $ Stream.fromList [1,2,3]
|
||||
-- [2,3,4]
|
||||
--
|
||||
{-# INLINE map #-}
|
||||
@ -239,7 +257,7 @@ map f = fromStreamD . D.map f . toStreamD
|
||||
--
|
||||
-- >>> import Data.Maybe (fromJust)
|
||||
-- >>> let avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)
|
||||
-- >>> s = Stream.unfold Unfold.enumerateFromTo (1.0, 100.0)
|
||||
-- >>> s = Stream.enumerateFromTo 1.0 100.0
|
||||
-- >>> :{
|
||||
-- Stream.fold Fold.toList
|
||||
-- $ fmap (fromJust . fst)
|
||||
@ -340,7 +358,7 @@ findIndices p m = fromStreamD $ D.findIndices p (toStreamD m)
|
||||
-- | Insert an effect and its output before consuming an element of a stream
|
||||
-- except the first one.
|
||||
--
|
||||
-- >>> input = Stream.unfold Unfold.fromList "hello"
|
||||
-- >>> input = Stream.fromList "hello"
|
||||
-- >>> Stream.fold Fold.toList $ Stream.trace putChar $ Stream.intersperseM (putChar '.' >> return ',') input
|
||||
-- h.,e.,l.,l.,o"h,e,l,l,o"
|
||||
--
|
||||
@ -433,11 +451,11 @@ concatM generator = concatMapM (\() -> generator) (fromPure ())
|
||||
-- termination aligns:
|
||||
--
|
||||
-- >>> f = Fold.take 2 Fold.sum
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.unfold Unfold.fromList []
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList []
|
||||
-- [0]
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.unfold Unfold.fromList [1..9]
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList [1..9]
|
||||
-- [3,7,11,15,9]
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.unfold Unfold.fromList [1..10]
|
||||
-- >>> Stream.fold Fold.toList $ Stream.foldManyPost f $ Stream.fromList [1..10]
|
||||
-- [3,7,11,15,19,0]
|
||||
--
|
||||
-- /Pre-release/
|
||||
@ -468,8 +486,8 @@ zipWithM f m1 m2 = fromStreamD $ D.zipWithM f (toStreamD m1) (toStreamD m2)
|
||||
-- If stream @a@ or stream @b@ ends, the zipped stream ends. If stream @b@ ends
|
||||
-- first, the element @a@ from previous evaluation of stream @a@ is discarded.
|
||||
--
|
||||
-- >>> s1 = Stream.unfold Unfold.fromList [1,2,3]
|
||||
-- >>> s2 = Stream.unfold Unfold.fromList [4,5,6]
|
||||
-- >>> s1 = Stream.fromList [1,2,3]
|
||||
-- >>> s2 = Stream.fromList [4,5,6]
|
||||
-- >>> Stream.fold Fold.toList $ Stream.zipWith (+) s1 s2
|
||||
-- [5,7,9]
|
||||
--
|
||||
|
580
core/src/Streamly/Internal/Data/Stream/Enumerate.hs
Normal file
580
core/src/Streamly/Internal/Data/Stream/Enumerate.hs
Normal file
@ -0,0 +1,580 @@
|
||||
-- |
|
||||
-- Module : Streamly.Internal.Data.Stream.Enumerate
|
||||
-- Copyright : (c) 2018 Composewell Technologies
|
||||
--
|
||||
-- License : BSD3
|
||||
-- Maintainer : streamly@composewell.com
|
||||
-- Stability : experimental
|
||||
-- Portability : GHC
|
||||
--
|
||||
-- The functions defined in this module should be rarely needed for direct use,
|
||||
-- try to use the operations from the 'Enumerable' type class
|
||||
-- instances instead.
|
||||
--
|
||||
-- This module provides an 'Enumerable' type class to enumerate 'Enum' types
|
||||
-- into a stream. The operations in this type class correspond to similar
|
||||
-- perations in the 'Enum' type class, the only difference is that they produce
|
||||
-- a stream instead of a list. These operations cannot be defined generically
|
||||
-- based on the 'Enum' type class. We provide instances for commonly used
|
||||
-- types. If instances for other types are needed convenience functions defined
|
||||
-- in this module can be used to define them. Alternatively, these functions
|
||||
-- can be used directly.
|
||||
|
||||
-- XXX The Unfold.Enumeration module is more modular, check the differences and
|
||||
-- reconcile the two.
|
||||
|
||||
module Streamly.Internal.Data.Stream.Enumerate
|
||||
(
|
||||
Enumerable (..)
|
||||
|
||||
-- ** Enumerating 'Bounded' 'Enum' Types
|
||||
, enumerate
|
||||
, enumerateTo
|
||||
, enumerateFromBounded
|
||||
|
||||
-- ** Enumerating 'Enum' Types not larger than 'Int'
|
||||
, enumerateFromToSmall
|
||||
, enumerateFromThenToSmall
|
||||
, enumerateFromThenSmallBounded
|
||||
|
||||
-- ** Enumerating 'Bounded' 'Integral' Types
|
||||
, enumerateFromIntegral
|
||||
, enumerateFromThenIntegral
|
||||
|
||||
-- ** Enumerating 'Integral' Types
|
||||
, enumerateFromToIntegral
|
||||
, enumerateFromThenToIntegral
|
||||
|
||||
-- ** Enumerating unbounded 'Integral' Types
|
||||
, enumerateFromStepIntegral
|
||||
|
||||
-- ** Enumerating 'Fractional' Types
|
||||
, enumerateFromFractional
|
||||
, enumerateFromToFractional
|
||||
, enumerateFromThenFractional
|
||||
, enumerateFromThenToFractional
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Fixed
|
||||
import Data.Int
|
||||
import Data.Ratio
|
||||
import Data.Word
|
||||
import Numeric.Natural
|
||||
import Data.Functor.Identity (Identity(..))
|
||||
|
||||
import Streamly.Internal.Data.Stream.Type (Stream, fromStreamD)
|
||||
|
||||
import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
|
||||
|
||||
-- $setup
|
||||
-- >>> import Streamly.Data.Fold as Fold
|
||||
-- >>> import Streamly.Internal.Data.Stream as Stream
|
||||
-- >>> import Streamly.Internal.Data.Stream.Enumerate as Stream
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Enumeration of Integral types
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- | @enumerateFromStepIntegral from step@ generates an infinite stream whose
|
||||
-- first element is @from@ and the successive elements are in increments of
|
||||
-- @step@.
|
||||
--
|
||||
-- CAUTION: This function is not safe for finite integral types. It does not
|
||||
-- check for overflow, underflow or bounds.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromStepIntegral 0 2
|
||||
-- [0,2,4,6]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 3 $ Stream.enumerateFromStepIntegral 0 (-2)
|
||||
-- [0,-2,-4]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromStepIntegral #-}
|
||||
enumerateFromStepIntegral
|
||||
:: (Monad m, Integral a)
|
||||
=> a -> a -> Stream m a
|
||||
enumerateFromStepIntegral from stride =
|
||||
fromStreamD $ D.enumerateFromStepIntegral from stride
|
||||
|
||||
-- | Enumerate an 'Integral' type. @enumerateFromIntegral from@ generates a
|
||||
-- stream whose first element is @from@ and the successive elements are in
|
||||
-- increments of @1@. The stream is bounded by the size of the 'Integral' type.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromIntegral (0 :: Int)
|
||||
-- [0,1,2,3]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromIntegral #-}
|
||||
enumerateFromIntegral
|
||||
:: (Monad m, Integral a, Bounded a)
|
||||
=> a -> Stream m a
|
||||
enumerateFromIntegral from = fromStreamD $ D.enumerateFromIntegral from
|
||||
|
||||
-- | Enumerate an 'Integral' type in steps. @enumerateFromThenIntegral from
|
||||
-- then@ generates a stream whose first element is @from@, the second element
|
||||
-- is @then@ and the successive elements are in increments of @then - from@.
|
||||
-- The stream is bounded by the size of the 'Integral' type.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) 2
|
||||
-- [0,2,4,6]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenIntegral (0 :: Int) (-2)
|
||||
-- [0,-2,-4,-6]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenIntegral #-}
|
||||
enumerateFromThenIntegral
|
||||
:: (Monad m, Integral a, Bounded a)
|
||||
=> a -> a -> Stream m a
|
||||
enumerateFromThenIntegral from next =
|
||||
fromStreamD $ D.enumerateFromThenIntegral from next
|
||||
|
||||
-- | Enumerate an 'Integral' type up to a given limit.
|
||||
-- @enumerateFromToIntegral from to@ generates a finite stream whose first
|
||||
-- element is @from@ and successive elements are in increments of @1@ up to
|
||||
-- @to@.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToIntegral 0 4
|
||||
-- [0,1,2,3,4]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromToIntegral #-}
|
||||
enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
|
||||
enumerateFromToIntegral from to =
|
||||
fromStreamD $ D.enumerateFromToIntegral from to
|
||||
|
||||
-- | Enumerate an 'Integral' type in steps up to a given limit.
|
||||
-- @enumerateFromThenToIntegral from then to@ generates a finite stream whose
|
||||
-- first element is @from@, the second element is @then@ and the successive
|
||||
-- elements are in increments of @then - from@ up to @to@.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToIntegral 0 2 6
|
||||
-- [0,2,4,6]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToIntegral 0 (-2) (-6)
|
||||
-- [0,-2,-4,-6]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenToIntegral #-}
|
||||
enumerateFromThenToIntegral
|
||||
:: (Monad m, Integral a)
|
||||
=> a -> a -> a -> Stream m a
|
||||
enumerateFromThenToIntegral from next to =
|
||||
fromStreamD $ D.enumerateFromThenToIntegral from next to
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Enumeration of Fractional types
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Even though the underlying implementation of enumerateFromFractional and
|
||||
-- enumerateFromThenFractional works for any 'Num' we have restricted these to
|
||||
-- 'Fractional' because these do not perform any bounds check, in contrast to
|
||||
-- integral versions and are therefore not equivalent substitutes for those.
|
||||
--
|
||||
-- | Numerically stable enumeration from a 'Fractional' number in steps of size
|
||||
-- @1@. @enumerateFromFractional from@ generates a stream whose first element
|
||||
-- is @from@ and the successive elements are in increments of @1@. No overflow
|
||||
-- or underflow checks are performed.
|
||||
--
|
||||
-- This is the equivalent to 'enumFrom' for 'Fractional' types. For example:
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromFractional 1.1
|
||||
-- [1.1,2.1,3.1,4.1]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromFractional #-}
|
||||
enumerateFromFractional :: (Monad m, Fractional a) => a -> Stream m a
|
||||
enumerateFromFractional from = fromStreamD $ D.enumerateFromNum from
|
||||
|
||||
-- | Numerically stable enumeration from a 'Fractional' number in steps.
|
||||
-- @enumerateFromThenFractional from then@ generates a stream whose first
|
||||
-- element is @from@, the second element is @then@ and the successive elements
|
||||
-- are in increments of @then - from@. No overflow or underflow checks are
|
||||
-- performed.
|
||||
--
|
||||
-- This is the equivalent of 'enumFromThen' for 'Fractional' types. For
|
||||
-- example:
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 2.1
|
||||
-- [1.1,2.1,3.1,4.1]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThenFractional 1.1 (-2.1)
|
||||
-- [1.1,-2.1,-5.300000000000001,-8.500000000000002]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenFractional #-}
|
||||
enumerateFromThenFractional
|
||||
:: (Monad m, Fractional a)
|
||||
=> a -> a -> Stream m a
|
||||
enumerateFromThenFractional from next = fromStreamD $ D.enumerateFromThenNum from next
|
||||
|
||||
-- | Numerically stable enumeration from a 'Fractional' number to a given
|
||||
-- limit. @enumerateFromToFractional from to@ generates a finite stream whose
|
||||
-- first element is @from@ and successive elements are in increments of @1@ up
|
||||
-- to @to@.
|
||||
--
|
||||
-- This is the equivalent of 'enumFromTo' for 'Fractional' types. For
|
||||
-- example:
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToFractional 1.1 4
|
||||
-- [1.1,2.1,3.1,4.1]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromToFractional 1.1 4.6
|
||||
-- [1.1,2.1,3.1,4.1,5.1]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- Notice that the last element is equal to the specified @to@ value after
|
||||
-- rounding to the nearest integer.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromToFractional #-}
|
||||
enumerateFromToFractional
|
||||
:: (Monad m, Fractional a, Ord a)
|
||||
=> a -> a -> Stream m a
|
||||
enumerateFromToFractional from to =
|
||||
fromStreamD $ D.enumerateFromToFractional from to
|
||||
|
||||
-- | Numerically stable enumeration from a 'Fractional' number in steps up to a
|
||||
-- given limit. @enumerateFromThenToFractional from then to@ generates a
|
||||
-- finite stream whose first element is @from@, the second element is @then@
|
||||
-- and the successive elements are in increments of @then - from@ up to @to@.
|
||||
--
|
||||
-- This is the equivalent of 'enumFromThenTo' for 'Fractional' types. For
|
||||
-- example:
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToFractional 0.1 2 6
|
||||
-- [0.1,2.0,3.9,5.799999999999999]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenToFractional 0.1 (-2) (-6)
|
||||
-- [0.1,-2.0,-4.1000000000000005,-6.200000000000001]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenToFractional #-}
|
||||
enumerateFromThenToFractional
|
||||
:: (Monad m, Fractional a, Ord a)
|
||||
=> a -> a -> a -> Stream m a
|
||||
enumerateFromThenToFractional from next to =
|
||||
fromStreamD $ D.enumerateFromThenToFractional from next to
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Enumeration of Enum types not larger than Int
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- | 'enumerateFromTo' for 'Enum' types not larger than 'Int'.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromToSmall #-}
|
||||
enumerateFromToSmall :: (Monad m, Enum a) => a -> a -> Stream m a
|
||||
enumerateFromToSmall from to =
|
||||
fmap toEnum
|
||||
$ enumerateFromToIntegral (fromEnum from) (fromEnum to)
|
||||
|
||||
-- | 'enumerateFromThenTo' for 'Enum' types not larger than 'Int'.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenToSmall #-}
|
||||
enumerateFromThenToSmall :: (Monad m, Enum a)
|
||||
=> a -> a -> a -> Stream m a
|
||||
enumerateFromThenToSmall from next to =
|
||||
fmap toEnum
|
||||
$ enumerateFromThenToIntegral
|
||||
(fromEnum from) (fromEnum next) (fromEnum to)
|
||||
|
||||
-- | 'enumerateFromThen' for 'Enum' types not larger than 'Int'.
|
||||
--
|
||||
-- Note: We convert the 'Enum' to 'Int' and enumerate the 'Int'. If a
|
||||
-- type is bounded but does not have a 'Bounded' instance then we can go on
|
||||
-- enumerating it beyond the legal values of the type, resulting in the failure
|
||||
-- of 'toEnum' when converting back to 'Enum'. Therefore we require a 'Bounded'
|
||||
-- instance for this function to be safely used.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromThenSmallBounded #-}
|
||||
enumerateFromThenSmallBounded :: (Monad m, Enumerable a, Bounded a)
|
||||
=> a -> a -> Stream m a
|
||||
enumerateFromThenSmallBounded from next =
|
||||
if fromEnum next >= fromEnum from
|
||||
then enumerateFromThenTo from next maxBound
|
||||
else enumerateFromThenTo from next minBound
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Enumerable type class
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- NOTE: We would like to rewrite calls to fromList [1..] etc. to stream
|
||||
-- enumerations like this:
|
||||
--
|
||||
-- {-# RULES "fromList enumFrom" [1]
|
||||
-- forall (a :: Int). D.fromList (enumFrom a) = D.enumerateFromIntegral a #-}
|
||||
--
|
||||
-- But this does not work because enumFrom is a class method and GHC rewrites
|
||||
-- it quickly, so we do not get a chance to have our rule fired.
|
||||
|
||||
-- | Types that can be enumerated as a stream. The operations in this type
|
||||
-- class are equivalent to those in the 'Enum' type class, except that these
|
||||
-- generate a stream instead of a list. Use the functions in
|
||||
-- "Streamly.Internal.Data.Stream.Enumeration" module to define new instances.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
class Enum a => Enumerable a where
|
||||
-- | @enumerateFrom from@ generates a stream starting with the element
|
||||
-- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
|
||||
-- generating an infinite stream when the type is not 'Bounded'.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFrom (0 :: Int)
|
||||
-- [0,1,2,3]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- For 'Fractional' types, enumeration is numerically stable. However, no
|
||||
-- overflow or underflow checks are performed.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFrom 1.1
|
||||
-- [1.1,2.1,3.1,4.1]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
enumerateFrom :: (Monad m) => a -> Stream m a
|
||||
|
||||
-- | Generate a finite stream starting with the element @from@, enumerating
|
||||
-- the type up to the value @to@. If @to@ is smaller than @from@ then an
|
||||
-- empty stream is returned.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 0 4
|
||||
-- [0,1,2,3,4]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- For 'Fractional' types, the last element is equal to the specified @to@
|
||||
-- value after rounding to the nearest integral value.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 1.1 4
|
||||
-- [1.1,2.1,3.1,4.1]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromTo 1.1 4.6
|
||||
-- [1.1,2.1,3.1,4.1,5.1]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
enumerateFromTo :: (Monad m) => a -> a -> Stream m a
|
||||
|
||||
-- | @enumerateFromThen from then@ generates a stream whose first element
|
||||
-- is @from@, the second element is @then@ and the successive elements are
|
||||
-- in increments of @then - from@. Enumeration can occur downwards or
|
||||
-- upwards depending on whether @then@ comes before or after @from@. For
|
||||
-- 'Bounded' types the stream ends when 'maxBound' is reached, for
|
||||
-- unbounded types it keeps enumerating infinitely.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 2
|
||||
-- [0,2,4,6]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 4 $ Stream.enumerateFromThen 0 (-2)
|
||||
-- [0,-2,-4,-6]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
enumerateFromThen :: (Monad m) => a -> a -> Stream m a
|
||||
|
||||
-- | @enumerateFromThenTo from then to@ generates a finite stream whose
|
||||
-- first element is @from@, the second element is @then@ and the successive
|
||||
-- elements are in increments of @then - from@ up to @to@. Enumeration can
|
||||
-- occur downwards or upwards depending on whether @then@ comes before or
|
||||
-- after @from@.
|
||||
--
|
||||
-- @
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenTo 0 2 6
|
||||
-- [0,2,4,6]
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.enumerateFromThenTo 0 (-2) (-6)
|
||||
-- [0,-2,-4,-6]
|
||||
--
|
||||
-- @
|
||||
--
|
||||
-- @since 0.6.0
|
||||
enumerateFromThenTo :: (Monad m) => a -> a -> a -> Stream m a
|
||||
|
||||
-- MAYBE: Sometimes it is more convenient to know the count rather then the
|
||||
-- ending or starting element. For those cases we can define the folllowing
|
||||
-- APIs. All of these will work only for bounded types if we represent the
|
||||
-- count by Int.
|
||||
--
|
||||
-- enumerateN
|
||||
-- enumerateFromN
|
||||
-- enumerateToN
|
||||
-- enumerateFromStep
|
||||
-- enumerateFromStepN
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Convenient functions for bounded types
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- |
|
||||
-- > enumerate = enumerateFrom minBound
|
||||
--
|
||||
-- Enumerate a 'Bounded' type from its 'minBound' to 'maxBound'
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerate #-}
|
||||
enumerate :: (Monad m, Bounded a, Enumerable a) => Stream m a
|
||||
enumerate = enumerateFrom minBound
|
||||
|
||||
-- |
|
||||
-- > enumerateTo = enumerateFromTo minBound
|
||||
--
|
||||
-- Enumerate a 'Bounded' type from its 'minBound' to specified value.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateTo #-}
|
||||
enumerateTo :: (Monad m, Bounded a, Enumerable a) => a -> Stream m a
|
||||
enumerateTo = enumerateFromTo minBound
|
||||
|
||||
-- |
|
||||
-- > enumerateFromBounded = enumerateFromTo from maxBound
|
||||
--
|
||||
-- 'enumerateFrom' for 'Bounded' 'Enum' types.
|
||||
--
|
||||
-- @since 0.6.0
|
||||
{-# INLINE enumerateFromBounded #-}
|
||||
enumerateFromBounded :: (Monad m, Enumerable a, Bounded a)
|
||||
=> a -> Stream m a
|
||||
enumerateFromBounded from = enumerateFromTo from maxBound
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Enumerable Instances
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- For Enum types smaller than or equal to Int size.
|
||||
#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
|
||||
instance Enumerable SMALL_TYPE where { \
|
||||
{-# INLINE enumerateFrom #-}; \
|
||||
enumerateFrom = enumerateFromBounded; \
|
||||
{-# INLINE enumerateFromThen #-}; \
|
||||
enumerateFromThen = enumerateFromThenSmallBounded; \
|
||||
{-# INLINE enumerateFromTo #-}; \
|
||||
enumerateFromTo = enumerateFromToSmall; \
|
||||
{-# INLINE enumerateFromThenTo #-}; \
|
||||
enumerateFromThenTo = enumerateFromThenToSmall }
|
||||
|
||||
|
||||
ENUMERABLE_BOUNDED_SMALL(())
|
||||
ENUMERABLE_BOUNDED_SMALL(Bool)
|
||||
ENUMERABLE_BOUNDED_SMALL(Ordering)
|
||||
ENUMERABLE_BOUNDED_SMALL(Char)
|
||||
|
||||
-- For bounded Integral Enum types, may be larger than Int.
|
||||
#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
|
||||
instance Enumerable INTEGRAL_TYPE where { \
|
||||
{-# INLINE enumerateFrom #-}; \
|
||||
enumerateFrom = enumerateFromIntegral; \
|
||||
{-# INLINE enumerateFromThen #-}; \
|
||||
enumerateFromThen = enumerateFromThenIntegral; \
|
||||
{-# INLINE enumerateFromTo #-}; \
|
||||
enumerateFromTo = enumerateFromToIntegral; \
|
||||
{-# INLINE enumerateFromThenTo #-}; \
|
||||
enumerateFromThenTo = enumerateFromThenToIntegral }
|
||||
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Int)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Int8)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Int16)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Int32)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Int64)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Word)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Word8)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Word16)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Word32)
|
||||
ENUMERABLE_BOUNDED_INTEGRAL(Word64)
|
||||
|
||||
-- For unbounded Integral Enum types.
|
||||
#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
|
||||
instance Enumerable INTEGRAL_TYPE where { \
|
||||
{-# INLINE enumerateFrom #-}; \
|
||||
enumerateFrom from = enumerateFromStepIntegral from 1; \
|
||||
{-# INLINE enumerateFromThen #-}; \
|
||||
enumerateFromThen from next = \
|
||||
enumerateFromStepIntegral from (next - from); \
|
||||
{-# INLINE enumerateFromTo #-}; \
|
||||
enumerateFromTo = enumerateFromToIntegral; \
|
||||
{-# INLINE enumerateFromThenTo #-}; \
|
||||
enumerateFromThenTo = enumerateFromThenToIntegral }
|
||||
|
||||
ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
|
||||
ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
|
||||
|
||||
#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
|
||||
instance (CONSTRAINT) => Enumerable FRACTIONAL_TYPE where { \
|
||||
{-# INLINE enumerateFrom #-}; \
|
||||
enumerateFrom = enumerateFromFractional; \
|
||||
{-# INLINE enumerateFromThen #-}; \
|
||||
enumerateFromThen = enumerateFromThenFractional; \
|
||||
{-# INLINE enumerateFromTo #-}; \
|
||||
enumerateFromTo = enumerateFromToFractional; \
|
||||
{-# INLINE enumerateFromThenTo #-}; \
|
||||
enumerateFromThenTo = enumerateFromThenToFractional }
|
||||
|
||||
ENUMERABLE_FRACTIONAL(Float,)
|
||||
ENUMERABLE_FRACTIONAL(Double,)
|
||||
ENUMERABLE_FRACTIONAL((Fixed a),HasResolution a)
|
||||
ENUMERABLE_FRACTIONAL((Ratio a),Integral a)
|
||||
|
||||
instance Enumerable a => Enumerable (Identity a) where
|
||||
{-# INLINE enumerateFrom #-}
|
||||
enumerateFrom (Identity from) =
|
||||
fmap Identity $ enumerateFrom from
|
||||
{-# INLINE enumerateFromThen #-}
|
||||
enumerateFromThen (Identity from) (Identity next) =
|
||||
fmap Identity $ enumerateFromThen from next
|
||||
{-# INLINE enumerateFromTo #-}
|
||||
enumerateFromTo (Identity from) (Identity to) =
|
||||
fmap Identity $ enumerateFromTo from to
|
||||
{-# INLINE enumerateFromThenTo #-}
|
||||
enumerateFromThenTo (Identity from) (Identity next) (Identity to) =
|
||||
fmap Identity
|
||||
$ enumerateFromThenTo from next to
|
||||
|
||||
-- TODO
|
||||
{-
|
||||
instance Enumerable a => Enumerable (Last a)
|
||||
instance Enumerable a => Enumerable (First a)
|
||||
instance Enumerable a => Enumerable (Max a)
|
||||
instance Enumerable a => Enumerable (Min a)
|
||||
instance Enumerable a => Enumerable (Const a b)
|
||||
instance Enumerable (f a) => Enumerable (Alt f a)
|
||||
instance Enumerable (f a) => Enumerable (Ap f a)
|
||||
-}
|
@ -1,3 +1,5 @@
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
-- |
|
||||
-- Module : Streamly.Internal.Data.Stream.Generate
|
||||
-- Copyright : (c) 2017 Composewell Technologies
|
||||
@ -6,6 +8,15 @@
|
||||
-- Stability : experimental
|
||||
-- Portability : GHC
|
||||
--
|
||||
-- Some idioms:
|
||||
--
|
||||
-- >>> fromEffect = Stream.sequence . Stream.fromPure
|
||||
-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
|
||||
-- >>> repeatM = Stream.sequence . Stream.repeat
|
||||
-- >>> replicateM n = Stream.sequence . Stream.replicate n
|
||||
-- >>> fromListM = Stream.sequence . Stream.fromList
|
||||
-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
|
||||
--
|
||||
module Streamly.Internal.Data.Stream.Generate
|
||||
(
|
||||
-- * Primitives
|
||||
@ -17,51 +28,79 @@ module Streamly.Internal.Data.Stream.Generate
|
||||
-- * From 'Unfold'
|
||||
, unfold
|
||||
|
||||
-- * Unfolding
|
||||
, unfoldr
|
||||
, unfoldrM
|
||||
|
||||
-- * From Values
|
||||
, Stream.fromPure
|
||||
, Stream.fromEffect
|
||||
, repeat
|
||||
, replicate
|
||||
|
||||
-- * Enumeration
|
||||
, Enumerable (..)
|
||||
, enumerate
|
||||
, enumerateTo
|
||||
|
||||
-- * Time Enumeration
|
||||
, times
|
||||
, timesWith
|
||||
, absTimes
|
||||
, absTimesWith
|
||||
, relTimes
|
||||
, relTimesWith
|
||||
, durations
|
||||
, timeout
|
||||
|
||||
-- * Iteration
|
||||
, iterate
|
||||
, iterateM
|
||||
|
||||
-- * Cyclic Elements
|
||||
, mfix
|
||||
|
||||
-- * From Containers
|
||||
, Bottom.fromList
|
||||
, fromFoldable
|
||||
, fromFoldableM
|
||||
|
||||
-- * From memory
|
||||
, fromPtr
|
||||
, fromPtrN
|
||||
, fromByteStr#
|
||||
-- , fromByteArray#
|
||||
, fromUnboxedIORef
|
||||
)
|
||||
where
|
||||
|
||||
#include "inline.hs"
|
||||
|
||||
import Control.Monad.IO.Class (MonadIO)
|
||||
import Data.Word (Word8)
|
||||
import Foreign.Storable (Storable)
|
||||
import GHC.Exts (Addr#, Ptr (Ptr))
|
||||
import Streamly.Internal.Data.Stream.Bottom
|
||||
(absTimesWith, relTimesWith, timesWith)
|
||||
import Streamly.Internal.Data.Stream.Type (Stream, fromStreamK, toStreamK)
|
||||
import Streamly.Internal.Data.Stream.Enumerate
|
||||
(Enumerable(..), enumerate, enumerateTo)
|
||||
import Streamly.Internal.Data.Stream.Type
|
||||
(Stream, fromStreamD, fromStreamK, toStreamK)
|
||||
import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
|
||||
import Streamly.Internal.Data.Unboxed (Unboxed)
|
||||
import Streamly.Internal.Data.Unfold.Type (Unfold)
|
||||
|
||||
import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
|
||||
import qualified Streamly.Internal.Data.Stream.Bottom as Bottom
|
||||
import qualified Streamly.Internal.Data.Stream.StreamD as D
|
||||
import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
|
||||
import qualified Streamly.Internal.Data.Stream.Type as Stream
|
||||
|
||||
import Prelude hiding (iterate, replicate, repeat)
|
||||
|
||||
-- $setup
|
||||
-- >>> :m
|
||||
-- >>> import Control.Concurrent (threadDelay)
|
||||
-- >>> import Data.Function (fix)
|
||||
-- >>> import Prelude hiding (take)
|
||||
-- >>> import Data.Function ((&))
|
||||
-- >>> import qualified Streamly.Data.Fold as Fold
|
||||
-- >>> import qualified Streamly.Data.Unfold as Unfold
|
||||
-- >>> import qualified Streamly.Internal.Data.Stream as Stream
|
||||
@ -84,6 +123,77 @@ import qualified Streamly.Internal.Data.Stream.Type as Stream
|
||||
unfold :: Monad m => Unfold m a b -> a -> Stream m b
|
||||
unfold unf = Stream.fromStreamD . D.unfold unf
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Generation by Unfolding
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- |
|
||||
-- >>> :{
|
||||
-- unfoldr step s =
|
||||
-- case step s of
|
||||
-- Nothing -> Stream.nil
|
||||
-- Just (a, b) -> a `Stream.cons` unfoldr step b
|
||||
-- :}
|
||||
--
|
||||
-- Build a stream by unfolding a /pure/ step function @step@ starting from a
|
||||
-- seed @s@. The step function returns the next element in the stream and the
|
||||
-- next seed value. When it is done it returns 'Nothing' and the stream ends.
|
||||
-- For example,
|
||||
--
|
||||
-- >>> :{
|
||||
-- let f b =
|
||||
-- if b > 2
|
||||
-- then Nothing
|
||||
-- else Just (b, b + 1)
|
||||
-- in Stream.fold Fold.toList $ Stream.unfoldr f 0
|
||||
-- :}
|
||||
-- [0,1,2]
|
||||
--
|
||||
{-# INLINE_EARLY unfoldr #-}
|
||||
unfoldr :: Monad m => (b -> Maybe (a, b)) -> b -> Stream m a
|
||||
unfoldr step seed = fromStreamD (D.unfoldr step seed)
|
||||
{-# RULES "unfoldr fallback to StreamK" [1]
|
||||
forall a b. D.toStreamK (D.unfoldr a b) = K.unfoldr a b #-}
|
||||
|
||||
-- | Build a stream by unfolding a /monadic/ step function starting from a
|
||||
-- seed. The step function returns the next element in the stream and the next
|
||||
-- seed value. When it is done it returns 'Nothing' and the stream ends. For
|
||||
-- example,
|
||||
--
|
||||
-- >>> :{
|
||||
-- let f b =
|
||||
-- if b > 2
|
||||
-- then return Nothing
|
||||
-- else return (Just (b, b + 1))
|
||||
-- in Stream.fold Fold.toList $ Stream.unfoldrM f 0
|
||||
-- :}
|
||||
-- [0,1,2]
|
||||
--
|
||||
--
|
||||
{-# INLINE unfoldrM #-}
|
||||
unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
|
||||
unfoldrM step = fromStreamD . D.unfoldrM step
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- From Values
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- |
|
||||
-- Generate an infinite stream by repeating a pure value.
|
||||
--
|
||||
{-# INLINE_NORMAL repeat #-}
|
||||
repeat :: Monad m => a -> Stream m a
|
||||
repeat = fromStreamD . D.repeat
|
||||
|
||||
-- |
|
||||
-- >>> replicate n = Stream.take n . Stream.repeat
|
||||
--
|
||||
-- Generate a stream of length @n@ by repeating a value @n@ times.
|
||||
--
|
||||
{-# INLINE_NORMAL replicate #-}
|
||||
replicate :: Monad m => Int -> a -> Stream m a
|
||||
replicate n = fromStreamD . D.replicate n
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Time Enumeration
|
||||
------------------------------------------------------------------------------
|
||||
@ -93,7 +203,8 @@ unfold unf = Stream.fromStreamD . D.unfold unf
|
||||
-- (epoch) denoting the start of the stream and the second component is a time
|
||||
-- relative to the reference.
|
||||
--
|
||||
-- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.times
|
||||
-- >>> f = Fold.drainBy (\x -> print x >> threadDelay 1000000)
|
||||
-- >>> Stream.fold f $ Stream.take 3 $ Stream.times
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
|
||||
@ -109,7 +220,8 @@ times = timesWith 0.01
|
||||
-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
|
||||
-- granularity.
|
||||
--
|
||||
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
|
||||
-- >>> f = Fold.drainBy print
|
||||
-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
-- AbsTime (TimeSpec {sec = ..., nsec = ...})
|
||||
@ -125,7 +237,8 @@ absTimes = fmap (uncurry addToAbsTime64) times
|
||||
-- | @relTimes@ returns a stream of relative time values starting from 0,
|
||||
-- using a clock of granularity 10 ms.
|
||||
--
|
||||
-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
|
||||
-- >>> f = Fold.drainBy print
|
||||
-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
-- RelTime64 (NanoSecond64 ...)
|
||||
@ -138,6 +251,72 @@ absTimes = fmap (uncurry addToAbsTime64) times
|
||||
relTimes :: MonadIO m => Stream m RelTime64
|
||||
relTimes = fmap snd times
|
||||
|
||||
-- | @durations g@ returns a stream of relative time values measuring the time
|
||||
-- elapsed since the immediate predecessor element of the stream was generated.
|
||||
-- The first element of the stream is always 0. @durations@ uses a clock of
|
||||
-- granularity @g@ specified in seconds. A low granularity clock is more
|
||||
-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
|
||||
-- Durations lower than 1 ms will be 0.
|
||||
--
|
||||
-- Note: This API is not safe on 32-bit machines.
|
||||
--
|
||||
-- /Unimplemented/
|
||||
--
|
||||
{-# INLINE durations #-}
|
||||
durations :: -- Monad m =>
|
||||
Double -> t m RelTime64
|
||||
durations = undefined
|
||||
|
||||
-- | Generate a singleton event at or after the specified absolute time. Note
|
||||
-- that this is different from a threadDelay, a threadDelay starts from the
|
||||
-- time when the action is evaluated, whereas if we use AbsTime based timeout
|
||||
-- it will immediately expire if the action is evaluated too late.
|
||||
--
|
||||
-- /Unimplemented/
|
||||
--
|
||||
{-# INLINE timeout #-}
|
||||
timeout :: -- Monad m =>
|
||||
AbsTime -> t m ()
|
||||
timeout = undefined
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Iterating functions
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- |
|
||||
-- >>> iterate f x = x `Stream.cons` iterate f x
|
||||
--
|
||||
-- Generate an infinite stream with @x@ as the first element and each
|
||||
-- successive element derived by applying the function @f@ on the previous
|
||||
-- element.
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.take 5 $ Stream.iterate (+1) 1
|
||||
-- [1,2,3,4,5]
|
||||
--
|
||||
{-# INLINE_NORMAL iterate #-}
|
||||
iterate :: Monad m => (a -> a) -> a -> Stream m a
|
||||
iterate step = fromStreamD . D.iterate step
|
||||
|
||||
-- |
|
||||
-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
|
||||
--
|
||||
-- Generate an infinite stream with the first element generated by the action
|
||||
-- @m@ and each successive element derived by applying the monadic function
|
||||
-- @f@ on the previous element.
|
||||
--
|
||||
-- >>> :{
|
||||
-- Stream.iterateM (\x -> print x >> return (x + 1)) (return 0)
|
||||
-- & Stream.take 3
|
||||
-- & Stream.fold Fold.toList
|
||||
-- :}
|
||||
-- 0
|
||||
-- 1
|
||||
-- [0,1,2]
|
||||
--
|
||||
{-# INLINE iterateM #-}
|
||||
iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
|
||||
iterateM step = fromStreamD . D.iterateM step
|
||||
|
||||
-- | We can define cyclic structures using @let@:
|
||||
--
|
||||
-- >>> let (a, b) = ([1, b], head a) in (a, b)
|
||||
@ -176,8 +355,8 @@ relTimes = fmap snd times
|
||||
-- where
|
||||
-- f action = do
|
||||
-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
|
||||
-- x <- Stream.unfold Unfold.fromListM [incr 1 action, incr 2 action]
|
||||
-- y <- Stream.unfold Unfold.fromList [4,5]
|
||||
-- x <- Stream.sequence $ Stream.fromList [incr 1 action, incr 2 action]
|
||||
-- y <- Stream.fromList [4,5]
|
||||
-- return (x, y)
|
||||
-- :}
|
||||
--
|
||||
@ -206,18 +385,6 @@ mfix f = fromStreamK $ K.mfix (toStreamK . f)
|
||||
fromFoldable :: Foldable f => f a -> Stream m a
|
||||
fromFoldable = fromStreamK . K.fromFoldable
|
||||
|
||||
-- |
|
||||
-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil
|
||||
--
|
||||
-- Construct a stream from a 'Foldable' containing monadic actions.
|
||||
--
|
||||
-- >>> Stream.fold Fold.toList $ Stream.fromFoldableM $ map return [1,2,3]
|
||||
-- [1,2,3]
|
||||
--
|
||||
{-# INLINE fromFoldableM #-}
|
||||
fromFoldableM :: (Monad m, Foldable f) => f (m a) -> Stream m a
|
||||
fromFoldableM = Prelude.foldr Stream.consM Stream.nil
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- From pointers
|
||||
------------------------------------------------------------------------------
|
||||
@ -260,3 +427,10 @@ fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
|
||||
fromByteStr# addr =
|
||||
Stream.fromStreamD $ D.takeWhile (/= 0) $ D.fromPtr $ Ptr addr
|
||||
|
||||
-- | Construct a stream by reading an 'Unboxed' 'IORef' repeatedly.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
{-# INLINE fromUnboxedIORef #-}
|
||||
fromUnboxedIORef :: (MonadIO m, Unboxed a) => Unboxed.IORef a -> Stream m a
|
||||
fromUnboxedIORef = fromStreamD . Unboxed.toStreamD
|
||||
|
@ -94,7 +94,6 @@ where
|
||||
import Control.Monad.IO.Class (MonadIO(..))
|
||||
import Foreign.Ptr (Ptr, plusPtr)
|
||||
import Foreign.Storable (Storable (peek), sizeOf)
|
||||
import Streamly.Internal.Control.Concurrent (MonadAsync)
|
||||
import Streamly.Internal.Data.Time.Clock
|
||||
(Clock(Monotonic), asyncClock, readClock)
|
||||
import Streamly.Internal.Data.Time.Units
|
||||
@ -452,10 +451,9 @@ iterate step st = iterateM (return . step) (return st)
|
||||
-- From containers
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- XXX we need the MonadAsync constraint because of a rewrite rule.
|
||||
-- | Convert a list of monadic actions to a 'Stream'
|
||||
{-# INLINE_LATE fromListM #-}
|
||||
fromListM :: MonadAsync m => [m a] -> Stream m a
|
||||
fromListM :: Monad m => [m a] -> Stream m a
|
||||
#ifdef USE_UNFOLDS_EVERYWHERE
|
||||
fromListM = unfold Unfold.fromListM
|
||||
#else
|
||||
|
@ -294,6 +294,7 @@ fromPure = fromStreamK . K.fromPure
|
||||
-- | Create a singleton stream from a monadic action.
|
||||
--
|
||||
-- >>> fromEffect m = m `consM` Stream.nil
|
||||
-- >>> fromEffect = Stream.sequence . Stream.fromPure
|
||||
--
|
||||
-- >>> Stream.fold Fold.drain $ Stream.fromEffect (putStrLn "hello")
|
||||
-- hello
|
||||
|
@ -308,6 +308,7 @@ library
|
||||
, Streamly.Internal.Data.Pipe
|
||||
, Streamly.Internal.Data.Stream.Type
|
||||
, Streamly.Internal.Data.Stream.Eliminate
|
||||
, Streamly.Internal.Data.Stream.Enumerate
|
||||
, Streamly.Internal.Data.Stream.Generate
|
||||
, Streamly.Internal.Data.Stream.Transform
|
||||
, Streamly.Internal.Data.Stream.Bottom
|
||||
|
@ -190,6 +190,7 @@ extra-source-files:
|
||||
core/src/Streamly/Internal/Data/Stream.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Bottom.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Eliminate.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Enumerate.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Exception.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Expand.hs
|
||||
core/src/Streamly/Internal/Data/Stream/Generate.hs
|
||||
@ -601,6 +602,7 @@ library
|
||||
, Streamly.Internal.Data.Pipe
|
||||
, Streamly.Internal.Data.Stream.Type
|
||||
, Streamly.Internal.Data.Stream.Bottom
|
||||
, Streamly.Internal.Data.Stream.Enumerate
|
||||
, Streamly.Internal.Data.Stream.Generate
|
||||
, Streamly.Internal.Data.Stream.Eliminate
|
||||
, Streamly.Internal.Data.Stream.Expand
|
||||
|
Loading…
Reference in New Issue
Block a user