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