on 30c98dc help sign in
446 lines 14 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3-- |
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
9-- Portability : GHC
10--
11-- Some idioms:
12--
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
19--
20module Streamly.Internal.Data.Stream.Generate
21 (
22 -- * Primitives
23 Stream.nil
24 , Stream.nilM
25 , Stream.cons
26 , Stream.consM
28 -- * From 'Unfold'
29 , unfold
31 -- * Unfolding
32 , unfoldr
33 , unfoldrM
35 -- * From Values
36 , Stream.fromPure
37 , Stream.fromEffect
38 , repeat
39 , replicate
41 -- * Enumeration
42 , Enumerable (..)
43 , enumerate
44 , enumerateTo
46 -- * Time Enumeration
47 , times
48 , timesWith
49 , absTimes
50 , absTimesWith
51 , relTimes
52 , relTimesWith
53 , durations
54 , timeout
56 -- * Iteration
57 , iterate
58 , iterateM
60 -- * Cyclic Elements
61 , mfix
63 -- * From Containers
64 , Bottom.fromList
65 , fromFoldable
67 -- * From memory
68 , fromPtr
69 , fromPtrN
70 , fromByteStr#
71 -- , fromByteArray#
72 , fromUnboxedIORef
73 )
74where
76#include "inline.hs"
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)
100-- $setup
101-- >>> :m
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------------------------------------------------------------------------------
110-- From Unfold
111------------------------------------------------------------------------------
113-- | Convert an 'Unfold' into a stream by supplying it an input seed.
114--
115-- >>> s = Stream.unfold (Unfold.replicateM 3) (putStrLn "hello")
116-- >>> Stream.fold Fold.drain s
117-- hello
118-- hello
119-- hello
120--
121-- @since 0.9.0
122{-# INLINE unfold #-}
123unfold :: Monad m => Unfold m a b -> a -> Stream m b
124unfold unf = Stream.fromStreamD . D.unfold unf
126------------------------------------------------------------------------------
127-- Generation by Unfolding
128------------------------------------------------------------------------------
130-- |
131-- >>> :{
132-- unfoldr step s =
133-- case step s of
134-- Nothing -> Stream.nil
135-- Just (a, b) -> a `Stream.cons` unfoldr step b
136-- :}
137--
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.
141-- For example,
142--
143-- >>> :{
144-- let f b =
145-- if b > 2
146-- then Nothing
147-- else Just (b, b + 1)
148-- in Stream.fold Fold.toList $ Stream.unfoldr f 0
149-- :}
150-- [0,1,2]
151--
152-- @since 0.9.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
162-- example,
163--
164-- >>> :{
165-- let f b =
166-- if b > 2
167-- then return Nothing
168-- else return (Just (b, b + 1))
169-- in Stream.fold Fold.toList $ Stream.unfoldrM f 0
170-- :}
171-- [0,1,2]
172--
173-- @since 0.9.0
174{-# INLINE unfoldrM #-}
175unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
176unfoldrM step = fromStreamD . D.unfoldrM step
178------------------------------------------------------------------------------
179-- From Values
180------------------------------------------------------------------------------
182-- |
183-- Generate an infinite stream by repeating a pure value.
184--
185-- @since 0.9.0
186{-# INLINE_NORMAL repeat #-}
187repeat :: Monad m => a -> Stream m a
188repeat = fromStreamD . D.repeat
190-- |
191-- >>> replicate n = Stream.take n . Stream.repeat
192--
193-- Generate a stream of length @n@ by repeating a value @n@ times.
194--
195-- @since 0.9.0
196{-# INLINE_NORMAL replicate #-}
197replicate :: Monad m => Int -> a -> Stream m a
198replicate n = fromStreamD . D.replicate n
200------------------------------------------------------------------------------
201-- Time Enumeration
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.
208--
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 ...))
214--
215-- Note: This API is not safe on 32-bit machines.
216--
217-- /Pre-release/
218--
219{-# INLINE times #-}
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
224-- granularity.
225--
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 = ...})
231--
232-- Note: This API is not safe on 32-bit machines.
233--
234-- /Pre-release/
235--
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.
242--
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 ...)
248--
249-- Note: This API is not safe on 32-bit machines.
250--
251-- /Pre-release/
252--
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.
263--
264-- Note: This API is not safe on 32-bit machines.
265--
266-- /Unimplemented/
267--
268{-# INLINE durations #-}
269durations :: -- Monad m =>
270 Double -> t m RelTime64
271durations = undefined
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.
277--
278-- /Unimplemented/
279--
280{-# INLINE timeout #-}
281timeout :: -- Monad m =>
282 AbsTime -> t m ()
283timeout = undefined
285------------------------------------------------------------------------------
286-- Iterating functions
287------------------------------------------------------------------------------
289-- |
290-- >>> iterate f x = x `Stream.cons` iterate f x
291--
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
294-- element.
295--
296-- >>> Stream.fold Fold.toList $ Stream.take 5 $ Stream.iterate (+1) 1
297-- [1,2,3,4,5]
298--
299-- @since 0.9.0
300{-# INLINE_NORMAL iterate #-}
301iterate :: Monad m => (a -> a) -> a -> Stream m a
302iterate step = fromStreamD . D.iterate step
304-- |
305-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
306--
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.
310--
311-- >>> :{
312-- Stream.iterateM (\x -> print x >> return (x + 1)) (return 0)
313-- & Stream.take 3
314-- & Stream.fold Fold.toList
315-- :}
316-- 0
317-- 1
318-- [0,1,2]
319--
320-- @since 0.9.0
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@:
326--
327-- >>> let (a, b) = ([1, b], head a) in (a, b)
328-- ([1,1],1)
329--
330-- The function @fix@ defined as:
331--
332-- >>> fix f = let x = f x in x
333--
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.
337--
338-- >>> f ~(a, b) = ([1, b], head a)
339-- >>> fix f
340-- ([1,1],1)
341--
342-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
343-- values.
344--
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
349-- itself.
350--
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.
354--
355-- >>> import Streamly.Internal.Data.Stream as Stream
356-- >>> import System.IO.Unsafe (unsafeInterleaveIO)
357--
358-- >>> :{
359-- main = Stream.fold (Fold.drainBy print) $ Stream.mfix f
360-- where
361-- f action = do
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]
365-- return (x, y)
366-- :}
367--
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
370-- are generated.
371--
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.
374--
375-- /Not fused/
376--
377-- /Pre-release/
378{-# INLINE mfix #-}
379mfix :: Monad m => (m a -> Stream m a) -> Stream m a
380mfix f = fromStreamK $ K.mfix (toStreamK . f)
382------------------------------------------------------------------------------
383-- Conversions
384------------------------------------------------------------------------------
386-- |
387-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
388--
389-- Construct a stream from a 'Foldable' containing pure values:
390--
391-- /Not fused/
392--
393-- @since 0.9.0
394{-# INLINE fromFoldable #-}
395fromFoldable :: Foldable f => f a -> Stream m a
396fromFoldable = fromStreamK . K.fromFoldable
398------------------------------------------------------------------------------
399-- From pointers
400------------------------------------------------------------------------------
402-- | Keep reading 'Storable' elements from 'Ptr' onwards.
403--
404-- /Unsafe:/ The caller is responsible for safe addressing.
405--
406-- /Pre-release/
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.
412--
413-- >>> fromPtrN n = Stream.take n . Stream.fromPtr
414--
415-- /Unsafe:/ The caller is responsible for safe addressing.
416--
417-- /Pre-release/
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.
424--
425-- >>> fromByteStr# addr = Stream.takeWhile (/= 0) $ Stream.fromPtr $ Ptr addr
426--
427-- /Unsafe:/ The caller is responsible for safe addressing.
428--
429-- Note that this is completely safe when reading from Haskell string
430-- literals because they are guaranteed to be NULL terminated:
431--
432-- >>> Stream.fold Fold.toList $ Stream.fromByteStr# "\1\2\3\0"#
433-- [1,2,3]
434--
435{-# INLINE fromByteStr# #-}
436fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
437fromByteStr# addr =
438 Stream.fromStreamD $ D.takeWhile (/= 0) $ D.fromPtr $ Ptr addr
440-- | Construct a stream by reading an 'Unboxed' 'IORef' repeatedly.
441--
442-- /Pre-release/
443--
444{-# INLINE fromUnboxedIORef #-}
445fromUnboxedIORef :: (MonadIO m, Unboxed a) => Unboxed.IORef a -> Stream m a
446fromUnboxedIORef = fromStreamD . Unboxed.toStreamD