@@ -23,29 +23,38 @@ module Streamly.Internal.Data.Unfold.Enumeration
2323 (
2424 Enumerable (..)
2525
26− -- ** Enumerate 'Num' Types
26+ -- ** Enumerating 'Num' Types
27+ , enumerateFromStepNum
2728 , enumerateFromNum
2829 , enumerateFromThenNum
30+ , enumerateFromToNum
31+ , enumerateFromThenToNum
2932
30− -- ** Enumerating 'Bounded Integral' Types
31− , enumerateFromIntegralBounded
32− , enumerateFromThenIntegralBounded
33− , enumerateFromToIntegralBounded
34− , enumerateFromThenToIntegralBounded
35−
36− -- ** Enumerating 'Unbounded Integral' Types
33+ -- ** Enumerating unbounded 'Integral' Types
34+ , enumerateFromStepIntegral
3735 , enumerateFromIntegral
3836 , enumerateFromThenIntegral
37+
38+ , enumerateFromToStepIntegral
3939 , enumerateFromToIntegral
4040 , enumerateFromThenToIntegral
4141
42− -- ** Enumerating 'Small Integral' Types
43− , enumerateFromSmall
44− , enumerateFromThenSmall
42+ -- ** Enumerating 'Bounded' 'Integral' Types
43+ , enumerateFromStepIntegralBounded
44+ , enumerateFromIntegralBounded
45+ , enumerateFromThenIntegralBounded
46+ , enumerateFromToIntegralBounded
47+ , enumerateFromThenToIntegralBounded
48+
49+ -- ** Enumerating small 'Integral' Types
50+ -- | Small types are always bounded.
51+ , enumerateFromSmallBounded
52+ , enumerateFromThenSmallBounded
4553 , enumerateFromToSmall
4654 , enumerateFromThenToSmall
4755
4856 -- ** Enumerating 'Fractional' Types
57+ -- | Enumeration of 'Num' specialized to 'Fractional' types.
4958 , enumerateFromFractional
5059 , enumerateFromThenFractional
5160 , enumerateFromToFractional
@@ -67,22 +76,22 @@ import Prelude
6776 hiding (map, mapM, takeWhile, take, filter, const, zipWith
6877 , drop, dropWhile)
6978
70−------------------------------------------------------------------------------
71−-- Enumeration of Num
72−------------------------------------------------------------------------------
73−
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:
77−--
7879-- $setup
7980-- >>> :m
8081-- >>> import qualified Streamly.Prelude as Stream
8182-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
8283-- >>> import Streamly.Internal.Data.Unfold.Type
8384-- >>> import Data.Word
85+
86+------------------------------------------------------------------------------
87+-- Enumeration of Num
88+------------------------------------------------------------------------------
89+
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:
8493--
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)
8695-- [255,0,1,2,3,4,5,6,7,8]
8796--
8897-- The implementation is numerically stable for floating point values.
@@ -91,13 +100,13 @@ import Prelude
91100--
92101-- /Internal/
93102--
94−{-# INLINE enumerateFromThenNum #-}
95−enumerateFromThenNum :: (Monad m, Num a) => Unfold m (a, a) a
96−enumerateFromThenNum = Unfold step inject
103+{-# INLINE enumerateFromStepNum #-}
104+enumerateFromStepNum :: (Monad m, Num a) => Unfold m (a, a) a
105+enumerateFromStepNum = Unfold step inject
97106
98107 where
99108
100− inject (!from, !next) = return (from, next - from, 0)
109+ inject (!from, !stride) = return (from, stride, 0)
101110
102111 -- Note that the counter "i" is the same type as the type being enumerated.
103112 -- It may overflow, for example, if we are enumerating Word8, after 255 the
@@ -108,42 +117,61 @@ enumerateFromThenNum = Unfold step inject
108117 return $
109118 (Yield $! (from + i * stride)) $! (from, stride, i + 1)
110119
111−-- | Same as 'enumerateFromThenNum' using a stride of 1.
120+-- | Same as 'enumerateFromStepNum (from, next)' using a stride of @next - from@:
121+--
122+-- >>> enumerateFromThenNum =
123+-- lmap (\(from, next) -> (from, next - from)) enumerateFromStepNum
124+--
125+-- Example:
126+--
127+-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold Unfold.enumerateFromThenNum (255::Word8,0)
128+-- [255,0,1,2,3,4,5,6,7,8]
129+--
130+-- The implementation is numerically stable for floating point values.
131+--
132+-- Note that 'enumerateFromThenIntegral' is faster for integrals.
133+--
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.
140+--
141+-- /Internal/
142+--
143+{-# INLINE enumerateFromThenNum #-}
144+enumerateFromThenNum :: (Monad m, Num a) => Unfold m (a, a) a
145+enumerateFromThenNum =
146+ lmap (\(from, next) -> (from, next - from)) enumerateFromStepNum
147+
148+-- | Same as 'enumerateFromStepNum' using a stride of 1:
149+--
150+-- >>> enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum
112151--
113−-- >> enumerateFromNum = lmap (\from -> (from, from + 1)) enumerateFromThenNum
152+-- Also, same as 'enumerateFromThenNum' using a stride of 1 but see the note in
153+-- 'enumerateFromThenNum' about the loss of precision:
154+--
155+-- >>> enumerateFromNum = lmap (\from -> (from, from + 1)) enumerateFromThenNum
114156--
115157-- /Internal/
116158--
117159{-# INLINE enumerateFromNum #-}
118160enumerateFromNum :: (Monad m, Num a) => Unfold m a a
119−enumerateFromNum = Unfold step inject
120−
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]
125−
126− where
127−
128− inject !from = return (from, 1, 0)
129−
130− {-# INLINE_LATE step #-}
131− step (from, stride, i) =
132− return $
133− (Yield $! (from + i * stride)) $! (from, stride, i + 1)
161+enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum
134162
135163-- | 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
137165-- stable for floating point values.
138166--
139−-- Note 'enumerateFromStepIntegral' is faster for integrals.
167+-- Note that 'enumerateFromThenToIntegral' is faster for integrals.
140168--
141169-- /Internal/
142170--
143−{-# INLINE enumerateFromThenToNumBounded #-}
144−enumerateFromThenToNumBounded :: (Monad m, Ord a, Fractional a) =>
171+{-# INLINE enumerateFromThenToNum #-}
172+enumerateFromThenToNum :: (Monad m, Ord a, Fractional a) =>
145173 Unfold m (a, a, a) a
146−enumerateFromThenToNumBounded = Unfold step inject
174+enumerateFromThenToNum = Unfold step inject
147175
148176 where
149177
@@ -168,14 +196,14 @@ enumerateFromThenToNumBounded = Unfold step inject
168196-- stride of value 1 will be used. The implementation is numerically
169197-- stable for floating point values.
170198--
171−-- Note 'enumerateFromStepIntegralBounded' is faster for integrals.
199+-- Note that 'enumerateFromToIntegral' is faster for integrals.
172200--
173201-- /Internal/
174202--
175−{-# INLINE enumerateFromToNumBounded #-}
176−enumerateFromToNumBounded :: (Monad m, Ord a, Fractional a) =>
203+{-# INLINE enumerateFromToNum #-}
204+enumerateFromToNum :: (Monad m, Ord a, Fractional a) =>
177205 Unfold m (a, a) a
178−enumerateFromToNumBounded = Unfold step inject
206+enumerateFromToNum = Unfold step inject
179207
180208 where
181209
@@ -203,6 +231,39 @@ enumerateFromStepIntegral = Unfold step inject
203231 {-# INLINE_LATE step #-}
204232 step (x, stride) = return $ Yield x $! (x + stride, stride)
205233
234+-- | Can be used to enumerate unbounded integrals. Starting with value from
235+-- with stride of next-from till value of to.
236+--
237+-- /Internal/
238+--
239+{-# INLINE_NORMAL enumerateFromToStepIntegral #-}
240+enumerateFromToStepIntegral :: (Integral a, Monad m) =>
241+ Unfold m (a, a, a) a
242+enumerateFromToStepIntegral = Unfold step inject
243+ where
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 $
248+ if stride == 0
249+ then
250+ if x <= to then Yield x $! (x, stride, to) else Stop
251+
252+ else
253+ if stride > 0
254+ then
255+ if x <= to
256+ then Yield x $! (x + stride, stride, to)
257+ else Stop
258+ else
259+ if x >= to
260+ then Yield x $! (x + stride, stride, to)
261+ else Stop
262+
263+------------------------------------------------------------------------------
264+-- Enumeration of Bounded Integrals
265+------------------------------------------------------------------------------
266+
206267-- | Can be used to enumerate bounded integrals from starting from with
207268-- stride of (next-from) . This check for overflow or underflow for
208269-- bounded integrals.
@@ -265,35 +326,6 @@ enumerateFromToStepIntegralBounded = Unfold step inject
265326 then Yield x $! (x + stride, stride, to)
266327 else Stop
267328
268−-- | Can be used to enumerate unbounded integrals. Startting with value from
269−-- with stride of next-from till value of to.
270−--
271−-- /Internal/
272−--
273−{-# INLINE_NORMAL enumerateFromToStepIntegral #-}
274−enumerateFromToStepIntegral :: (Integral a, Monad m) =>
275− Unfold m (a, a, a) a
276−enumerateFromToStepIntegral = Unfold step inject
277− where
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 $
282− if stride == 0
283− then
284− if x <= to then Yield x $! (x, stride, to) else Stop
285−
286− else
287− if stride > 0
288− then
289− if x <= to
290− then Yield x $! (x + stride, stride, to)
291− else Stop
292− else
293− if x >= to
294− then Yield x $! (x + stride, stride, to)
295− else Stop
296−
297329-- Enumerate Unbounded Integrals ----------------------------------------------
298330{-# INLINE enumerateFromIntegral #-}
299331enumerateFromIntegral :: (Monad m, Integral a) => Unfold m a a
@@ -340,7 +372,7 @@ enumerateFromThenToIntegralBounded = enumerateFromToStepIntegralBounded
340372
341373{-# INLINE_NORMAL enumerateFromFractional #-}
342374enumerateFromFractional :: (Monad m, Fractional a) => Unfold m a a
343−enumerateFromFractional = enumerateFromNum
375+enumerateFromFractional = enumerateFromNum
344376
345377{-# INLINE_NORMAL enumerateFromThenFractional #-}
346378enumerateFromThenFractional :: (Monad m, Fractional a) => Unfold m (a, a) a
@@ -349,12 +381,128 @@ enumerateFromThenFractional = enumerateFromThenNum
349381{-# INLINE_NORMAL enumerateFromToFractional #-}
350382enumerateFromToFractional :: (Monad m, Fractional a, Ord a) =>
351383 Unfold m (a, a) a
352−enumerateFromToFractional = enumerateFromToNumBounded
384+enumerateFromToFractional = enumerateFromToNum
353385
354386{-# INLINE_NORMAL enumerateFromThenToFractional #-}
355−enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) =>
387+enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) =>
356388 Unfold m (a, a, a) a
357−enumerateFromThenToFractional = enumerateFromThenToNumBounded
389+enumerateFromThenToFractional = enumerateFromThenToNum
390+
391+-------------------------------------------------------------------------------
392+-- Enumeration of Enum types not larger than Int
393+-------------------------------------------------------------------------------
394+
395+-- XXX should we check for bounds here? Otherwise it will cycle back to "to" if
396+-- to is smaller?
397+--
398+-- | Enumerate from given starting Enum value 'from' and to Enum value 'to'
399+-- with stride of 1 till to value.
400+--
401+-- /Internal/
402+--
403+{-# INLINE enumerateFromToSmall #-}
404+enumerateFromToSmall :: (Monad m, Enum a) => Unfold m (a, a) a
405+enumerateFromToSmall = map toEnum $
406+ Unfold step inject
407+ where
408+ inject (from, to) =
409+ fromEnum from
410+ `seq` fromEnum to
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
415+
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)
418+-- till to value.
419+--
420+-- /Internal/
421+--
422+{-# INLINE enumerateFromThenToSmall #-}
423+enumerateFromThenToSmall :: (Monad m, Enum a) => Unfold m (a, a, a) a
424+enumerateFromThenToSmall = map toEnum $
425+ Unfold step inject
426+ where
427+ inject (from, next, to) =
428+ fromEnum from
429+ `seq` fromEnum next
430+ `seq` fromEnum to
431+ `seq` return
432+ (fromEnum from, fromEnum next - fromEnum from, fromEnum to)
433+ {-# INLINE_LATE step #-}
434+ step (x, stride, to) = return $
435+ if stride == 0
436+ then
437+ if x <= to then Yield x $! (x, stride, to) else Stop
438+
439+ else
440+ if stride > 0
441+ then
442+ if x <= to
443+ then Yield x $! (x + stride, stride, to)
444+ else Stop
445+ else
446+ if x >= 0 && x >= to
447+ then Yield x $! (x + stride, stride, to)
448+ else Stop
449+
450+-------------------------------------------------------------------------------
451+-- Bounded Enumeration of Enum types not larger than Int
452+-------------------------------------------------------------------------------
453+
454+-- | Enumerate from given starting Enum value 'from' with stride of 1 till
455+-- maxBound
456+--
457+-- /Internal/
458+--
459+{-# INLINE enumerateFromSmallBounded #-}
460+enumerateFromSmallBounded :: forall a m. (Monad m, Bounded a, Enum a) => Unfold m a a
461+enumerateFromSmallBounded = map toEnum $
462+ Unfold step inject
463+ where
464+ inject from =
465+ fromEnum from
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
470+
471+-- | Enumerate from given starting Enum value 'from' and next Enum value 'next'
472+-- with stride of (fromEnum next - fromEnum from) till maxBound.
473+--
474+-- /Internal/
475+--
476+{-# INLINE enumerateFromThenSmallBounded #-}
477+enumerateFromThenSmallBounded :: forall a m. (Monad m, Bounded a, Enum a) =>
478+ Unfold m (a, a) a
479+enumerateFromThenSmallBounded = map toEnum $
480+ Unfold step inject
481+ where
482+ inject (from, next) =
483+ fromEnum from
484+ `seq` fromEnum next
485+ `seq` return
486+ ( fromEnum from
487+ , fromEnum next - fromEnum from
488+ , fromEnum (maxBound :: a)
489+ )
490+ {-# INLINE_LATE step #-}
491+ step (x, stride, to) = return $
492+ if stride == 0
493+ then
494+ if x <= to then Yield x $! (x, stride, to) else Stop
495+
496+ else
497+ if stride > 0
498+ then
499+ if x <= to
500+ then Yield x $! (x + stride, stride, to)
501+ else Stop
502+ else
503+ if x >= 0
504+ then Yield x $! (x + stride, stride, to)
505+ else Stop
358506
359507-------------------------------------------------------------------------------
360508-- Enumerable type class
@@ -463,115 +611,6 @@ class Enum a => Enumerable a where
463611 -- /Pre-release/
464612 enumerateFromThenTo :: Monad m => Unfold m (a, a, a) a
465613
466−-------------------------------------------------------------------------------
467−-- Enumeration of Enum types not larger than Int
468−-------------------------------------------------------------------------------
469−
470−-- | Enumerate from given starting Enum value 'from' with stride of 1 till
471−-- maxBound
472−--
473−-- /Internal/
474−--
475−{-# INLINE enumerateFromSmall #-}
476−enumerateFromSmall :: forall a m. (Monad m, Bounded a, Enum a) => Unfold m a a
477−enumerateFromSmall = map toEnum $
478− Unfold step inject
479− where
480− inject from =
481− fromEnum from
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
486−
487−-- | Enumerate from given starting Enum value 'from' and next Enum value 'next'
488−-- with stride of (fromEnum next - fromEnum from) till maxBound.
489−--
490−-- /Internal/
491−--
492−{-# INLINE enumerateFromThenSmall #-}
493−enumerateFromThenSmall :: forall a m. (Monad m, Bounded a, Enum a) =>
494− Unfold m (a, a) a
495−enumerateFromThenSmall = map toEnum $
496− Unfold step inject
497− where
498− inject (from, next) =
499− fromEnum from
500− `seq` fromEnum next
501− `seq` return
502− ( fromEnum from
503− , fromEnum next - fromEnum from
504− , fromEnum (maxBound :: a)
505− )
506− {-# INLINE_LATE step #-}
507− step (x, stride, to) = return $
508− if stride == 0
509− then
510− if x <= to then Yield x $! (x, stride, to) else Stop
511−
512− else
513− if stride > 0
514− then
515− if x <= to
516− then Yield x $! (x + stride, stride, to)
517− else Stop
518− else
519− if x >= 0
520− then Yield x $! (x + stride, stride, to)
521− else Stop
522−
523−-- | Enumerate from given starting Enum value 'from' and to Enum value 'to'
524−-- with stride of 1 till to value.
525−--
526−-- /Internal/
527−--
528−{-# INLINE enumerateFromToSmall #-}
529−enumerateFromToSmall :: (Monad m, Enum a) => Unfold m (a, a) a
530−enumerateFromToSmall = map toEnum $
531− Unfold step inject
532− where
533− inject (from, to) =
534− fromEnum from
535− `seq` fromEnum to
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
540−
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)
543−-- till to value.
544−--
545−-- /Internal/
546−--
547−{-# INLINE enumerateFromThenToSmall #-}
548−enumerateFromThenToSmall :: (Monad m, Enum a) => Unfold m (a, a, a) a
549−enumerateFromThenToSmall = map toEnum $
550− Unfold step inject
551− where
552− inject (from, next, to) =
553− fromEnum from
554− `seq` fromEnum next
555− `seq` fromEnum to
556− `seq` return
557− (fromEnum from, fromEnum next - fromEnum from, fromEnum to)
558− {-# INLINE_LATE step #-}
559− step (x, stride, to) = return $
560− if stride == 0
561− then
562− if x <= to then Yield x $! (x, stride, to) else Stop
563−
564− else
565− if stride > 0
566− then
567− if x <= to
568− then Yield x $! (x + stride, stride, to)
569− else Stop
570− else
571− if x >= 0 && x >= to
572− then Yield x $! (x + stride, stride, to)
573− else Stop
574−
575614-------------------------------------------------------------------------------
576615-- Enumerable Instances
577616-------------------------------------------------------------------------------
@@ -580,9 +619,9 @@ enumerateFromThenToSmall = map toEnum $
580619#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
581620instance Enumerable SMALL_TYPE where { \
582621 {-# INLINE enumerateFrom #-}; \
583− enumerateFrom = enumerateFromSmall; \
622+ enumerateFrom = enumerateFromSmallBounded; \
584623 {-# INLINE enumerateFromThen #-}; \
585− enumerateFromThen = enumerateFromThenSmall; \
624+ enumerateFromThen = enumerateFromThenSmallBounded; \
586625 {-# INLINE enumerateFromTo #-}; \
587626 enumerateFromTo = enumerateFromToSmall; \
588627 {-# INLINE enumerateFromThenTo #-}; \