on 48ad6db help sign in
663 lines 21 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 IsStream.nil
22 , IsStream.nilM
23 , IsStream.cons
24 , (IsStream..:)
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 , mfix
73 -- * From Containers
74 , IsStream.fromList
75 , fromListM
76 , fromFoldable
77 , fromFoldableM
78 , fromCallback
79 , fromPrimIORef
81 -- * Deprecated
82 , yield
83 , yieldM
84 , fromHandle
85 , currentTime
86 )
87where
89#include "inline.hs"
91import Control.Monad.IO.Class (MonadIO(..))
92import Data.Primitive.Types (Prim)
93import Data.Void (Void)
94import Streamly.Internal.Control.Concurrent (MonadAsync)
95import Streamly.Internal.Data.Unfold.Type (Unfold)
96import Streamly.Internal.Data.SVar (Rate (..))
97import Streamly.Internal.Data.Stream.IsStream.Enumeration
98 (Enumerable(..), enumerate, enumerateTo)
99import Streamly.Internal.Data.Stream.IsStream.Common
100 ( absTimesWith, concatM, relTimesWith, timesWith, fromPure, fromEffect
101 , yield, yieldM, repeatM)
102import Streamly.Internal.Data.Stream.IsStream.Type
103 (IsStream (..), fromSerial, consM, fromStreamD, fromStreamS)
104import Streamly.Internal.Data.Stream.Serial (SerialT(..))
105import Streamly.Internal.Data.Stream.WSerial (WSerialT)
106import Streamly.Internal.Data.Stream.Zip (ZipSerialM)
107import Streamly.Internal.Data.Time.Units (AbsTime , RelTime64, addToAbsTime64)
109import qualified Streamly.Internal.Data.IORef.Prim as Prim
110import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
111import qualified Streamly.Internal.Data.Stream.Parallel as Par
112import qualified Streamly.Internal.Data.Stream.Serial as Serial
113import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
114import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
115#ifdef USE_STREAMK_ONLY
116import qualified Streamly.Internal.Data.Stream.StreamK as S
117import qualified Streamly.Internal.Data.Stream.StreamK.Type as S
118#else
119import qualified Streamly.Internal.Data.Stream.StreamD.Generate as S
120#endif
121import qualified System.IO as IO
123import Prelude hiding (iterate, replicate, repeat)
125-- $setup
126-- >>> :m
127-- >>> import Data.Function ((&))
128-- >>> import Prelude hiding (iterate, replicate, repeat)
129-- >>> import qualified Streamly.Prelude as Stream
130-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
131-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
132-- >>> import Control.Concurrent (threadDelay)
133-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
134--
135-- >>> hSetBuffering stdout LineBuffering
137------------------------------------------------------------------------------
138-- From Unfold
139------------------------------------------------------------------------------
141-- | Convert an 'Unfold' into a stream by supplying it an input seed.
142--
143-- >>> Stream.drain $ Stream.unfold (Unfold.replicateM 3) (putStrLn "hello")
144-- hello
145-- hello
146-- hello
147--
148-- /Since: 0.7.0/
149{-# INLINE unfold #-}
150unfold :: (IsStream t, Monad m) => Unfold m a b -> a -> t m b
151unfold unf x = fromStreamD $ D.unfold unf x
153-- | Convert an 'Unfold' with a closed input end into a stream.
154--
155-- /Pre-release/
156{-# INLINE unfold0 #-}
157unfold0 :: (IsStream t, Monad m) => Unfold m Void b -> t m b
158unfold0 unf = unfold unf (error "unfold0: unexpected void evaluation")
160------------------------------------------------------------------------------
161-- Generation by Unfolding
162------------------------------------------------------------------------------
164-- |
165-- >>> :{
166-- unfoldr step s =
167-- case step s of
168-- Nothing -> Stream.nil
169-- Just (a, b) -> a `Stream.cons` unfoldr step b
170-- :}
171--
172-- Build a stream by unfolding a /pure/ step function @step@ starting from a
173-- seed @s@. The step function returns the next element in the stream and the
174-- next seed value. When it is done it returns 'Nothing' and the stream ends.
175-- For example,
176--
177-- >>> :{
178-- let f b =
179-- if b > 2
180-- then Nothing
181-- else Just (b, b + 1)
182-- in Stream.toList $ Stream.unfoldr f 0
183-- :}
184-- [0,1,2]
185--
186-- @since 0.1.0
187{-# INLINE_EARLY unfoldr #-}
188unfoldr :: (Monad m, IsStream t) => (b -> Maybe (a, b)) -> b -> t m a
189unfoldr step seed = fromStreamS (S.unfoldr step seed)
190{-# RULES "unfoldr fallback to StreamK" [1]
191 forall a b. S.toStreamK (S.unfoldr a b) = K.unfoldr a b #-}
193-- | Build a stream by unfolding a /monadic/ step function starting from a
194-- seed. The step function returns the next element in the stream and the next
195-- seed value. When it is done it returns 'Nothing' and the stream ends. For
196-- example,
197--
198-- >>> :{
199-- let f b =
200-- if b > 2
201-- then return Nothing
202-- else return (Just (b, b + 1))
203-- in Stream.toList $ Stream.unfoldrM f 0
204-- :}
205-- [0,1,2]
206--
207-- When run concurrently, the next unfold step can run concurrently with the
208-- processing of the output of the previous step. Note that more than one step
209-- cannot run concurrently as the next step depends on the output of the
210-- previous step.
211--
212-- >>> :{
213-- let f b =
214-- if b > 2
215-- then return Nothing
216-- else threadDelay 1000000 >> return (Just (b, b + 1))
217-- in Stream.toList $ Stream.delay 1 $ Stream.fromAsync $ Stream.unfoldrM f 0
218-- :}
219-- [0,1,2]
220--
221-- /Concurrent/
222--
223-- /Since: 0.1.0/
224{-# INLINE_EARLY unfoldrM #-}
225unfoldrM :: forall t m b a. (IsStream t, MonadAsync m) =>
226 (b -> m (Maybe (a, b))) -> b -> t m a
227unfoldrM step = fromStream . K.unfoldrMWith (IsStream.toConsK (consM @t)) step
229{-# RULES "unfoldrM serial" unfoldrM = unfoldrMSerial #-}
230{-# INLINE_EARLY unfoldrMSerial #-}
231unfoldrMSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> SerialT m a
232unfoldrMSerial = Serial.unfoldrM
234{-# RULES "unfoldrM wSerial" unfoldrM = unfoldrMWSerial #-}
235{-# INLINE_EARLY unfoldrMWSerial #-}
236unfoldrMWSerial :: MonadAsync m => (b -> m (Maybe (a, b))) -> b -> WSerialT m a
237unfoldrMWSerial f = fromSerial . Serial.unfoldrM f
239{-# RULES "unfoldrM zipSerial" unfoldrM = unfoldrMZipSerial #-}
240{-# INLINE_EARLY unfoldrMZipSerial #-}
241unfoldrMZipSerial :: MonadAsync m =>
242 (b -> m (Maybe (a, b))) -> b -> ZipSerialM m a
243unfoldrMZipSerial f = fromSerial . Serial.unfoldrM f
245------------------------------------------------------------------------------
246-- From Values
247------------------------------------------------------------------------------
249-- |
250-- Generate an infinite stream by repeating a pure value.
251--
252-- @since 0.4.0
253{-# INLINE_NORMAL repeat #-}
254repeat :: (IsStream t, Monad m) => a -> t m a
255repeat = fromStreamS . S.repeat
257-- |
258-- >>> replicate n = Stream.take n . Stream.repeat
259--
260-- Generate a stream of length @n@ by repeating a value @n@ times.
261--
262-- @since 0.6.0
263{-# INLINE_NORMAL replicate #-}
264replicate :: (IsStream t, Monad m) => Int -> a -> t m a
265replicate n = fromStreamS . S.replicate n
267-- |
268-- >>> replicateM n = Stream.take n . Stream.repeatM
269--
270-- Generate a stream by performing a monadic action @n@ times. Same as:
271--
272-- >>> pr n = threadDelay 1000000 >> print n
273--
274-- This runs serially and takes 3 seconds:
275--
276-- >>> Stream.drain $ Stream.fromSerial $ Stream.replicateM 3 $ pr 1
277-- 1
278-- 1
279-- 1
280--
281-- This runs concurrently and takes just 1 second:
282--
283-- >>> Stream.drain $ Stream.fromAsync $ Stream.replicateM 3 $ pr 1
284-- 1
285-- 1
286-- 1
287--
288-- /Concurrent/
289--
290-- @since 0.1.1
291{-# INLINE_EARLY replicateM #-}
292replicateM :: forall t m a. (IsStream t, MonadAsync m) => Int -> m a -> t m a
293replicateM count =
294 fromStream . K.replicateMWith (IsStream.toConsK (consM @t)) count
296{-# RULES "replicateM serial" replicateM = replicateMSerial #-}
297{-# INLINE replicateMSerial #-}
298replicateMSerial :: MonadAsync m => Int -> m a -> SerialT m a
299replicateMSerial n = fromStreamS . S.replicateM n
301------------------------------------------------------------------------------
302-- Time Enumeration
303------------------------------------------------------------------------------
305-- | @times@ returns a stream of time value tuples with clock of 10 ms
306-- granularity. The first component of the tuple is an absolute time reference
307-- (epoch) denoting the start of the stream and the second component is a time
308-- relative to the reference.
309--
310-- >>> Stream.mapM_ (\x -> print x >> threadDelay 1000000) $ Stream.take 3 $ Stream.times
311-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
312-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
313-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
314--
315-- Note: This API is not safe on 32-bit machines.
316--
317-- /Pre-release/
318--
319{-# INLINE times #-}
320times :: (IsStream t, MonadAsync m) => t m (AbsTime, RelTime64)
321times = timesWith 0.01
323-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
324-- granularity.
325--
326-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
327-- AbsTime (TimeSpec {sec = ..., nsec = ...})
328-- AbsTime (TimeSpec {sec = ..., nsec = ...})
329-- AbsTime (TimeSpec {sec = ..., nsec = ...})
330--
331-- Note: This API is not safe on 32-bit machines.
332--
333-- /Pre-release/
334--
335{-# INLINE absTimes #-}
336absTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m AbsTime
337absTimes = fmap (uncurry addToAbsTime64) times
339{-# DEPRECATED currentTime "Please use absTimes instead" #-}
340{-# INLINE currentTime #-}
341currentTime :: (IsStream t, MonadAsync m, Functor (t m))
342 => Double -> t m AbsTime
343currentTime = absTimesWith
345-- | @relTimes@ returns a stream of relative time values starting from 0,
346-- using a clock of granularity 10 ms.
347--
348-- >>> Stream.mapM_ print $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
349-- RelTime64 (NanoSecond64 ...)
350-- RelTime64 (NanoSecond64 ...)
351-- RelTime64 (NanoSecond64 ...)
352--
353-- Note: This API is not safe on 32-bit machines.
354--
355-- /Pre-release/
356--
357{-# INLINE relTimes #-}
358relTimes :: (IsStream t, MonadAsync m, Functor (t m)) => t m RelTime64
359relTimes = fmap snd times
361-- | @durations g@ returns a stream of relative time values measuring the time
362-- elapsed since the immediate predecessor element of the stream was generated.
363-- The first element of the stream is always 0. @durations@ uses a clock of
364-- granularity @g@ specified in seconds. A low granularity clock is more
365-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
366-- Durations lower than 1 ms will be 0.
367--
368-- Note: This API is not safe on 32-bit machines.
369--
370-- /Unimplemented/
371--
372{-# INLINE durations #-}
373durations :: -- (IsStream t, MonadAsync m) =>
374 Double -> t m RelTime64
375durations = undefined
377-- | Generate ticks at the specified rate. The rate is adaptive, the tick
378-- generation speed can be increased or decreased at different times to achieve
379-- the specified rate. The specific behavior for different styles of 'Rate'
380-- specifications is documented under 'Rate'. The effective maximum rate
381-- achieved by a stream is governed by the processor speed.
382--
383-- /Unimplemented/
384--
385{-# INLINE ticks #-}
386ticks :: -- (IsStream t, MonadAsync m) =>
387 Rate -> t m ()
388ticks = undefined
390-- | Generate a singleton event at or after the specified absolute time. Note
391-- that this is different from a threadDelay, a threadDelay starts from the
392-- time when the action is evaluated, whereas if we use AbsTime based timeout
393-- it will immediately expire if the action is evaluated too late.
394--
395-- /Unimplemented/
396--
397{-# INLINE timeout #-}
398timeout :: -- (IsStream t, MonadAsync m) =>
399 AbsTime -> t m ()
400timeout = undefined
402------------------------------------------------------------------------------
403-- From Generator functions
404------------------------------------------------------------------------------
406-- XXX we can remove it and recommend the definition in terms of enumerate and
407-- map. Check performance equivalence.
408--
409-- |
410-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
411-- >>> fromIndices f = let g i = f i `Stream.cons` g (i + 1) in g 0
412--
413-- Generate an infinite stream, whose values are the output of a function @f@
414-- applied on the corresponding index. Index starts at 0.
415--
416-- >>> Stream.toList $ Stream.take 5 $ Stream.fromIndices id
417-- [0,1,2,3,4]
418--
419-- @since 0.6.0
420{-# INLINE fromIndices #-}
421fromIndices :: (IsStream t, Monad m) => (Int -> a) -> t m a
422fromIndices = fromStreamS . S.fromIndices
424--
425-- |
426-- >>> fromIndicesM f = Stream.mapM f $ Stream.enumerateFrom 0
427-- >>> fromIndicesM f = let g i = f i `Stream.consM` g (i + 1) in g 0
428--
429-- Generate an infinite stream, whose values are the output of a monadic
430-- function @f@ applied on the corresponding index. Index starts at 0.
431--
432-- /Concurrent/
433--
434-- @since 0.6.0
435{-# INLINE_EARLY fromIndicesM #-}
436fromIndicesM :: forall t m a. (IsStream t, MonadAsync m) =>
437 (Int -> m a) -> t m a
438fromIndicesM = fromStream . K.fromIndicesMWith (IsStream.toConsK (consM @t))
440{-# RULES "fromIndicesM serial" fromIndicesM = fromIndicesMSerial #-}
441{-# INLINE fromIndicesMSerial #-}
442fromIndicesMSerial :: MonadAsync m => (Int -> m a) -> SerialT m a
443fromIndicesMSerial = fromStreamS . S.fromIndicesM
445------------------------------------------------------------------------------
446-- Iterating functions
447------------------------------------------------------------------------------
449-- |
450-- >>> iterate f x = x `Stream.cons` iterate f x
451--
452-- Generate an infinite stream with @x@ as the first element and each
453-- successive element derived by applying the function @f@ on the previous
454-- element.
455--
456-- >>> Stream.toList $ Stream.take 5 $ Stream.iterate (+1) 1
457-- [1,2,3,4,5]
458--
459-- @since 0.1.2
460{-# INLINE_NORMAL iterate #-}
461iterate :: (IsStream t, Monad m) => (a -> a) -> a -> t m a
462iterate step = fromStreamS . S.iterate step
464-- |
465-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
466--
467-- Generate an infinite stream with the first element generated by the action
468-- @m@ and each successive element derived by applying the monadic function
469-- @f@ on the previous element.
470--
471-- >>> pr n = threadDelay 1000000 >> print n
472-- >>> :{
473-- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0)
474-- & Stream.take 3
475-- & Stream.fromSerial
476-- & Stream.toList
477-- :}
478-- 0
479-- 1
480-- [0,1,2]
481--
482-- When run concurrently, the next iteration can run concurrently with the
483-- processing of the previous iteration. Note that more than one iteration
484-- cannot run concurrently as the next iteration depends on the output of the
485-- previous iteration.
486--
487-- >>> :{
488-- Stream.iterateM (\x -> pr x >> return (x + 1)) (return 0)
489-- & Stream.delay 1
490-- & Stream.take 3
491-- & Stream.fromAsync
492-- & Stream.toList
493-- :}
494-- 0
495-- 1
496-- ...
497--
498-- /Concurrent/
499--
500-- /Since: 0.1.2/
501--
502-- /Since: 0.7.0 (signature change)/
503{-# INLINE_EARLY iterateM #-}
504iterateM :: forall t m a. (IsStream t, MonadAsync m) =>
505 (a -> m a) -> m a -> t m a
506iterateM f = fromStream . K.iterateMWith (IsStream.toConsK (consM @t)) f
508{-# RULES "iterateM serial" iterateM = iterateMSerial #-}
509{-# INLINE iterateMSerial #-}
510iterateMSerial :: MonadAsync m => (a -> m a) -> m a -> SerialT m a
511iterateMSerial step = fromStreamS . S.iterateM step
513-- | We can define cyclic structures using @let@:
514--
515-- >>> let (a, b) = ([1, b], head a) in (a, b)
516-- ([1,1],1)
517--
518-- The function @fix@ defined as:
519--
520-- >>> fix f = let x = f x in x
521--
522-- ensures that the argument of a function and its output refer to the same
523-- lazy value @x@ i.e. the same location in memory. Thus @x@ can be defined
524-- in terms of itself, creating structures with cyclic references.
525--
526-- >>> f ~(a, b) = ([1, b], head a)
527-- >>> fix f
528-- ([1,1],1)
529--
530-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
531-- values.
532--
533-- Using 'mfix' for streams we can construct a stream in which each element of
534-- the stream is defined in a cyclic fashion. The argument of the function
535-- being fixed represents the current element of the stream which is being
536-- returned by the stream monad. Thus, we can use the argument to construct
537-- itself.
538--
539-- In the following example, the argument @action@ of the function @f@
540-- represents the tuple @(x,y)@ returned by it in a given iteration. We define
541-- the first element of the tuple in terms of the second.
542--
543-- >>> import Streamly.Internal.Data.Stream.IsStream as Stream
544-- >>> import System.IO.Unsafe (unsafeInterleaveIO)
545--
546-- >>> :{
547-- main = Stream.mapM_ print $ Stream.mfix f
548-- where
549-- f action = do
550-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
551-- x <- Stream.fromListM [incr 1 action, incr 2 action]
552-- y <- Stream.fromList [4,5]
553-- return (x, y)
554-- :}
555--
556-- Note: you cannot achieve this by just changing the order of the monad
557-- statements because that would change the order in which the stream elements
558-- are generated.
559--
560-- Note that the function @f@ must be lazy in its argument, that's why we use
561-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
562--
563-- /Pre-release/
564{-# INLINE mfix #-}
565mfix :: (IsStream t, Monad m) => (m a -> t m a) -> t m a
566mfix f = fromStream $ K.mfix (toStream . f)
568------------------------------------------------------------------------------
569-- Conversions
570------------------------------------------------------------------------------
572-- |
573-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
574--
575-- Construct a stream from a 'Foldable' containing pure values:
576--
577-- @since 0.2.0
578{-# INLINE fromFoldable #-}
579fromFoldable :: (IsStream t, Foldable f) => f a -> t m a
580fromFoldable = fromStream . K.fromFoldable
582-- |
583-- >>> fromFoldableM = Prelude.foldr Stream.consM Stream.nil
584--
585-- Construct a stream from a 'Foldable' containing monadic actions.
586--
587-- >>> pr n = threadDelay 1000000 >> print n
588-- >>> Stream.drain $ Stream.fromSerial $ Stream.fromFoldableM $ map pr [1,2,3]
589-- 1
590-- 2
591-- 3
592--
593-- >>> Stream.drain $ Stream.fromAsync $ Stream.fromFoldableM $ map pr [1,2,3]
594-- ...
595-- ...
596-- ...
597--
598-- /Concurrent (do not use with 'fromParallel' on infinite containers)/
599--
600-- @since 0.3.0
601{-# INLINE fromFoldableM #-}
602fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
603fromFoldableM = Prelude.foldr consM IsStream.nil
605-- |
606-- >>> fromListM = Stream.fromFoldableM
607-- >>> fromListM = Stream.sequence . Stream.fromList
608-- >>> fromListM = Stream.mapM id . Stream.fromList
609-- >>> fromListM = Prelude.foldr Stream.consM Stream.nil
610--
611-- Construct a stream from a list of monadic actions. This is more efficient
612-- than 'fromFoldableM' for serial streams.
613--
614-- @since 0.4.0
615{-# INLINE_EARLY fromListM #-}
616fromListM :: (MonadAsync m, IsStream t) => [m a] -> t m a
617fromListM = fromFoldableM
618{-# RULES "fromListM fallback to StreamK" [1]
619 forall a. D.toStreamK (D.fromListM a) = K.fromFoldableM a #-}
621{-# RULES "fromListM serial" fromListM = fromListMSerial #-}
622{-# INLINE_EARLY fromListMSerial #-}
623fromListMSerial :: MonadAsync m => [m a] -> SerialT m a
624fromListMSerial = fromStreamD . D.fromListM
626-- | Read lines from an IO Handle into a stream of Strings.
627--
628-- @since 0.1.0
629{-# DEPRECATED fromHandle
630 "Please use Streamly.FileSystem.Handle module (see the changelog)" #-}
631fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
632fromHandle h = go
633 where
634 go = IsStream.mkStream $ \_ yld _ stp -> do
635 eof <- liftIO $ IO.hIsEOF h
636 if eof
637 then stp
638 else do
639 str <- liftIO $ IO.hGetLine h
640 yld str go
642-- XXX This should perhaps be moved to Parallel
643--
644-- | Takes a callback setter function and provides it with a callback. The
645-- callback when invoked adds a value at the tail of the stream. Returns a
646-- stream of values generated by the callback.
647--
648-- /Pre-release/
649--
650{-# INLINE fromCallback #-}
651fromCallback :: MonadAsync m => ((a -> m ()) -> m ()) -> SerialT m a
652fromCallback setCallback = concatM $ do
653 (callback, stream) <- Par.newCallbackStream
654 setCallback callback
655 return $ SerialT stream
657-- | Construct a stream by reading a 'Prim' 'IORef' repeatedly.
658--
659-- /Pre-release/
660--
661{-# INLINE fromPrimIORef #-}
662fromPrimIORef :: (IsStream t, MonadIO m, Prim a) => Prim.IORef a -> t m a
663fromPrimIORef = fromStreamD . Prim.toStreamD