on 03218ad help sign in
572 lines 18 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3-- |
4-- Module : Streamly.Internal.Data.Stream.IsStream.Generate
5-- Copyright : (c) 2017 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
9-- Portability : GHC
10--
11-- Most of the combinators in this module can be implemented as unfolds. Some
12-- of them however can only be expressed in terms StreamK e.g. cons/consM,
13-- fromFoldable, mfix. We can possibly remove those from this module which can
14-- be expressed as unfolds. Unless we want to use rewrite rules to rewrite them
15-- as StreamK when StreamK is used, avoiding conversion to StreamD. Will that
16-- help? Are there any other reasons to keep these and not use unfolds?
18module Streamly.Internal.Data.Stream.IsStream.Generate
19 (
20 -- * Primitives
21 K.nil
22 , K.nilM
23 , K.cons
24 , (K..:)
26 , consM
27 , (|:)
29 -- * From 'Unfold'
30 , unfold
31 , unfold0
33 -- * Unfolding
34 , unfoldr
35 , unfoldrM
37 -- * From Values
38 , fromPure
39 , fromEffect
40 , repeat
41 , repeatM
42 , replicate
43 , replicateM
45 -- * Enumeration
46 , Enumerable (..)
47 , enumerate
48 , enumerateTo
50 -- * Time Enumeration
51 , times
52 , absTimes
53 , absTimesWith
54 , relTimes
55 , relTimesWith
56 , durations
57 , ticks
58 , timeout
60 -- * From Generators
61 , fromIndices
62 , fromIndicesM
63 -- , generate
64 -- , generateM
66 -- * Iteration
67 , iterate
68 , iterateM
70 -- * Cyclic Elements
71 , K.mfix
73 -- * From Containers
74 , P.fromList
75 , fromListM
76 , K.fromFoldable
77 , fromFoldableM
78 , fromCallback
80 -- * Deprecated
81 , K.once
82 , yield
83 , yieldM
84 , each
85 , fromHandle
86 , currentTime
87 )
88where
90#include "inline.hs"
92import Control.Monad.IO.Class (MonadIO(..))
93import Data.Void (Void)
94import Streamly.Internal.Data.Unfold.Type (Unfold)
95import Streamly.Internal.Data.SVar (MonadAsync, Rate (..))
96import Streamly.Internal.Data.Stream.IsStream.Enumeration
97 (Enumerable(..), enumerate, enumerateTo)
98import Streamly.Internal.Data.Stream.IsStream.Common
99 ( absTimesWith, concatM, relTimesWith, timesWith, fromPure, fromEffect
100 , yield, yieldM, repeatM)
101import Streamly.Internal.Data.Stream.Prelude (fromStreamS)
102import Streamly.Internal.Data.Stream.StreamD (fromStreamD)
103import Streamly.Internal.Data.Stream.StreamK (IsStream((|:), consM))
104import Streamly.Internal.Data.Stream.Serial (SerialT, WSerialT)
105import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
106import Streamly.Internal.Data.Time.Units (AbsTime , RelTime64, addToAbsTime64)
108import qualified Streamly.Internal.Data.Stream.Parallel as Par
109import qualified Streamly.Internal.Data.Stream.Prelude as P
110import qualified Streamly.Internal.Data.Stream.Serial as Serial
111import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
112import qualified Streamly.Internal.Data.Stream.StreamK as K
113#ifdef USE_STREAMK_ONLY
114import qualified Streamly.Internal.Data.Stream.StreamK as S
115#else
116import qualified Streamly.Internal.Data.Stream.StreamD.Generate as S
117#endif
118import qualified System.IO as IO
120import Prelude hiding (iterate, replicate, repeat)
122-- $setup
123-- >>> :m
124-- >>> import Prelude hiding (iterate, replicate, repeat)
125-- >>> import qualified Streamly.Prelude as Stream
126-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
127-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
128-- >>> import Control.Concurrent (threadDelay)
130------------------------------------------------------------------------------
131-- From Unfold
132------------------------------------------------------------------------------
134-- | Convert an 'Unfold' into a stream by supplying it an input seed.
135--
136-- >>> Stream.drain $ Stream.unfold (Unfold.replicateM 3) (putStrLn "hello")
137-- hello
138-- hello
139-- hello
140--
141-- /Since: 0.7.0/
142{-# INLINE unfold #-}
143unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
144unfold unf x = fromStreamD $ D.unfold unf x
146-- | Convert an 'Unfold' with a closed input end into a stream.
147--
148-- /Pre-release/
149{-# INLINE unfold0 #-}
150unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
151unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
153------------------------------------------------------------------------------
154-- Generation by Unfolding
155------------------------------------------------------------------------------
157-- |
158-- @
159-- unfoldr step s =
160-- case step s of
161-- Nothing -> 'K.nil'
162-- Just (a, b) -> a \`cons` unfoldr step b
163-- @
164--
165-- Build a stream by unfolding a /pure/ step function @step@ starting from a
166-- seed @s@. The step function returns the next element in the stream and the
167-- next seed value. When it is done it returns 'Nothing' and the stream ends.
168-- For example,
169--
170-- @
171-- >>> :{
172-- let f b =
173-- if b > 3
174-- then Nothing
175-- else Just (b, b + 1)
176-- in Stream.toList $ Stream.unfoldr f 0
177-- :}
178-- [0,1,2,3]
179--
180-- @
181--
182-- @since 0.1.0
183{-# INLINE_EARLY unfoldr #-}
184unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
185unfoldr step seed = fromStreamS (S.unfoldr step seed)
186{-# RULES "unfoldr fallback to StreamK" [1]
187 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
189-- | Build a stream by unfolding a /monadic/ step function starting from a
190-- seed. The step function returns the next element in the stream and the next
191-- seed value. When it is done it returns 'Nothing' and the stream ends. For
192-- example,
193--
194-- @
195-- >>> :{
196-- let f b =
197-- if b > 3
198-- then return Nothing
199-- else return (Just (b, b + 1))
200-- in Stream.toList $ Stream.unfoldrM f 0
201-- :}
202-- [0,1,2,3]
203--
204-- @
205-- When run concurrently, the next unfold step can run concurrently with the
206-- processing of the output of the previous step. Note that more than one step
207-- cannot run concurrently as the next step depends on the output of the
208-- previous step.
209--
210-- @
211-- (fromAsync $ S.unfoldrM (\\n -> liftIO (threadDelay 1000000) >> return (Just (n, n + 1))) 0)
212-- & S.foldlM' (\\_ a -> threadDelay 1000000 >> print a) ()
213-- @
214--
215-- /Concurrent/
216--
217-- /Since: 0.1.0/
218{-# INLINE_EARLY unfoldrM #-}
219unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
220unfoldrM = K.unfoldrM
222{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
223{-# INLINE_EARLY unfoldrMSerial #-}
224unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
225unfoldrMSerial = Serial.unfoldrM
227{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
228{-# INLINE_EARLY unfoldrMWSerial #-}
229unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
230unfoldrMWSerial = Serial.unfoldrM
232{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
233{-# INLINE_EARLY unfoldrMZipSerial #-}
234unfoldrMZipSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
235unfoldrMZipSerial = Serial.unfoldrM
237------------------------------------------------------------------------------
238-- From Values
239------------------------------------------------------------------------------
241-- |
242-- Generate an infinite stream by repeating a pure value.
243--
244-- @since 0.4.0
245{-# INLINE_NORMAL repeat #-}
246repeat :: (IsStream t, Monad m) => a -> t m a
247repeat = fromStreamS . S.repeat
249-- |
250-- @
251-- replicate = take n . repeat
252-- @
253--
254-- Generate a stream of length @n@ by repeating a value @n@ times.
255--
256-- @since 0.6.0
257{-# INLINE_NORMAL replicate #-}
258replicate :: (IsStream t, Monad m) => Int -> a -> t m a
259replicate n = fromStreamS . S.replicate n
261-- |
262-- @
263-- replicateM = take n . repeatM
264-- @
265--
266-- Generate a stream by performing a monadic action @n@ times. Same as:
267--
268-- @
269-- drain $ fromSerial $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
270-- drain $ fromAsync $ S.replicateM 10 $ (threadDelay 1000000 >> print 1)
271-- @
272--
273-- /Concurrent/
274--
275-- @since 0.1.1
276{-# INLINE_EARLY replicateM #-}
277replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
278replicateM = K.replicateM
280{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
281{-# INLINE replicateMSerial #-}
282replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
283replicateMSerial n = fromStreamS . S.replicateM n
285------------------------------------------------------------------------------
286-- Time Enumeration
287------------------------------------------------------------------------------
289-- | @times@ returns a stream of time value tuples with clock of 10 ms
290-- granularity. The first component of the tuple is an absolute time reference
291-- (epoch) denoting the start of the stream and the second component is a time
292-- relative to the reference.
293--
294-- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.times
295-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
296-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
297-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
298--
299-- Note: This API is not safe on 32-bit machines.
300--
301-- /Pre-release/
302--
303{-# INLINE times #-}
304times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
305times = timesWith 0.01
307-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
308-- granularity.
309--
310-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
311-- AbsTime (TimeSpec {sec = ..., nsec = ...})
312-- AbsTime (TimeSpec {sec = ..., nsec = ...})
313-- AbsTime (TimeSpec {sec = ..., nsec = ...})
314--
315-- Note: This API is not safe on 32-bit machines.
316--
317-- /Pre-release/
318--
319{-# INLINE absTimes #-}
320absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
321absTimes = fmap (uncurry addToAbsTime64) times
323{-# DEPRECATED currentTime "Please use absTimes instead" #-}
324{-# INLINE currentTime #-}
325currentTime :: (IsStream t, MonadAsync m, Functor (t m))
326 => Double -> t m AbsTime
327currentTime = absTimesWith
329-- | @relTimes@ returns a stream of relative time values starting from 0,
330-- using a clock of granularity 10 ms.
331--
332-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
333-- RelTime64 (NanoSecond64 ...)
334-- RelTime64 (NanoSecond64 ...)
335-- RelTime64 (NanoSecond64 ...)
336--
337-- Note: This API is not safe on 32-bit machines.
338--
339-- /Pre-release/
340--
341{-# INLINE relTimes #-}
342relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
343relTimes = fmap snd times
345-- | @durations g@ returns a stream of relative time values measuring the time
346-- elapsed since the immediate predecessor element of the stream was generated.
347-- The first element of the stream is always 0. @durations@ uses a clock of
348-- granularity @g@ specified in seconds. A low granularity clock is more
349-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
350-- Durations lower than 1 ms will be 0.
351--
352-- Note: This API is not safe on 32-bit machines.
353--
354-- /Unimplemented/
355--
356{-# INLINE durations #-}
357durations :: -- (IsStream t, MonadAsync m) =>
358 Double -> t m RelTime64
359durations = undefined
361-- | Generate ticks at the specified rate. The rate is adaptive, the tick
362-- generation speed can be increased or decreased at different times to achieve
363-- the specified rate. The specific behavior for different styles of 'Rate'
364-- specifications is documented under 'Rate'. The effective maximum rate
365-- achieved by a stream is governed by the processor speed.
366--
367-- /Unimplemented/
368--
369{-# INLINE ticks #-}
370ticks :: -- (IsStream t, MonadAsync m) =>
371 Rate -> t m ()
372ticks = undefined
374-- | Generate a singleton event at or after the specified absolute time. Note
375-- that this is different from a threadDelay, a threadDelay starts from the
376-- time when the action is evaluated, whereas if we use AbsTime based timeout
377-- it will immediately expire if the action is evaluated too late.
378--
379-- /Unimplemented/
380--
381{-# INLINE timeout #-}
382timeout :: -- (IsStream t, MonadAsync m) =>
383 AbsTime -> t m ()
384timeout = undefined
386------------------------------------------------------------------------------
387-- From Generator functions
388------------------------------------------------------------------------------
390-- XXX we can remove it and recommend the definition in terms of enumerate and
391-- map. Check performance equivalence.
392--
393-- |
394-- @
395-- fromIndices f = fmap f $ Stream.enumerateFrom 0
396-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
397-- @
398--
399-- Generate an infinite stream, whose values are the output of a function @f@
400-- applied on the corresponding index. Index starts at 0.
401--
402-- >>> Stream.toList $ Stream.take 5 $ Stream.fromIndices id
403-- [0,1,2,3,4]
404--
405-- @since 0.6.0
406{-# INLINE fromIndices #-}
407fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
408fromIndices = fromStreamS . S.fromIndices
410--
411-- |
412-- @
413-- fromIndicesM f = Stream.mapM f $ Stream.enumerateFrom 0
414-- fromIndicesM f = let g i = f i \`consM` g (i + 1) in g 0
415-- @
416--
417-- Generate an infinite stream, whose values are the output of a monadic
418-- function @f@ applied on the corresponding index. Index starts at 0.
419--
420-- /Concurrent/
421--
422-- @since 0.6.0
423{-# INLINE_EARLY fromIndicesM #-}
424fromIndicesM :: (IsStream t, MonadAsync m) => (Int -> m a) -> t m a
425fromIndicesM = K.fromIndicesM
427{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
428{-# INLINE fromIndicesMSerial #-}
429fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
430fromIndicesMSerial = fromStreamS . S.fromIndicesM
432------------------------------------------------------------------------------
433-- Iterating functions
434------------------------------------------------------------------------------
436-- |
437-- @
438-- iterate f x = x \`cons` iterate f x
439-- @
440--
441-- Generate an infinite stream with @x@ as the first element and each
442-- successive element derived by applying the function @f@ on the previous
443-- element.
444--
445-- @
446-- >>> Stream.toList $ Stream.take 5 $ Stream.iterate (+1) 1
447-- [1,2,3,4,5]
448--
449-- @
450--
451-- @since 0.1.2
452{-# INLINE_NORMAL iterate #-}
453iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
454iterate step = fromStreamS . S.iterate step
456-- |
457-- @
458-- iterateM f m = m >>= \a -> return a \`consM` iterateM f (f a)
459-- @
460--
461-- Generate an infinite stream with the first element generated by the action
462-- @m@ and each successive element derived by applying the monadic function
463-- @f@ on the previous element.
464--
465-- When run concurrently, the next iteration can run concurrently with the
466-- processing of the previous iteration. Note that more than one iteration
467-- cannot run concurrently as the next iteration depends on the output of the
468-- previous iteration.
469--
470-- @
471-- drain $ fromSerial $ S.take 10 $ S.iterateM
472-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
473--
474-- drain $ fromAsync $ S.take 10 $ S.iterateM
475-- (\\x -> threadDelay 1000000 >> print x >> return (x + 1)) (return 0)
476-- @
477--
478-- /Concurrent/
479--
480-- /Since: 0.1.2/
481--
482-- /Since: 0.7.0 (signature change)/
483{-# INLINE_EARLY iterateM #-}
484iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> m a -> t m a
485iterateM = K.iterateM
487{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
488{-# INLINE iterateMSerial #-}
489iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
490iterateMSerial step = fromStreamS . S.iterateM step
492------------------------------------------------------------------------------
493-- Conversions
494------------------------------------------------------------------------------
496-- |
497-- @
498-- fromFoldableM = 'Prelude.foldr' 'consM' 'K.nil'
499-- @
500--
501-- Construct a stream from a 'Foldable' containing monadic actions.
502--
503-- @
504-- drain $ fromSerial $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
505-- drain $ fromAsync $ S.fromFoldableM $ replicateM 10 (threadDelay 1000000 >> print 1)
506-- @
507--
508-- /Concurrent (do not use with 'fromParallel' on infinite containers)/
509--
510-- @since 0.3.0
511{-# INLINE fromFoldableM #-}
512fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
513fromFoldableM = Prelude.foldr consM K.nil
515-- |
516-- @
517-- fromListM = 'Prelude.foldr' 'K.consM' 'K.nil'
518-- @
519--
520-- Construct a stream from a list of monadic actions. This is more efficient
521-- than 'fromFoldableM' for serial streams.
522--
523-- @since 0.4.0
524{-# INLINE_EARLY fromListM #-}
525fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
526fromListM = fromFoldableM
527{-# RULES "fromListM fallback to StreamK" [1]
528 forall a. D.toStreamK (D.fromListM a) = fromFoldableM a #-}
530{-# RULES "fromListM serial" fromListM = fromListMSerial #-}
531{-# INLINE_EARLY fromListMSerial #-}
532fromListMSerial :: MonadAsync m => [m a] -> SerialT m a
533fromListMSerial = fromStreamD . D.fromListM
535-- | Same as 'fromFoldable'.
536--
537-- @since 0.1.0
538{-# DEPRECATED each "Please use fromFoldable instead." #-}
539{-# INLINE each #-}
540each :: (IsStream t, Foldable f) => f a -> t m a
541each = K.fromFoldable
543-- | Read lines from an IO Handle into a stream of Strings.
544--
545-- @since 0.1.0
546{-# DEPRECATED fromHandle
547 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
548fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
549fromHandle h = go
550 where
551 go = K.mkStream $ \_ yld _ stp -> do
552 eof <- liftIO $ IO.hIsEOF h
553 if eof
554 then stp
555 else do
556 str <- liftIO $ IO.hGetLine h
557 yld str go
559-- XXX This should perhaps be moved to Parallel
560--
561-- | Takes a callback setter function and provides it with a callback. The
562-- callback when invoked adds a value at the tail of the stream. Returns a
563-- stream of values generated by the callback.
564--
565-- /Pre-release/
566--
567{-# INLINE fromCallback #-}
568fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
569fromCallback setCallback = concatM $ do
570 (callback, stream) <- Par.newCallbackStream
571 setCallback callback
572 return stream