1{-# OPTIONS_GHC -Wno-orphans #-}
4-- Module : Streamly.Internal.Data.Stream.Generate
5-- Copyright : (c) 2017 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
13-- >>> fromEffect = Stream.sequence . Stream.fromPure
14-- >>> fromIndices f = fmap f $ Stream.enumerateFrom 0
15-- >>> repeatM = Stream.sequence . Stream.repeat
16-- >>> replicateM n = Stream.sequence . Stream.replicate n
17-- >>> fromListM = Stream.sequence . Stream.fromList
18-- >>> fromFoldableM = Stream.sequence . Stream.fromFoldable
20module Streamly.Internal.Data.Stream.Generate
78import Control.Monad.IO.Class (MonadIO)
79import Data.Word (Word8)
80import Foreign.Storable (Storable)
81import GHC.Exts (Addr#, Ptr (Ptr))
82import Streamly.Internal.Data.Stream.Bottom
83 (absTimesWith, relTimesWith, timesWith)
84import Streamly.Internal.Data.Stream.Enumerate
85 (Enumerable(..), enumerate, enumerateTo)
86import Streamly.Internal.Data.Stream.Type
87 (Stream, fromStreamD, fromStreamK, toStreamK)
88import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
89import Streamly.Internal.Data.Unboxed (Unboxed)
90import Streamly.Internal.Data.Unfold.Type (Unfold)
92import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
93import qualified Streamly.Internal.Data.Stream.Bottom as Bottom
94import qualified Streamly.Internal.Data.Stream.StreamD as D
95import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
96import qualified Streamly.Internal.Data.Stream.Type as Stream
98import Prelude hiding (iterate, replicate, repeat)
102-- >>> import Control.Concurrent (threadDelay)
103-- >>> import Data.Function ((&))
104-- >>> import qualified Streamly.Data.Fold as Fold
105-- >>> import qualified Streamly.Data.Unfold as Unfold
106-- >>> import qualified Streamly.Internal.Data.Stream as Stream
107-- >>> import GHC.Exts (Ptr (Ptr))
109------------------------------------------------------------------------------
111------------------------------------------------------------------------------
113-- | Convert an 'Unfold' into a stream by supplying it an input seed.
115-- >>> s = Stream.unfold (Unfold.replicateM 3) (putStrLn "hello")
116-- >>> Stream.fold Fold.drain s
123unfold :: Monad m => Unfold m a b -> a -> Stream m b
124unfold unf = Stream.fromStreamD . D.unfold unf
126------------------------------------------------------------------------------
127-- Generation by Unfolding
128------------------------------------------------------------------------------
134-- Nothing -> Stream.nil
135-- Just (a, b) -> a `Stream.cons` unfoldr step b
138-- Build a stream by unfolding a /pure/ step function @step@ starting from a
139-- seed @s@. The step function returns the next element in the stream and the
140-- next seed value. When it is done it returns 'Nothing' and the stream ends.
147-- else Just (b, b + 1)
148-- in Stream.fold Fold.toList $ Stream.unfoldr f 0
153{-# INLINE_EARLY unfoldr #-}
154unfoldr :: Monad m => (b -> Maybe (a, b)) -> b -> Stream m a
155unfoldr step seed = fromStreamD (D.unfoldr step seed)
156{-# RULES "unfoldr fallback to StreamK" [1]
157 forall a b. D.toStreamK (D.unfoldr a b) = K.unfoldr a b #-}
159-- | Build a stream by unfolding a /monadic/ step function starting from a
160-- seed. The step function returns the next element in the stream and the next
161-- seed value. When it is done it returns 'Nothing' and the stream ends. For
167-- then return Nothing
168-- else return (Just (b, b + 1))
169-- in Stream.fold Fold.toList $ Stream.unfoldrM f 0
174{-# INLINE unfoldrM #-}
175unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
176unfoldrM step = fromStreamD . D.unfoldrM step
178------------------------------------------------------------------------------
180------------------------------------------------------------------------------
183-- Generate an infinite stream by repeating a pure value.
186{-# INLINE_NORMAL repeat #-}
187repeat :: Monad m => a -> Stream m a
188repeat = fromStreamD . D.repeat
191-- >>> replicate n = Stream.take n . Stream.repeat
193-- Generate a stream of length @n@ by repeating a value @n@ times.
196{-# INLINE_NORMAL replicate #-}
197replicate :: Monad m => Int -> a -> Stream m a
198replicate n = fromStreamD . D.replicate n
200------------------------------------------------------------------------------
202------------------------------------------------------------------------------
204-- | @times@ returns a stream of time value tuples with clock of 10 ms
205-- granularity. The first component of the tuple is an absolute time reference
206-- (epoch) denoting the start of the stream and the second component is a time
207-- relative to the reference.
209-- >>> f = Fold.drainBy (\x -> print x >> threadDelay 1000000)
210-- >>> Stream.fold f $ Stream.take 3 $ Stream.times
211-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
212-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
213-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
215-- Note: This API is not safe on 32-bit machines.
220times :: MonadIO m => Stream m (AbsTime, RelTime64)
221times = timesWith 0.01
223-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
226-- >>> f = Fold.drainBy print
227-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
228-- AbsTime (TimeSpec {sec = ..., nsec = ...})
229-- AbsTime (TimeSpec {sec = ..., nsec = ...})
230-- AbsTime (TimeSpec {sec = ..., nsec = ...})
232-- Note: This API is not safe on 32-bit machines.
236{-# INLINE absTimes #-}
237absTimes :: MonadIO m => Stream m AbsTime
238absTimes = fmap (uncurry addToAbsTime64) times
240-- | @relTimes@ returns a stream of relative time values starting from 0,
241-- using a clock of granularity 10 ms.
243-- >>> f = Fold.drainBy print
244-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
245-- RelTime64 (NanoSecond64 ...)
246-- RelTime64 (NanoSecond64 ...)
247-- RelTime64 (NanoSecond64 ...)
249-- Note: This API is not safe on 32-bit machines.
253{-# INLINE relTimes #-}
254relTimes :: MonadIO m => Stream m RelTime64
255relTimes = fmap snd times
257-- | @durations g@ returns a stream of relative time values measuring the time
258-- elapsed since the immediate predecessor element of the stream was generated.
259-- The first element of the stream is always 0. @durations@ uses a clock of
260-- granularity @g@ specified in seconds. A low granularity clock is more
261-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
262-- Durations lower than 1 ms will be 0.
264-- Note: This API is not safe on 32-bit machines.
268{-# INLINE durations #-}
269durations :: -- Monad m =>
270 Double -> t m RelTime64
273-- | Generate a singleton event at or after the specified absolute time. Note
274-- that this is different from a threadDelay, a threadDelay starts from the
275-- time when the action is evaluated, whereas if we use AbsTime based timeout
276-- it will immediately expire if the action is evaluated too late.
280{-# INLINE timeout #-}
281timeout :: -- Monad m =>
285------------------------------------------------------------------------------
286-- Iterating functions
287------------------------------------------------------------------------------
290-- >>> iterate f x = x `Stream.cons` iterate f x
292-- Generate an infinite stream with @x@ as the first element and each
293-- successive element derived by applying the function @f@ on the previous
296-- >>> Stream.fold Fold.toList $ Stream.take 5 $ Stream.iterate (+1) 1
300{-# INLINE_NORMAL iterate #-}
301iterate :: Monad m => (a -> a) -> a -> Stream m a
302iterate step = fromStreamD . D.iterate step
305-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
307-- Generate an infinite stream with the first element generated by the action
308-- @m@ and each successive element derived by applying the monadic function
309-- @f@ on the previous element.
312-- Stream.iterateM (\x -> print x >> return (x + 1)) (return 0)
314-- & Stream.fold Fold.toList
321{-# INLINE iterateM #-}
322iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
323iterateM step = fromStreamD . D.iterateM step
325-- | We can define cyclic structures using @let@:
327-- >>> let (a, b) = ([1, b], head a) in (a, b)
330-- The function @fix@ defined as:
332-- >>> fix f = let x = f x in x
334-- ensures that the argument of a function and its output refer to the same
335-- lazy value @x@ i.e. the same location in memory. Thus @x@ can be defined
336-- in terms of itself, creating structures with cyclic references.
338-- >>> f ~(a, b) = ([1, b], head a)
342-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
345-- Using 'mfix' for streams we can construct a stream in which each element of
346-- the stream is defined in a cyclic fashion. The argument of the function
347-- being fixed represents the current element of the stream which is being
348-- returned by the stream monad. Thus, we can use the argument to construct
351-- In the following example, the argument @action@ of the function @f@
352-- represents the tuple @(x,y)@ returned by it in a given iteration. We define
353-- the first element of the tuple in terms of the second.
355-- >>> import Streamly.Internal.Data.Stream as Stream
356-- >>> import System.IO.Unsafe (unsafeInterleaveIO)
359-- main = Stream.fold (Fold.drainBy print) $ Stream.mfix f
362-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
363-- x <- Stream.sequence $ Stream.fromList [incr 1 action, incr 2 action]
364-- y <- Stream.fromList [4,5]
368-- Note: you cannot achieve this by just changing the order of the monad
369-- statements because that would change the order in which the stream elements
372-- Note that the function @f@ must be lazy in its argument, that's why we use
373-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
379mfix :: Monad m => (m a -> Stream m a) -> Stream m a
380mfix f = fromStreamK $ K.mfix (toStreamK . f)
382------------------------------------------------------------------------------
384------------------------------------------------------------------------------
387-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
389-- Construct a stream from a 'Foldable' containing pure values:
394{-# INLINE fromFoldable #-}
395fromFoldable :: Foldable f => f a -> Stream m a
396fromFoldable = fromStreamK . K.fromFoldable
398------------------------------------------------------------------------------
400------------------------------------------------------------------------------
402-- | Keep reading 'Storable' elements from 'Ptr' onwards.
404-- /Unsafe:/ The caller is responsible for safe addressing.
407{-# INLINE fromPtr #-}
408fromPtr :: (MonadIO m, Storable a) => Ptr a -> Stream m a
409fromPtr = Stream.fromStreamD . D.fromPtr
411-- | Take @n@ 'Storable' elements starting from 'Ptr' onwards.
413-- >>> fromPtrN n = Stream.take n . Stream.fromPtr
415-- /Unsafe:/ The caller is responsible for safe addressing.
418{-# INLINE fromPtrN #-}
419fromPtrN :: (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
420fromPtrN n = Stream.fromStreamD . D.take n . D.fromPtr
422-- | Read bytes from an 'Addr#' until a 0 byte is encountered, the 0 byte is
423-- not included in the stream.
425-- >>> fromByteStr# addr = Stream.takeWhile (/= 0) $ Stream.fromPtr $ Ptr addr
427-- /Unsafe:/ The caller is responsible for safe addressing.
429-- Note that this is completely safe when reading from Haskell string
430-- literals because they are guaranteed to be NULL terminated:
432-- >>> Stream.fold Fold.toList $ Stream.fromByteStr# "\1\2\3\0"#
435{-# INLINE fromByteStr# #-}
436fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
438 Stream.fromStreamD $ D.takeWhile (/= 0) $ D.fromPtr $ Ptr addr
440-- | Construct a stream by reading an 'Unboxed' 'IORef' repeatedly.
444{-# INLINE fromUnboxedIORef #-}
445fromUnboxedIORef :: (MonadIO m, Unboxed a) => Unboxed.IORef a -> Stream m a
446fromUnboxedIORef = fromStreamD . Unboxed.toStreamD
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list