@@ -23,29 +23,38 @@ module Streamly.Internal.Data.Unfold.Enumeration
24 Enumerable (..)
24 Enumerable (..)
26− -- ** Enumerate 'Num' Types
26+ -- ** Enumerating 'Num' Types
27+ , enumerateFromStepNum
27 , enumerateFromNum
28 , enumerateFromNum
28 , enumerateFromThenNum
29 , enumerateFromThenNum
31+ , enumerateFromThenToNum
30− -- ** Enumerating 'Bounded Integral' Types
33+ -- ** Enumerating unbounded 'Integral' Types
31− , enumerateFromIntegralBounded
34+ , enumerateFromStepIntegral
32− , enumerateFromThenIntegralBounded
33− , enumerateFromToIntegralBounded
34− , enumerateFromThenToIntegralBounded
36− -- ** Enumerating 'Unbounded Integral' Types
37 , enumerateFromIntegral
35 , enumerateFromIntegral
38 , enumerateFromThenIntegral
36 , enumerateFromThenIntegral
38+ , enumerateFromToStepIntegral
39 , enumerateFromToIntegral
39 , enumerateFromToIntegral
40 , enumerateFromThenToIntegral
40 , enumerateFromThenToIntegral
42− -- ** Enumerating 'Small Integral' Types
42+ -- ** Enumerating 'Bounded' 'Integral' Types
43− , enumerateFromSmall
43+ , enumerateFromStepIntegralBounded
44− , enumerateFromThenSmall
44+ , enumerateFromIntegralBounded
45+ , enumerateFromThenIntegralBounded
46+ , enumerateFromToIntegralBounded
47+ , enumerateFromThenToIntegralBounded
49+ -- ** Enumerating small 'Integral' Types
50+ -- | Small types are always bounded.
51+ , enumerateFromSmallBounded
52+ , enumerateFromThenSmallBounded
45 , enumerateFromToSmall
53 , enumerateFromToSmall
46 , enumerateFromThenToSmall
54 , enumerateFromThenToSmall
48 -- ** Enumerating 'Fractional' Types
56 -- ** Enumerating 'Fractional' Types
57+ -- | Enumeration of 'Num' specialized to 'Fractional' types.
49 , enumerateFromFractional
58 , enumerateFromFractional
50 , enumerateFromThenFractional
59 , enumerateFromThenFractional
51 , enumerateFromToFractional
60 , enumerateFromToFractional
@@ -67,22 +76,22 @@ import Prelude
67 hiding (map, mapM, takeWhile, take, filter, const, zipWith
76 hiding (map, mapM, takeWhile, take, filter, const, zipWith
68 , drop, dropWhile)
77 , drop, dropWhile)
70−------------------------------------------------------------------------------
72−------------------------------------------------------------------------------
74−-- | Unfolds @(from, next)@ generating an infinite stream starting from @from@
75−-- and @next@ values with a stride of @(next - from)@. After the value
76−-- overflows it keeps enumerating in a cycle:
80-- >>> import qualified Streamly.Prelude as Stream
81-- >>> import qualified Streamly.Prelude as Stream
81-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
82-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
82-- >>> import Streamly.Internal.Data.Unfold.Type
83-- >>> import Streamly.Internal.Data.Unfold.Type
83-- >>> import Data.Word
84-- >>> import Data.Word
86+------------------------------------------------------------------------------
88+------------------------------------------------------------------------------
90+-- | Unfolds @(from, stride)@ generating an infinite stream starting from
91+-- @from@ and incrementing every time by @stride@. For 'Bounded' types, after
92+-- the value overflows it keeps enumerating in a cycle:
85−-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold Unfold.enumerateFromThenNum (255::Word8,0)
94+-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold Unfold.enumerateFromStepNum (255::Word8,1)
86-- [255,0,1,2,3,4,5,6,7,8]
95-- [255,0,1,2,3,4,5,6,7,8]
88-- The implementation is numerically stable for floating point values.
97-- The implementation is numerically stable for floating point values.
@@ -91,13 +100,13 @@ import Prelude
92-- /Internal/
101-- /Internal/
94−{-# INLINE enumerateFromThenNum #-}
103+{-# INLINE enumerateFromStepNum #-}
95−enumerateFromThenNum :: (Monad m, Num a) => Unfold m (a, a) a
104+enumerateFromStepNum :: (Monad m, Num a) => Unfold m (a, a) a
96−enumerateFromThenNum = Unfold step inject
105+enumerateFromStepNum = Unfold step inject
100− inject (!from, !next) = return (from, next - from, 0)
109+ inject (!from, !stride) = return (from, stride, 0)
102 -- Note that the counter "i" is the same type as the type being enumerated.
111 -- Note that the counter "i" is the same type as the type being enumerated.
103 -- It may overflow, for example, if we are enumerating Word8, after 255 the
112 -- It may overflow, for example, if we are enumerating Word8, after 255 the
@@ -108,42 +117,61 @@ enumerateFromThenNum = Unfold step inject
109 (Yield $! (from + i * stride)) $! (from, stride, i + 1)
118 (Yield $! (from + i * stride)) $! (from, stride, i + 1)
120+-- | Same as 'enumerateFromStepNum (from, next)' using a stride of @next - from@:
122+-- >>> enumerateFromThenNum =
123+-- lmap (\(from, next) -> (from, next - from)) enumerateFromStepNum
127+-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold Unfold.enumerateFromThenNum (255::Word8,0)
128+-- [255,0,1,2,3,4,5,6,7,8]
130+-- The implementation is numerically stable for floating point values.
132+-- Note that 'enumerateFromThenIntegral' is faster for integrals.
134+-- Note that in the strange world of floating point numbers, using
135+-- @enumerateFromThenNum (from, from + 1)@ is almost exactly the same as
136+-- @enumerateFromStepNum (from, 1) but not precisely the same. Because @(from +
137+-- 1) - from@ is not exactly 1, it may lose some precision, the loss may also
138+-- be aggregated in each step, if you want that precision then use
139+-- 'enumerateFromStepNum' instead.
143+{-# INLINE enumerateFromThenNum #-}
144+enumerateFromThenNum :: (Monad m, Num a) => Unfold m (a, a) a
111−-- | Same as 'enumerateFromThenNum' using a stride of 1.
145+enumerateFromThenNum =
146+ lmap (\(from, next) -> (from, next - from)) enumerateFromStepNum
148+-- | Same as 'enumerateFromStepNum' using a stride of 1:
150+-- >>> enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum
152+-- Also, same as 'enumerateFromThenNum' using a stride of 1 but see the note in
153+-- 'enumerateFromThenNum' about the loss of precision:
113−-- >> enumerateFromNum = lmap (\from -> (from, from + 1)) enumerateFromThenNum
155+-- >>> enumerateFromNum = lmap (\from -> (from, from + 1)) enumerateFromThenNum
115-- /Internal/
157-- /Internal/
117{-# INLINE enumerateFromNum #-}
159{-# INLINE enumerateFromNum #-}
118enumerateFromNum :: (Monad m, Num a) => Unfold m a a
160enumerateFromNum :: (Monad m, Num a) => Unfold m a a
119−enumerateFromNum = Unfold step inject
161+enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum
121−-- XXX It loses the precisions if we use
122−-- enumerateFromNum = lmap (\from -> (from, from + 1)) enumerateFromThenNum
123−-- Example ‘S.unfold (UF.take 5 $ UF.enumerateFromFractional) 3.9’
124−-- [3.9,4.9,5.9,6.900000000000001,7.900000000000002]
128− inject !from = return (from, 1, 0)
130− {-# INLINE_LATE step #-}
131− step (from, stride, i) =
133− (Yield $! (from + i * stride)) $! (from, stride, i + 1)
135-- | Generate a finite stream starting from a from and next values with
163-- | Generate a finite stream starting from a from and next values with
136−-- stride of (next-from) till to value. The implementation is numerically
164+-- stride of (next-from) up to value. The implementation is numerically
137-- stable for floating point values.
165-- stable for floating point values.
139−-- Note 'enumerateFromStepIntegral' is faster for integrals.
167+-- Note that 'enumerateFromThenToIntegral' is faster for integrals.
141-- /Internal/
169-- /Internal/
143−{-# INLINE enumerateFromThenToNumBounded #-}
171+{-# INLINE enumerateFromThenToNum #-}
144−enumerateFromThenToNumBounded :: (Monad m, Ord a, Fractional a) =>
172+enumerateFromThenToNum :: (Monad m, Ord a, Fractional a) =>
145 Unfold m (a, a, a) a
173 Unfold m (a, a, a) a
146−enumerateFromThenToNumBounded = Unfold step inject
174+enumerateFromThenToNum = Unfold step inject
@@ -168,14 +196,14 @@ enumerateFromThenToNumBounded = Unfold step inject
168-- stride of value 1 will be used. The implementation is numerically
196-- stride of value 1 will be used. The implementation is numerically
169-- stable for floating point values.
197-- stable for floating point values.
171−-- Note 'enumerateFromStepIntegralBounded' is faster for integrals.
199+-- Note that 'enumerateFromToIntegral' is faster for integrals.
173-- /Internal/
201-- /Internal/
175−{-# INLINE enumerateFromToNumBounded #-}
203+{-# INLINE enumerateFromToNum #-}
176−enumerateFromToNumBounded :: (Monad m, Ord a, Fractional a) =>
204+enumerateFromToNum :: (Monad m, Ord a, Fractional a) =>
177 Unfold m (a, a) a
205 Unfold m (a, a) a
178−enumerateFromToNumBounded = Unfold step inject
206+enumerateFromToNum = Unfold step inject
@@ -203,6 +231,39 @@ enumerateFromStepIntegral = Unfold step inject
203 {-# INLINE_LATE step #-}
231 {-# INLINE_LATE step #-}
204 step (x, stride) = return $ Yield x $! (x + stride, stride)
232 step (x, stride) = return $ Yield x $! (x + stride, stride)
234+-- | Can be used to enumerate unbounded integrals. Starting with value from
235+-- with stride of next-from till value of to.
239+{-# INLINE_NORMAL enumerateFromToStepIntegral #-}
240+enumerateFromToStepIntegral :: (Integral a, Monad m) =>
241+ Unfold m (a, a, a) a
242+enumerateFromToStepIntegral = Unfold step inject
244+ inject (from, next, to) =
245+ from `seq` next `seq` to `seq` return (from, next - from, to)
246+ {-# INLINE_LATE step #-}
247+ step (x, stride, to) = return $
250+ if x <= to then Yield x $! (x, stride, to) else Stop
256+ then Yield x $! (x + stride, stride, to)
260+ then Yield x $! (x + stride, stride, to)
263+------------------------------------------------------------------------------
264+-- Enumeration of Bounded Integrals
265+------------------------------------------------------------------------------
206-- | Can be used to enumerate bounded integrals from starting from with
267-- | Can be used to enumerate bounded integrals from starting from with
207-- stride of (next-from) . This check for overflow or underflow for
268-- stride of (next-from) . This check for overflow or underflow for
208-- bounded integrals.
269-- bounded integrals.
@@ -265,35 +326,6 @@ enumerateFromToStepIntegralBounded = Unfold step inject
265 then Yield x $! (x + stride, stride, to)
326 then Yield x $! (x + stride, stride, to)
266 else Stop
327 else Stop
268−-- | Can be used to enumerate unbounded integrals. Startting with value from
269−-- with stride of next-from till value of to.
273−{-# INLINE_NORMAL enumerateFromToStepIntegral #-}
274−enumerateFromToStepIntegral :: (Integral a, Monad m) =>
275− Unfold m (a, a, a) a
276−enumerateFromToStepIntegral = Unfold step inject
278− inject (from, next, to) =
279− from `seq` next `seq` to `seq` return (from, next - from, to)
280− {-# INLINE_LATE step #-}
281− step (x, stride, to) = return $
284− if x <= to then Yield x $! (x, stride, to) else Stop
290− then Yield x $! (x + stride, stride, to)
294− then Yield x $! (x + stride, stride, to)
297-- Enumerate Unbounded Integrals ----------------------------------------------
329-- Enumerate Unbounded Integrals ----------------------------------------------
298{-# INLINE enumerateFromIntegral #-}
330{-# INLINE enumerateFromIntegral #-}
299enumerateFromIntegral :: (Monad m, Integral a) => Unfold m a a
331enumerateFromIntegral :: (Monad m, Integral a) => Unfold m a a
@@ -340,7 +372,7 @@ enumerateFromThenToIntegralBounded = enumerateFromToStepIntegralBounded
341{-# INLINE_NORMAL enumerateFromFractional #-}
373{-# INLINE_NORMAL enumerateFromFractional #-}
342enumerateFromFractional :: (Monad m, Fractional a) => Unfold m a a
374enumerateFromFractional :: (Monad m, Fractional a) => Unfold m a a
343−enumerateFromFractional = enumerateFromNum
375+enumerateFromFractional = enumerateFromNum
345{-# INLINE_NORMAL enumerateFromThenFractional #-}
377{-# INLINE_NORMAL enumerateFromThenFractional #-}
346enumerateFromThenFractional :: (Monad m, Fractional a) => Unfold m (a, a) a
378enumerateFromThenFractional :: (Monad m, Fractional a) => Unfold m (a, a) a
@@ -349,12 +381,128 @@ enumerateFromThenFractional = enumerateFromThenNum
349{-# INLINE_NORMAL enumerateFromToFractional #-}
381{-# INLINE_NORMAL enumerateFromToFractional #-}
350enumerateFromToFractional :: (Monad m, Fractional a, Ord a) =>
382enumerateFromToFractional :: (Monad m, Fractional a, Ord a) =>
351 Unfold m (a, a) a
383 Unfold m (a, a) a
352−enumerateFromToFractional = enumerateFromToNumBounded
384+enumerateFromToFractional = enumerateFromToNum
354{-# INLINE_NORMAL enumerateFromThenToFractional #-}
386{-# INLINE_NORMAL enumerateFromThenToFractional #-}
355−enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) =>
387+enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) =>
356 Unfold m (a, a, a) a
388 Unfold m (a, a, a) a
357−enumerateFromThenToFractional = enumerateFromThenToNumBounded
389+enumerateFromThenToFractional = enumerateFromThenToNum
391+-------------------------------------------------------------------------------
392+-- Enumeration of Enum types not larger than Int
393+-------------------------------------------------------------------------------
395+-- XXX should we check for bounds here? Otherwise it will cycle back to "to" if
398+-- | Enumerate from given starting Enum value 'from' and to Enum value 'to'
399+-- with stride of 1 till to value.
403+{-# INLINE enumerateFromToSmall #-}
404+enumerateFromToSmall :: (Monad m, Enum a) => Unfold m (a, a) a
405+enumerateFromToSmall = map toEnum $
411+ `seq` return (fromEnum from, 1, fromEnum to)
412+ {-# INLINE_LATE step #-}
413+ step (x, stride, to) = return $
414+ if x <= to then Yield x $! (x + stride, stride, to) else Stop
416+-- | Enumerate from given starting Enum value 'from' and then Enum value 'next'
417+-- and to Enum value 'to' with stride of (fromEnum next - fromEnum from)
422+{-# INLINE enumerateFromThenToSmall #-}
423+enumerateFromThenToSmall :: (Monad m, Enum a) => Unfold m (a, a, a) a
424+enumerateFromThenToSmall = map toEnum $
427+ inject (from, next, to) =
432+ (fromEnum from, fromEnum next - fromEnum from, fromEnum to)
433+ {-# INLINE_LATE step #-}
434+ step (x, stride, to) = return $
437+ if x <= to then Yield x $! (x, stride, to) else Stop
443+ then Yield x $! (x + stride, stride, to)
446+ if x >= 0 && x >= to
447+ then Yield x $! (x + stride, stride, to)
450+-------------------------------------------------------------------------------
451+-- Bounded Enumeration of Enum types not larger than Int
452+-------------------------------------------------------------------------------
454+-- | Enumerate from given starting Enum value 'from' with stride of 1 till
459+{-# INLINE enumerateFromSmallBounded #-}
460+enumerateFromSmallBounded :: forall a m. (Monad m, Bounded a, Enum a) => Unfold m a a
461+enumerateFromSmallBounded = map toEnum $
466+ `seq` return (fromEnum from, 1, fromEnum (maxBound :: a))
467+ {-# INLINE_LATE step #-}
468+ step (x, stride, to) = return $
469+ if x <= to then Yield x $! (x + stride, stride, to) else Stop
471+-- | Enumerate from given starting Enum value 'from' and next Enum value 'next'
472+-- with stride of (fromEnum next - fromEnum from) till maxBound.
476+{-# INLINE enumerateFromThenSmallBounded #-}
477+enumerateFromThenSmallBounded :: forall a m. (Monad m, Bounded a, Enum a) =>
479+enumerateFromThenSmallBounded = map toEnum $
482+ inject (from, next) =
487+ , fromEnum next - fromEnum from
488+ , fromEnum (maxBound :: a)
490+ {-# INLINE_LATE step #-}
491+ step (x, stride, to) = return $
494+ if x <= to then Yield x $! (x, stride, to) else Stop
500+ then Yield x $! (x + stride, stride, to)
504+ then Yield x $! (x + stride, stride, to)
359-------------------------------------------------------------------------------
507-------------------------------------------------------------------------------
360-- Enumerable type class
508-- Enumerable type class
@@ -463,115 +611,6 @@ class Enum a => Enumerable a where
463 -- /Pre-release/
611 -- /Pre-release/
464 enumerateFromThenTo :: Monad m => Unfold m (a, a, a) a
612 enumerateFromThenTo :: Monad m => Unfold m (a, a, a) a
466−-------------------------------------------------------------------------------
467−-- Enumeration of Enum types not larger than Int
468−-------------------------------------------------------------------------------
470−-- | Enumerate from given starting Enum value 'from' with stride of 1 till
475−{-# INLINE enumerateFromSmall #-}
476−enumerateFromSmall :: forall a m. (Monad m, Bounded a, Enum a) => Unfold m a a
477−enumerateFromSmall = map toEnum $
482− `seq` return (fromEnum from, 1, fromEnum (maxBound :: a))
483− {-# INLINE_LATE step #-}
484− step (x, stride, to) = return $
485− if x <= to then Yield x $! (x + stride, stride, to) else Stop
487−-- | Enumerate from given starting Enum value 'from' and next Enum value 'next'
488−-- with stride of (fromEnum next - fromEnum from) till maxBound.
492−{-# INLINE enumerateFromThenSmall #-}
493−enumerateFromThenSmall :: forall a m. (Monad m, Bounded a, Enum a) =>
495−enumerateFromThenSmall = map toEnum $
498− inject (from, next) =
503− , fromEnum next - fromEnum from
504− , fromEnum (maxBound :: a)
506− {-# INLINE_LATE step #-}
507− step (x, stride, to) = return $
510− if x <= to then Yield x $! (x, stride, to) else Stop
516− then Yield x $! (x + stride, stride, to)
520− then Yield x $! (x + stride, stride, to)
523−-- | Enumerate from given starting Enum value 'from' and to Enum value 'to'
524−-- with stride of 1 till to value.
528−{-# INLINE enumerateFromToSmall #-}
529−enumerateFromToSmall :: (Monad m, Enum a) => Unfold m (a, a) a
530−enumerateFromToSmall = map toEnum $
536− `seq` return (fromEnum from, 1, fromEnum to)
537− {-# INLINE_LATE step #-}
538− step (x, stride, to) = return $
539− if x <= to then Yield x $! (x + stride, stride, to) else Stop
541−-- | Enumerate from given starting Enum value 'from' and then Enum value 'next'
542−-- and to Enum value 'to' with stride of (fromEnum next - fromEnum from)
547−{-# INLINE enumerateFromThenToSmall #-}
548−enumerateFromThenToSmall :: (Monad m, Enum a) => Unfold m (a, a, a) a
549−enumerateFromThenToSmall = map toEnum $
552− inject (from, next, to) =
557− (fromEnum from, fromEnum next - fromEnum from, fromEnum to)
558− {-# INLINE_LATE step #-}
559− step (x, stride, to) = return $
562− if x <= to then Yield x $! (x, stride, to) else Stop
568− then Yield x $! (x + stride, stride, to)
571− if x >= 0 && x >= to
572− then Yield x $! (x + stride, stride, to)
575-------------------------------------------------------------------------------
614-------------------------------------------------------------------------------
576-- Enumerable Instances
615-- Enumerable Instances
577-------------------------------------------------------------------------------
616-------------------------------------------------------------------------------
@@ -580,9 +619,9 @@ enumerateFromThenToSmall = map toEnum $
580#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
619#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
581instance Enumerable SMALL_TYPE where { \
620instance Enumerable SMALL_TYPE where { \
582 {-# INLINE enumerateFrom #-}; \
621 {-# INLINE enumerateFrom #-}; \
583− enumerateFrom = enumerateFromSmall; \
622+ enumerateFrom = enumerateFromSmallBounded; \
584 {-# INLINE enumerateFromThen #-}; \
623 {-# INLINE enumerateFromThen #-}; \
585− enumerateFromThen = enumerateFromThenSmall; \
624+ enumerateFromThen = enumerateFromThenSmallBounded; \
586 {-# INLINE enumerateFromTo #-}; \
625 {-# INLINE enumerateFromTo #-}; \
587 enumerateFromTo = enumerateFromToSmall; \
626 enumerateFromTo = enumerateFromToSmall; \
588 {-# INLINE enumerateFromThenTo #-}; \
627 {-# INLINE enumerateFromThenTo #-}; \