2-- Module : Streamly.Internal.Data.Stream.StreamD.Generate
3-- Copyright : (c) 2020 Composewell Technologies and Contributors
4-- (c) Roman Leshchinskiy 2008-2010
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
10-- Prefer unfolds ("Streamly.Internal.Data.Unfold") over the combinators in
11-- this module. They are more powerful and efficient as they can be transformed
12-- and composed on the input side efficiently and they can fuse in nested
13-- operations (e.g. unfoldMany). All the combinators in this module can be
14-- expressed using unfolds with the same efficiency.
16-- Operations in this module that are not in "Streamly.Internal.Data.Unfold":
17-- generate, times, fromPrimIORef.
19-- We should plan to replace this module with "Streamly.Internal.Data.Unfold"
22-- A few combinators in this module have been adapted from the vector package
23-- (c) Roman Leshchinskiy. See the notes in specific combinators.
25module Streamly.Internal.Data.Stream.StreamD.Generate
49 , enumerateFromStepIntegral
50 , enumerateFromIntegral
51 , enumerateFromThenIntegral
52 , enumerateFromToIntegral
53 , enumerateFromThenToIntegral
55 , enumerateFromStepNum
57 , enumerateFromThenNum
58 , enumerateFromToFractional
59 , enumerateFromThenToFractional
65 -- | Generate a monadic stream from a seed.
76 -- | Transform an input structure into a stream.
78 -- Note: Direct style stream does not support @fromFoldable@.
90import Control.Monad.IO.Class (MonadIO(..))
91import Streamly.Internal.Control.Concurrent (MonadAsync)
92import Streamly.Internal.Data.Time.Clock
93 (Clock(Monotonic), asyncClock, readClock)
94import Streamly.Internal.Data.Time.Units
95 (toAbsTime, AbsTime, toRelTime64, RelTime64)
97import Prelude hiding (iterate, repeat, replicate, takeWhile)
98import Streamly.Internal.Data.Stream.StreamD.Type
100------------------------------------------------------------------------------
102------------------------------------------------------------------------------
104-- | An empty 'Stream'.
105{-# INLINE_NORMAL nil #-}
106nil :: Monad m => Stream m a
107nil = Stream (\_ _ -> return Stop) ()
109-- XXX implement in terms of consM?
110-- cons x = consM (return x)
112-- | Can fuse but has O(n^2) complexity.
113{-# INLINE_NORMAL cons #-}
114cons :: Monad m => a -> Stream m a -> Stream m a
115cons x (Stream step state) = Stream step1 Nothing
117 {-# INLINE_LATE step1 #-}
118 step1 _ Nothing = return $ Yield x (Just state)
119 step1 gst (Just st) = do
123 Yield a s -> Yield a (Just s)
124 Skip s -> Skip (Just s)
127------------------------------------------------------------------------------
129------------------------------------------------------------------------------
131-- Adapted from vector package
132{-# INLINE_NORMAL unfoldrM #-}
133unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
134unfoldrM next = Stream step
136 {-# INLINE_LATE step #-}
140 Just (x, s) -> Yield x s
143{-# INLINE_LATE unfoldr #-}
144unfoldr :: Monad m => (s -> Maybe (a, s)) -> s -> Stream m a
145unfoldr f = unfoldrM (return . f)
147------------------------------------------------------------------------------
149------------------------------------------------------------------------------
151{-# INLINE_NORMAL repeatM #-}
152repeatM :: Monad m => m a -> Stream m a
153repeatM x = Stream (\_ _ -> x >>= \r -> return $ Yield r ()) ()
155{-# INLINE_NORMAL repeat #-}
156repeat :: Monad m => a -> Stream m a
157repeat x = Stream (\_ _ -> return $ Yield x ()) ()
159-- Adapted from the vector package
160{-# INLINE_NORMAL replicateM #-}
161replicateM :: forall m a. Monad m => Int -> m a -> Stream m a
162replicateM n p = Stream step n
164 {-# INLINE_LATE step #-}
166 | i <= 0 = return Stop
169 return $ Yield x (i - 1)
171{-# INLINE_NORMAL replicate #-}
172replicate :: Monad m => Int -> a -> Stream m a
173replicate n x = replicateM n (return x)
175------------------------------------------------------------------------------
177------------------------------------------------------------------------------
179-- | For floating point numbers if the increment is less than the precision then
180-- it just gets lost. Therefore we cannot always increment it correctly by just
182-- 9007199254740992 + 1 + 1 :: Double => 9.007199254740992e15
183-- 9007199254740992 + 2 :: Double => 9.007199254740994e15
185-- Instead we accumulate the increment counter and compute the increment
186-- every time before adding it to the starting number.
188-- This works for Integrals as well as floating point numbers, but
189-- enumerateFromStepIntegral is faster for integrals.
190{-# INLINE_NORMAL enumerateFromStepNum #-}
191enumerateFromStepNum :: (Monad m, Num a) => a -> a -> Stream m a
192enumerateFromStepNum from stride = Stream step 0
194 {-# INLINE_LATE step #-}
195 step _ !i = return $ (Yield $! (from + i * stride)) $! (i + 1)
197{-# INLINE_NORMAL enumerateFromNum #-}
198enumerateFromNum :: (Monad m, Num a) => a -> Stream m a
199enumerateFromNum from = enumerateFromStepNum from 1
201{-# INLINE_NORMAL enumerateFromThenNum #-}
202enumerateFromThenNum :: (Monad m, Num a) => a -> a -> Stream m a
203enumerateFromThenNum from next = enumerateFromStepNum from (next - from)
205------------------------------------------------------------------------------
206-- Enumeration of Integrals
207------------------------------------------------------------------------------
209data EnumState a = EnumInit | EnumYield a a a | EnumStop
211{-# INLINE_NORMAL enumerateFromThenToIntegralUp #-}
212enumerateFromThenToIntegralUp
213 :: (Monad m, Integral a)
214 => a -> a -> a -> Stream m a
215enumerateFromThenToIntegralUp from next to = Stream step EnumInit
217 {-# INLINE_LATE step #-}
223 else Yield from EnumStop
224 else -- from <= next <= to
225 let stride = next - from
226 in Skip $ EnumYield from stride (to - stride)
228 step _ (EnumYield x stride toMinus) =
231 then Yield x EnumStop
232 else Yield x $ EnumYield (x + stride) stride toMinus
234 step _ EnumStop = return Stop
236{-# INLINE_NORMAL enumerateFromThenToIntegralDn #-}
237enumerateFromThenToIntegralDn
238 :: (Monad m, Integral a)
239 => a -> a -> a -> Stream m a
240enumerateFromThenToIntegralDn from next to = Stream step EnumInit
242 {-# INLINE_LATE step #-}
244 return $ if to > next
247 else Yield from EnumStop
248 else -- from >= next >= to
249 let stride = next - from
250 in Skip $ EnumYield from stride (to - stride)
252 step _ (EnumYield x stride toMinus) =
255 then Yield x EnumStop
256 else Yield x $ EnumYield (x + stride) stride toMinus
258 step _ EnumStop = return Stop
260-- XXX This can perhaps be simplified and written in terms of
261-- enumeratFromStepIntegral as we have done in unfolds. But anyway we should be
262-- replacing the stream generation module with unfolds.
263{-# INLINE_NORMAL enumerateFromThenToIntegral #-}
264enumerateFromThenToIntegral
265 :: (Monad m, Integral a)
266 => a -> a -> a -> Stream m a
267enumerateFromThenToIntegral from next to
268 | next >= from = enumerateFromThenToIntegralUp from next to
269 | otherwise = enumerateFromThenToIntegralDn from next to
271{-# INLINE_NORMAL enumerateFromThenIntegral #-}
272enumerateFromThenIntegral
273 :: (Monad m, Integral a, Bounded a)
274 => a -> a -> Stream m a
275enumerateFromThenIntegral from next =
277 then enumerateFromThenToIntegralUp from next maxBound
278 else enumerateFromThenToIntegralDn from next minBound
280-- | Can be used to enumerate unbounded integrals. This does not check for
281-- overflow or underflow for bounded integrals.
283{-# INLINE_NORMAL enumerateFromStepIntegral #-}
284enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
285enumerateFromStepIntegral from stride =
286 from `seq` stride `seq` Stream step from
288 {-# INLINE_LATE step #-}
289 step _ !x = return $ Yield x $! (x + stride)
291-- | Enumerate upwards from @from@ to @to@. We are assuming that "to" is
292-- constrained by the type to be within max/min bounds.
293{-# INLINE enumerateFromToIntegral #-}
294enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
295enumerateFromToIntegral from to =
296 takeWhile (<= to) $ enumerateFromStepIntegral from 1
298{-# INLINE enumerateFromIntegral #-}
299enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
300enumerateFromIntegral from = enumerateFromToIntegral from maxBound
302------------------------------------------------------------------------------
303-- Enumeration of Fractionals
304------------------------------------------------------------------------------
306-- | We cannot write a general function for Num. The only way to write code
307-- portable between the two is to use a 'Real' constraint and convert between
308-- Fractional and Integral using fromRational which is horribly slow.
309{-# INLINE_NORMAL enumerateFromToFractional #-}
310enumerateFromToFractional
311 :: (Monad m, Fractional a, Ord a)
312 => a -> a -> Stream m a
313enumerateFromToFractional from to =
314 takeWhile (<= to + 1 / 2) $ enumerateFromStepNum from 1
316{-# INLINE_NORMAL enumerateFromThenToFractional #-}
317enumerateFromThenToFractional
318 :: (Monad m, Fractional a, Ord a)
319 => a -> a -> a -> Stream m a
320enumerateFromThenToFractional from next to =
321 takeWhile predicate $ enumerateFromThenNum from next
323 mid = (next - from) / 2
324 predicate | next >= from = (<= to + mid)
325 | otherwise = (>= to + mid)
327------------------------------------------------------------------------------
329------------------------------------------------------------------------------
331{-# INLINE_NORMAL times #-}
332times :: MonadAsync m => Double -> Stream m (AbsTime, RelTime64)
333times g = Stream step Nothing
337 {-# INLINE_LATE step #-}
339 clock <- liftIO $ asyncClock Monotonic g
340 a <- liftIO $ readClock clock
341 return $ Skip $ Just (clock, a)
343 step _ s@(Just (clock, t0)) = do
344 a <- liftIO $ readClock clock
345 -- XXX we can perhaps use an AbsTime64 using a 64 bit Int for
346 -- efficiency. or maybe we can use a representation using Double for
347 -- floating precision time
348 return $ Yield (toAbsTime t0, toRelTime64 (a - t0)) s
350-------------------------------------------------------------------------------
352-------------------------------------------------------------------------------
354{-# INLINE_NORMAL fromIndicesM #-}
355fromIndicesM :: Monad m => (Int -> m a) -> Stream m a
356fromIndicesM gen = Stream step 0
358 {-# INLINE_LATE step #-}
361 return $ Yield x (i + 1)
363{-# INLINE fromIndices #-}
364fromIndices :: Monad m => (Int -> a) -> Stream m a
365fromIndices gen = fromIndicesM (return . gen)
367-- Adapted from the vector package
368{-# INLINE_NORMAL generateM #-}
369generateM :: Monad m => Int -> (Int -> m a) -> Stream m a
370generateM n gen = n `seq` Stream step 0
372 {-# INLINE_LATE step #-}
373 step _ i | i < n = do
375 return $ Yield x (i + 1)
376 | otherwise = return Stop
378{-# INLINE generate #-}
379generate :: Monad m => Int -> (Int -> a) -> Stream m a
380generate n gen = generateM n (return . gen)
382-------------------------------------------------------------------------------
384-------------------------------------------------------------------------------
386{-# INLINE_NORMAL iterateM #-}
387iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
388iterateM step = Stream (\_ st -> st >>= \(!x) -> return $ Yield x (step x))
390{-# INLINE_NORMAL iterate #-}
391iterate :: Monad m => (a -> a) -> a -> Stream m a
392iterate step st = iterateM (return . step) (return st)
394-------------------------------------------------------------------------------
396-------------------------------------------------------------------------------
398-- XXX we need the MonadAsync constraint because of a rewrite rule.
399-- | Convert a list of monadic actions to a 'Stream'
400{-# INLINE_LATE fromListM #-}
401fromListM :: MonadAsync m => [m a] -> Stream m a
402fromListM = Stream step
404 {-# INLINE_LATE step #-}
405 step _ (m:ms) = m >>= \x -> return $ Yield x ms
406 step _ [] = return Stop
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