on 162fc17 help sign in
437 lines 13 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--
11module Streamly.Internal.Data.Stream.Generate
12 (
13 -- * Primitives
14 Stream.nil
15 , Stream.nilM
16 , Stream.cons
17 , Stream.consM
19 -- * From 'Unfold'
20 , unfold
22 -- * Unfolding
23 , unfoldr
24 , unfoldrM
26 -- * From Values
27 , Stream.fromPure
28 , Stream.fromEffect
29 , repeat
30 , replicate
32 -- * Enumeration
33 , Enumerable (..)
34 , enumerate
35 , enumerateTo
37 -- * Time Enumeration
38 , times
39 , timesWith
40 , absTimes
41 , absTimesWith
42 , relTimes
43 , relTimesWith
44 , durations
45 , timeout
47 -- * Iteration
48 , iterate
49 , iterateM
51 -- * Cyclic Elements
52 , mfix
54 -- * From Containers
55 , Bottom.fromList
56 , fromFoldable
58 -- * From memory
59 , fromPtr
60 , fromPtrN
61 , fromByteStr#
62 -- , fromByteArray#
63 , fromUnboxedIORef
64 )
65where
67#include "inline.hs"
69import Control.Monad.IO.Class (MonadIO)
70import Data.Word (Word8)
71import Foreign.Storable (Storable)
72import GHC.Exts (Addr#, Ptr (Ptr))
73import Streamly.Internal.Data.Stream.Bottom
74 (absTimesWith, relTimesWith, timesWith)
75import Streamly.Internal.Data.Stream.Enumerate
76 (Enumerable(..), enumerate, enumerateTo)
77import Streamly.Internal.Data.Stream.Type
78 (Stream, fromStreamD, fromStreamK, toStreamK)
79import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64, addToAbsTime64)
80import Streamly.Internal.Data.Unboxed (Unboxed)
81import Streamly.Internal.Data.Unfold.Type (Unfold)
83import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
84import qualified Streamly.Internal.Data.Stream.Bottom as Bottom
85import qualified Streamly.Internal.Data.Stream.StreamD as D
86import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
87import qualified Streamly.Internal.Data.Stream.Type as Stream
89import Prelude hiding (iterate, replicate, repeat)
91-- $setup
92-- >>> :m
93-- >>> import Control.Concurrent (threadDelay)
94-- >>> import Data.Function ((&))
95-- >>> import qualified Streamly.Data.Fold as Fold
96-- >>> import qualified Streamly.Data.Unfold as Unfold
97-- >>> import qualified Streamly.Internal.Data.Stream as Stream
98-- >>> import GHC.Exts (Ptr (Ptr))
100------------------------------------------------------------------------------
101-- From Unfold
102------------------------------------------------------------------------------
104-- | Convert an 'Unfold' into a stream by supplying it an input seed.
105--
106-- >>> s = Stream.unfold Unfold.replicateM (3, putStrLn "hello")
107-- >>> Stream.fold Fold.drain s
108-- hello
109-- hello
110-- hello
111--
112-- @since 0.9.0
113{-# INLINE unfold #-}
114unfold :: Monad m => Unfold m a b -> a -> Stream m b
115unfold unf = Stream.fromStreamD . D.unfold unf
117------------------------------------------------------------------------------
118-- Generation by Unfolding
119------------------------------------------------------------------------------
121-- |
122-- >>> :{
123-- unfoldr step s =
124-- case step s of
125-- Nothing -> Stream.nil
126-- Just (a, b) -> a `Stream.cons` unfoldr step b
127-- :}
128--
129-- Build a stream by unfolding a /pure/ step function @step@ starting from a
130-- seed @s@. The step function returns the next element in the stream and the
131-- next seed value. When it is done it returns 'Nothing' and the stream ends.
132-- For example,
133--
134-- >>> :{
135-- let f b =
136-- if b > 2
137-- then Nothing
138-- else Just (b, b + 1)
139-- in Stream.fold Fold.toList $ Stream.unfoldr f 0
140-- :}
141-- [0,1,2]
142--
143-- @since 0.9.0
144{-# INLINE_EARLY unfoldr #-}
145unfoldr :: Monad m => (b -> Maybe (a, b)) -> b -> Stream m a
146unfoldr step seed = fromStreamD (D.unfoldr step seed)
147{-# RULES "unfoldr fallback to StreamK" [1]
148 forall a b. D.toStreamK (D.unfoldr a b) = K.unfoldr a b #-}
150-- | Build a stream by unfolding a /monadic/ step function starting from a
151-- seed. The step function returns the next element in the stream and the next
152-- seed value. When it is done it returns 'Nothing' and the stream ends. For
153-- example,
154--
155-- >>> :{
156-- let f b =
157-- if b > 2
158-- then return Nothing
159-- else return (Just (b, b + 1))
160-- in Stream.fold Fold.toList $ Stream.unfoldrM f 0
161-- :}
162-- [0,1,2]
163--
164-- @since 0.9.0
165{-# INLINE unfoldrM #-}
166unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> Stream m a
167unfoldrM step = fromStreamD . D.unfoldrM step
169------------------------------------------------------------------------------
170-- From Values
171------------------------------------------------------------------------------
173-- |
174-- Generate an infinite stream by repeating a pure value.
175--
176-- @since 0.9.0
177{-# INLINE_NORMAL repeat #-}
178repeat :: Monad m => a -> Stream m a
179repeat = fromStreamD . D.repeat
181-- |
182-- >>> replicate n = Stream.take n . Stream.repeat
183--
184-- Generate a stream of length @n@ by repeating a value @n@ times.
185--
186-- @since 0.9.0
187{-# INLINE_NORMAL replicate #-}
188replicate :: Monad m => Int -> a -> Stream m a
189replicate n = fromStreamD . D.replicate n
191------------------------------------------------------------------------------
192-- Time Enumeration
193------------------------------------------------------------------------------
195-- | @times@ returns a stream of time value tuples with clock of 10 ms
196-- granularity. The first component of the tuple is an absolute time reference
197-- (epoch) denoting the start of the stream and the second component is a time
198-- relative to the reference.
199--
200-- >>> f = Fold.drainBy (\x -> print x >> threadDelay 1000000)
201-- >>> Stream.fold f $ Stream.take 3 $ Stream.times
202-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
203-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
204-- (AbsTime (TimeSpec {sec = ..., nsec = ...}),RelTime64 (NanoSecond64 ...))
205--
206-- Note: This API is not safe on 32-bit machines.
207--
208-- /Pre-release/
209--
210{-# INLINE times #-}
211times :: MonadIO m => Stream m (AbsTime, RelTime64)
212times = timesWith 0.01
214-- | @absTimes@ returns a stream of absolute timestamps using a clock of 10 ms
215-- granularity.
216--
217-- >>> f = Fold.drainBy print
218-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.absTimes
219-- AbsTime (TimeSpec {sec = ..., nsec = ...})
220-- AbsTime (TimeSpec {sec = ..., nsec = ...})
221-- AbsTime (TimeSpec {sec = ..., nsec = ...})
222--
223-- Note: This API is not safe on 32-bit machines.
224--
225-- /Pre-release/
226--
227{-# INLINE absTimes #-}
228absTimes :: MonadIO m => Stream m AbsTime
229absTimes = fmap (uncurry addToAbsTime64) times
231-- | @relTimes@ returns a stream of relative time values starting from 0,
232-- using a clock of granularity 10 ms.
233--
234-- >>> f = Fold.drainBy print
235-- >>> Stream.fold f $ Stream.delayPre 1 $ Stream.take 3 $ Stream.relTimes
236-- RelTime64 (NanoSecond64 ...)
237-- RelTime64 (NanoSecond64 ...)
238-- RelTime64 (NanoSecond64 ...)
239--
240-- Note: This API is not safe on 32-bit machines.
241--
242-- /Pre-release/
243--
244{-# INLINE relTimes #-}
245relTimes :: MonadIO m => Stream m RelTime64
246relTimes = fmap snd times
248-- | @durations g@ returns a stream of relative time values measuring the time
249-- elapsed since the immediate predecessor element of the stream was generated.
250-- The first element of the stream is always 0. @durations@ uses a clock of
251-- granularity @g@ specified in seconds. A low granularity clock is more
252-- expensive in terms of CPU usage. The minimum granularity is 1 millisecond.
253-- Durations lower than 1 ms will be 0.
254--
255-- Note: This API is not safe on 32-bit machines.
256--
257-- /Unimplemented/
258--
259{-# INLINE durations #-}
260durations :: -- Monad m =>
261 Double -> t m RelTime64
262durations = undefined
264-- | Generate a singleton event at or after the specified absolute time. Note
265-- that this is different from a threadDelay, a threadDelay starts from the
266-- time when the action is evaluated, whereas if we use AbsTime based timeout
267-- it will immediately expire if the action is evaluated too late.
268--
269-- /Unimplemented/
270--
271{-# INLINE timeout #-}
272timeout :: -- Monad m =>
273 AbsTime -> t m ()
274timeout = undefined
276------------------------------------------------------------------------------
277-- Iterating functions
278------------------------------------------------------------------------------
280-- |
281-- >>> iterate f x = x `Stream.cons` iterate f x
282--
283-- Generate an infinite stream with @x@ as the first element and each
284-- successive element derived by applying the function @f@ on the previous
285-- element.
286--
287-- >>> Stream.fold Fold.toList $ Stream.take 5 $ Stream.iterate (+1) 1
288-- [1,2,3,4,5]
289--
290-- @since 0.9.0
291{-# INLINE_NORMAL iterate #-}
292iterate :: Monad m => (a -> a) -> a -> Stream m a
293iterate step = fromStreamD . D.iterate step
295-- |
296-- >>> iterateM f m = m >>= \a -> return a `Stream.consM` iterateM f (f a)
297--
298-- Generate an infinite stream with the first element generated by the action
299-- @m@ and each successive element derived by applying the monadic function
300-- @f@ on the previous element.
301--
302-- >>> :{
303-- Stream.iterateM (\x -> print x >> return (x + 1)) (return 0)
304-- & Stream.take 3
305-- & Stream.fold Fold.toList
306-- :}
307-- 0
308-- 1
309-- [0,1,2]
310--
311-- @since 0.9.0
312{-# INLINE iterateM #-}
313iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
314iterateM step = fromStreamD . D.iterateM step
316-- | We can define cyclic structures using @let@:
317--
318-- >>> let (a, b) = ([1, b], head a) in (a, b)
319-- ([1,1],1)
320--
321-- The function @fix@ defined as:
322--
323-- >>> fix f = let x = f x in x
324--
325-- ensures that the argument of a function and its output refer to the same
326-- lazy value @x@ i.e. the same location in memory. Thus @x@ can be defined
327-- in terms of itself, creating structures with cyclic references.
328--
329-- >>> f ~(a, b) = ([1, b], head a)
330-- >>> fix f
331-- ([1,1],1)
332--
333-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
334-- values.
335--
336-- Using 'mfix' for streams we can construct a stream in which each element of
337-- the stream is defined in a cyclic fashion. The argument of the function
338-- being fixed represents the current element of the stream which is being
339-- returned by the stream monad. Thus, we can use the argument to construct
340-- itself.
341--
342-- In the following example, the argument @action@ of the function @f@
343-- represents the tuple @(x,y)@ returned by it in a given iteration. We define
344-- the first element of the tuple in terms of the second.
345--
346-- >>> import Streamly.Internal.Data.Stream as Stream
347-- >>> import System.IO.Unsafe (unsafeInterleaveIO)
348--
349-- >>> :{
350-- main = Stream.fold (Fold.drainBy print) $ Stream.mfix f
351-- where
352-- f action = do
353-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
354-- x <- Stream.sequence $ Stream.fromList [incr 1 action, incr 2 action]
355-- y <- Stream.fromList [4,5]
356-- return (x, y)
357-- :}
358--
359-- Note: you cannot achieve this by just changing the order of the monad
360-- statements because that would change the order in which the stream elements
361-- are generated.
362--
363-- Note that the function @f@ must be lazy in its argument, that's why we use
364-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
365--
366-- /Not fused/
367--
368-- /Pre-release/
369{-# INLINE mfix #-}
370mfix :: Monad m => (m a -> Stream m a) -> Stream m a
371mfix f = fromStreamK $ K.mfix (toStreamK . f)
373------------------------------------------------------------------------------
374-- Conversions
375------------------------------------------------------------------------------
377-- |
378-- >>> fromFoldable = Prelude.foldr Stream.cons Stream.nil
379--
380-- Construct a stream from a 'Foldable' containing pure values:
381--
382-- /Not fused/
383--
384-- @since 0.9.0
385{-# INLINE fromFoldable #-}
386fromFoldable :: Foldable f => f a -> Stream m a
387fromFoldable = fromStreamK . K.fromFoldable
389------------------------------------------------------------------------------
390-- From pointers
391------------------------------------------------------------------------------
393-- | Keep reading 'Storable' elements from 'Ptr' onwards.
394--
395-- /Unsafe:/ The caller is responsible for safe addressing.
396--
397-- /Pre-release/
398{-# INLINE fromPtr #-}
399fromPtr :: (MonadIO m, Storable a) => Ptr a -> Stream m a
400fromPtr = Stream.fromStreamD . D.fromPtr
402-- | Take @n@ 'Storable' elements starting from 'Ptr' onwards.
403--
404-- >>> fromPtrN n = Stream.take n . Stream.fromPtr
405--
406-- /Unsafe:/ The caller is responsible for safe addressing.
407--
408-- /Pre-release/
409{-# INLINE fromPtrN #-}
410fromPtrN :: (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
411fromPtrN n = Stream.fromStreamD . D.take n . D.fromPtr
413-- | Read bytes from an 'Addr#' until a 0 byte is encountered, the 0 byte is
414-- not included in the stream.
415--
416-- >>> fromByteStr# addr = Stream.takeWhile (/= 0) $ Stream.fromPtr $ Ptr addr
417--
418-- /Unsafe:/ The caller is responsible for safe addressing.
419--
420-- Note that this is completely safe when reading from Haskell string
421-- literals because they are guaranteed to be NULL terminated:
422--
423-- >>> Stream.fold Fold.toList $ Stream.fromByteStr# "\1\2\3\0"#
424-- [1,2,3]
425--
426{-# INLINE fromByteStr# #-}
427fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
428fromByteStr# addr =
429 Stream.fromStreamD $ D.takeWhile (/= 0) $ D.fromPtr $ Ptr addr
431-- | Construct a stream by reading an 'Unboxed' 'IORef' repeatedly.
432--
433-- /Pre-release/
434--
435{-# INLINE fromUnboxedIORef #-}
436fromUnboxedIORef :: (MonadIO m, Unboxed a) => Unboxed.IORef a -> Stream m a
437fromUnboxedIORef = fromStreamD . Unboxed.toStreamD