@@ -25,31 +25,33 @@
2525module Streamly.Enumeration
2626 (
2727 Enumerable (..)
28+
29+ -- ** Enumerating 'Bounded' 'Enum' Types
2830 , enumerate
31+ , enumerateTo
32+ , enumerateFromBounded
2933
30− -- ** Enumerating 'Enum' Types
34+ -- ** Enumerating 'Enum' Types not larger than 'Int'
3135 , enumerateFromToSmall
3236 , enumerateFromThenToSmall
3337 , enumerateFromThenSmallBounded
34− , enumerateFromBounded
3538
3639 -- ** Enumerating 'Bounded' 'Integral' Types
3740 , enumerateFromIntegral
3841 , enumerateFromThenIntegral
3942
40− -- ** Enumerating unbounded 'Integral' Types
43+ -- ** Enumerating 'Integral' Types
4144 , enumerateFromToIntegral
4245 , enumerateFromThenToIntegral
46+
47+ -- ** Enumerating unbounded 'Integral' Types
4348 , enumerateFromStepIntegral
4449
45− -- ** Enumerating unbounded 'Fractional' Types
50+ -- ** Enumerating 'Fractional' Types
4651 , enumerateFromFractional
4752 , enumerateFromToFractional
4853 , enumerateFromThenFractional
4954 , enumerateFromThenToFractional
50−
51− -- ** Enumerating unbounded 'Num' Types
52− , enumerateFromStepNum
5355 )
5456where
5557
@@ -72,8 +74,10 @@ import qualified Streamly.Streams.Serial as Serial
7274--
7375-- | @enumerateFromStepIntegral from step@ generates an infinite stream whose
7476-- first element is @from@ and the successive elements are in increments of
75−-- @step@. This does not check for overflow or underflow if the 'Integral' type
76−-- is bounded.
77+-- @step@.
78+--
79+-- CAUTION: This function is not safe for finite integral types. It does not
80+-- check for overflow, underflow or bounds.
7781--
7882-- @
7983-- > S.toList $ S.take 4 $ S.enumerateFromStepIntegral 0 2
@@ -162,30 +166,6 @@ enumerateFromThenToIntegral
162166enumerateFromThenToIntegral from next to =
163167 fromStreamD $ D.enumerateFromThenToIntegral from next to
164168
165−-------------------------------------------------------------------------------
166−-- Enumeration of Num types
167−-------------------------------------------------------------------------------
168−--
169−-- | @enumerateFromStepNum from step@ generates an infinite stream whose first
170−-- element is @from@ and the successive elements are in increments of @step@.
171−-- This is numerically stable but does not check for overflow or underflow for
172−-- bounded types. Note, for 'Integral' types 'enumerateFromStepIntegral' is
173−-- faster.
174−--
175−--
176−-- @
177−-- > S.toList $ S.take 4 $ S.enumerateFromStepNum 0.1 2
178−-- [0.1,2.1,4.1,6.1]
179−-- > S.toList $ S.take 3 $ S.enumerateFromStepNum 0.1 (-2)
180−-- [0.1,-1.9,-3.9,-5.9]
181−-- @
182−--
183−-- @since 0.6.0
184−{-# INLINE enumerateFromStepNum #-}
185−enumerateFromStepNum :: (IsStream t, Monad m, Num a) => a -> a -> t m a
186−enumerateFromStepNum from stride =
187− fromStreamD $ D.enumerateFromStepNum from stride
188−
189169-------------------------------------------------------------------------------
190170-- Enumeration of Fractional types
191171-------------------------------------------------------------------------------
@@ -287,40 +267,35 @@ enumerateFromThenToFractional from next to =
287267 fromStreamD $ D.enumerateFromThenToFractional from next to
288268
289269-------------------------------------------------------------------------------
290−-- Enumeration of Enum types
270+-- Enumeration of Enum types not larger than Int
291271-------------------------------------------------------------------------------
292272--
293−-- | 'enumerateFromTo' for 'Enum' types not larger than 'Int'. This function
294−-- does not check the bounds for 'Bounded' types, it assumes that the @to@
295−-- parameter is constrained by the type to be within the range representable by
296−-- the type.
273+-- | 'enumerateFromTo' for 'Enum' types not larger than 'Int'.
274+--
275+-- @since 0.6.0
297276{-# INLINE enumerateFromToSmall #-}
298277enumerateFromToSmall :: (IsStream t, Monad m, Enum a) => a -> a -> t m a
299278enumerateFromToSmall from to = Serial.map toEnum $
300279 enumerateFromToIntegral (fromEnum from) (fromEnum to)
301280
302−-- | 'enumerateFrom' for 'Bounded' 'Enum' types. This is defined in terms of
303−-- 'enumerateFromTo', therefore it will work even for types larger than 'Int'
304−-- depending on 'enumerateFromTo'.
305−{-# INLINE enumerateFromBounded #-}
306−enumerateFromBounded :: (IsStream t, Monad m, Enumerable a, Bounded a)
307− => a -> t m a
308−enumerateFromBounded from = enumerateFromTo from maxBound
309−
310−-- | 'enumerateFromThenTo' for 'Enum' types not larger than 'Int'. This
311−-- function does not check the bounds for 'Bounded' types, it assumes that the
312−-- @to@ parameter is constrained by the type to be within the range
313−-- representable by the type.
281+-- | 'enumerateFromThenTo' for 'Enum' types not larger than 'Int'.
282+--
283+-- @since 0.6.0
314284{-# INLINE enumerateFromThenToSmall #-}
315285enumerateFromThenToSmall :: (IsStream t, Monad m, Enum a)
316286 => a -> a -> a -> t m a
317287enumerateFromThenToSmall from next to = Serial.map toEnum $
318288 enumerateFromThenToIntegral (fromEnum from) (fromEnum next) (fromEnum to)
319289
320−-- | 'enumerateFromThen' for 'Bounded' 'Enum' types not larger than 'Int'. For
321−-- types smaller than 'Int' we know it is bounded though it may not have a
322−-- 'Bounded' instance. It is not necessary to require 'Bounded' instance for
323−-- all small types, we require it anyway because it is safe that way.
290+-- | 'enumerateFromThen' for 'Enum' types not larger than 'Int'.
291+--
292+-- Note: We convert the 'Enum' to 'Int' and enumerate the 'Int'. If a
293+-- type is bounded but does not have a 'Bounded' instance then we can go on
294+-- enumerating it beyond the legal values of the type, resulting in the failure
295+-- of 'toEnum' when converting back to 'Enum'. Therefore we require a 'Bounded'
296+-- instance for this function to be safely used.
297+--
298+-- @since 0.6.0
324299{-# INLINE enumerateFromThenSmallBounded #-}
325300enumerateFromThenSmallBounded :: (IsStream t, Monad m, Enumerable a, Bounded a)
326301 => a -> a -> t m a
@@ -366,6 +341,7 @@ class Enum a => Enumerable a where
366341 -- [1.1,2.1,3.1,4.1]
367342 -- @
368343 --
344+ -- @since 0.6.0
369345 enumerateFrom :: (IsStream t, Monad m) => a -> t m a
370346
371347 -- | Generate a finite stream starting with the element @from@, enumerating
@@ -387,6 +363,7 @@ class Enum a => Enumerable a where
387363 -- [1.1,2.1,3.1,4.1,5.1]
388364 -- @
389365 --
366+ -- @since 0.6.0
390367 enumerateFromTo :: (IsStream t, Monad m) => a -> a -> t m a
391368
392369 -- | @enumerateFromThen from then@ generates a stream whose first element
@@ -402,6 +379,8 @@ class Enum a => Enumerable a where
402379 -- > S.toList $ S.take 4 $ S.enumerateFromThen 0 (-2)
403380 -- [0,-2,-4,-6]
404381 -- @
382+ --
383+ -- @since 0.6.0
405384 enumerateFromThen :: (IsStream t, Monad m) => a -> a -> t m a
406385
407386 -- | @enumerateFromThenTo from then to@ generates a finite stream whose
@@ -416,8 +395,60 @@ class Enum a => Enumerable a where
416395 -- > S.toList $ S.enumerateFromThenTo 0 (-2) (-6)
417396 -- [0,-2,-4,-6]
418397 -- @
398+ --
399+ -- @since 0.6.0
419400 enumerateFromThenTo :: (IsStream t, Monad m) => a -> a -> a -> t m a
420401
402+-- MAYBE: Sometimes it is more convenient to know the count rather then the
403+-- ending or starting element. For those cases we can define the folllowing
404+-- APIs. All of these will work only for bounded types if we represent the
405+-- count by Int.
406+--
407+-- enumerateN
408+-- enumerateFromN
409+-- enumerateToN
410+-- enumerateFromStep
411+-- enumerateFromStepN
412+
413+-------------------------------------------------------------------------------
414+-- Convenient functions for bounded types
415+-------------------------------------------------------------------------------
416+--
417+-- |
418+-- > enumerate = enumerateFrom minBound
419+--
420+-- Enumerate a 'Bounded' type from its 'minBound' to 'maxBound'
421+--
422+-- @since 0.6.0
423+{-# INLINE enumerate #-}
424+enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a
425+enumerate = enumerateFrom minBound
426+
427+-- |
428+-- > enumerateTo = enumerateFromTo minBound
429+--
430+-- Enumerate a 'Bounded' type from its 'minBound' to specified value.
431+--
432+-- @since 0.6.0
433+{-# INLINE enumerateTo #-}
434+enumerateTo :: (IsStream t, Monad m, Bounded a, Enumerable a) => a -> t m a
435+enumerateTo = enumerateFromTo minBound
436+
437+-- |
438+-- > enumerateFromBounded = enumerateFromTo from maxBound
439+--
440+-- 'enumerateFrom' for 'Bounded' 'Enum' types.
441+--
442+-- @since 0.6.0
443+{-# INLINE enumerateFromBounded #-}
444+enumerateFromBounded :: (IsStream t, Monad m, Enumerable a, Bounded a)
445+ => a -> t m a
446+enumerateFromBounded from = enumerateFromTo from maxBound
447+
448+-------------------------------------------------------------------------------
449+-- Enumerable Instances
450+-------------------------------------------------------------------------------
451+--
421452-- For Enum types smaller than or equal to Int size.
422453#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
423454instance Enumerable SMALL_TYPE where { \
@@ -506,8 +537,9 @@ instance Enumerable a => Enumerable (Identity a) where
506537 enumerateFromThenTo (Identity from) (Identity next) (Identity to) =
507538 Serial.map Identity $ enumerateFromThenTo from next to
508539#endif
509−{-
540+
510541-- TODO
542+{-
511543instance Enumerable a => Enumerable (Last a)
512544instance Enumerable a => Enumerable (First a)
513545instance Enumerable a => Enumerable (Max a)
@@ -516,8 +548,3 @@ instance Enumerable a => Enumerable (Const a b)
516548instance Enumerable (f a) => Enumerable (Alt f a)
517549instance Enumerable (f a) => Enumerable (Ap f a)
518550-}
519−
520−-- | Enumerate a finite ('Bounded') data type from its 'minBound' to 'maxBound'
521−{-# INLINE enumerate #-}
522−enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a
523−enumerate = enumerateFrom minBound