on master help sign in
Move enumeration functions in a separate module
commitbcd787e710c5e65acb80b02102d2b9f9dc7402ef authorHarendra Kumar <harendra.kumar@gmail.com> dateSat 22 Dec 2018, 21:24 (8 years ago) parentfdf5b29
4 files changed+590−481
src/Streamly/Enumeration.hs+523 src/Streamly/Prelude.hs+3−433 src/Streamly/Streams/StreamD.hs+63−48 streamly.cabal+1
src/Streamly/Enumeration.hsnew file+523
@@ -0,0 +1,523 @@
1+{-# LANGUAGE CPP #-}
2+
3+-- |
4+-- Module : Streamly.Enumeration
5+-- Copyright : (c) 2018 Harendra Kumar
6+--
7+-- License : BSD3
8+-- Maintainer : harendra.kumar@gmail.com
9+-- Stability : experimental
10+-- Portability : GHC
11+--
12+-- The functions defined in this module should be rarely needed for direct use,
13+-- try to use the operations from the 'Enumerable' type class
14+-- instances instead.
15+--
16+-- This module provides an 'Enumerable' type class to enumerate 'Enum' types
17+-- into a stream. The operations in this type class correspond to similar
18+-- perations in the 'Enum' type class, the only difference is that they produce
19+-- a stream instead of a list. These operations cannot be defined generically
20+-- based on the 'Enum' type class. We provide instances for commonly used
21+-- types. If instances for other types are needed convenience functions defined
22+-- in this module can be used to define them. Alternatively, these functions
23+-- can be used directly.
24+
25+module Streamly.Enumeration
26+ (
27+ Enumerable (..)
28+ , enumerate
29+
30+ -- ** Enumerating 'Enum' Types
31+ , enumerateFromToSmall
32+ , enumerateFromThenToSmall
33+ , enumerateFromThenSmallBounded
34+ , enumerateFromBounded
35+
36+ -- ** Enumerating 'Bounded' 'Integral' Types
37+ , enumerateFromIntegral
38+ , enumerateFromThenIntegral
39+
40+ -- ** Enumerating unbounded 'Integral' Types
41+ , enumerateFromToIntegral
42+ , enumerateFromThenToIntegral
43+ , enumerateFromStepIntegral
44+
45+ -- ** Enumerating unbounded 'Fractional' Types
46+ , enumerateFromFractional
47+ , enumerateFromToFractional
48+ , enumerateFromThenFractional
49+ , enumerateFromThenToFractional
50+
51+ -- ** Enumerating unbounded 'Num' Types
52+ , enumerateFromStepNum
53+ )
54+where
55+
56+import Data.Fixed
57+import Data.Int
58+import Data.Ratio
59+import Data.Word
60+import Numeric.Natural
61+import Data.Functor.Identity (Identity(..))
62+
63+import Streamly.Streams.StreamD (fromStreamD)
64+import Streamly.Streams.StreamK (IsStream(..))
65+
66+import qualified Streamly.Streams.StreamD as D
67+import qualified Streamly.Streams.Serial as Serial
68+
69+-------------------------------------------------------------------------------
70+-- Enumeration of Integral types
71+-------------------------------------------------------------------------------
72+--
73+-- | @enumerateFromStepIntegral from step@ generates an infinite stream whose
74+-- 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+--
78+-- @
79+-- > S.toList $ S.take 4 $ S.enumerateFromStepIntegral 0 2
80+-- [0,2,4,6]
81+-- > S.toList $ S.take 3 $ S.enumerateFromStepIntegral 0 (-2)
82+-- [0,-2,-4]
83+-- @
84+--
85+-- @since 0.6.0
86+{-# INLINE enumerateFromStepIntegral #-}
87+enumerateFromStepIntegral
88+ :: (IsStream t, Monad m, Integral a)
89+ => a -> a -> t m a
90+enumerateFromStepIntegral from stride =
91+ fromStreamD $ D.enumerateFromStepIntegral from stride
92+
93+-- | Enumerate an 'Integral' type. @enumerateFromIntegral from@ generates a
94+-- stream whose first element is @from@ and the successive elements are in
95+-- increments of @1@. The stream is bounded by the size of the 'Integral' type.
96+--
97+-- @
98+-- > S.toList $ S.take 4 $ S.enumerateFromIntegral (0 :: Int)
99+-- [0,1,2,3]
100+-- @
101+--
102+-- @since 0.6.0
103+{-# INLINE enumerateFromIntegral #-}
104+enumerateFromIntegral
105+ :: (IsStream t, Monad m, Integral a, Bounded a)
106+ => a -> t m a
107+enumerateFromIntegral from = fromStreamD $ D.enumerateFromIntegral from
108+
109+-- | Enumerate an 'Integral' type in steps. @enumerateFromThenIntegral from
110+-- then@ generates a stream whose first element is @from@, the second element
111+-- is @then@ and the successive elements are in increments of @then - from@.
112+-- The stream is bounded by the size of the 'Integral' type.
113+--
114+-- @
115+-- > S.toList $ S.take 4 $ S.enumerateFromThenIntegral (0 :: Int) 2
116+-- [0,2,4,6]
117+-- > S.toList $ S.take 4 $ S.enumerateFromThenIntegral (0 :: Int) (-2)
118+-- [0,-2,-4,-6]
119+-- @
120+--
121+-- @since 0.6.0
122+{-# INLINE enumerateFromThenIntegral #-}
123+enumerateFromThenIntegral
124+ :: (IsStream t, Monad m, Integral a, Bounded a)
125+ => a -> a -> t m a
126+enumerateFromThenIntegral from next =
127+ fromStreamD $ D.enumerateFromThenIntegral from next
128+
129+-- | Enumerate an 'Integral' type up to a given limit.
130+-- @enumerateFromToIntegral from to@ generates a finite stream whose first
131+-- element is @from@ and successive elements are in increments of @1@ up to
132+-- @to@.
133+--
134+-- @
135+-- > S.toList $ S.enumerateFromToIntegral 0 4
136+-- [0,1,2,3,4]
137+-- @
138+--
139+-- @since 0.6.0
140+{-# INLINE enumerateFromToIntegral #-}
141+enumerateFromToIntegral :: (IsStream t, Monad m, Integral a) => a -> a -> t m a
142+enumerateFromToIntegral from to =
143+ fromStreamD $ D.enumerateFromToIntegral from to
144+
145+-- | Enumerate an 'Integral' type in steps up to a given limit.
146+-- @enumerateFromThenToIntegral from then to@ generates a finite stream whose
147+-- first element is @from@, the second element is @then@ and the successive
148+-- elements are in increments of @then - from@ up to @to@.
149+--
150+-- @
151+-- > S.toList $ S.enumerateFromThenToIntegral 0 2 6
152+-- [0,2,4,6]
153+-- > S.toList $ S.enumerateFromThenToIntegral 0 (-2) (-6)
154+-- [0,-2,-4,-6]
155+-- @
156+--
157+-- @since 0.6.0
158+{-# INLINE enumerateFromThenToIntegral #-}
159+enumerateFromThenToIntegral
160+ :: (IsStream t, Monad m, Integral a)
161+ => a -> a -> a -> t m a
162+enumerateFromThenToIntegral from next to =
163+ fromStreamD $ D.enumerateFromThenToIntegral from next to
164+
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+
189+-------------------------------------------------------------------------------
190+-- Enumeration of Fractional types
191+-------------------------------------------------------------------------------
192+--
193+-- Even though the underlying implementation of enumerateFromFractional and
194+-- enumerateFromThenFractional works for any 'Num' we have restricted these to
195+-- 'Fractional' because these do not perform any bounds check, in contrast to
196+-- integral versions and are therefore not equivalent substitutes for those.
197+--
198+-- | Numerically stable enumeration from a 'Fractional' number in steps of size
199+-- @1@. @enumerateFromFractional from@ generates a stream whose first element
200+-- is @from@ and the successive elements are in increments of @1@. No overflow
201+-- or underflow checks are performed.
202+--
203+-- This is the equivalent to 'enumFrom' for 'Fractional' types. For example:
204+--
205+-- @
206+-- > S.toList $ S.take 4 $ S.enumerateFromFractional 1.1
207+-- [1.1,2.1,3.1,4.1]
208+-- @
209+--
210+--
211+-- @since 0.6.0
212+{-# INLINE enumerateFromFractional #-}
213+enumerateFromFractional :: (IsStream t, Monad m, Fractional a) => a -> t m a
214+enumerateFromFractional from = fromStreamD $ D.numFrom from
215+
216+-- | Numerically stable enumeration from a 'Fractional' number in steps.
217+-- @enumerateFromThenFractional from then@ generates a stream whose first
218+-- element is @from@, the second element is @then@ and the successive elements
219+-- are in increments of @then - from@. No overflow or underflow checks are
220+-- performed.
221+--
222+-- This is the equivalent of 'enumFromThen' for 'Fractional' types. For
223+-- example:
224+--
225+-- @
226+-- > S.toList $ S.take 4 $ S.enumerateFromThenFractional 1.1 2.1
227+-- [1.1,2.1,3.1,4.1]
228+-- > S.toList $ S.take 4 $ S.enumerateFromThenFractional 1.1 (-2.1)
229+-- [1.1,-2.1,-5.300000000000001,-8.500000000000002]
230+-- @
231+--
232+-- @since 0.6.0
233+{-# INLINE enumerateFromThenFractional #-}
234+enumerateFromThenFractional
235+ :: (IsStream t, Monad m, Fractional a)
236+ => a -> a -> t m a
237+enumerateFromThenFractional from next = fromStreamD $ D.numFromThen from next
238+
239+-- | Numerically stable enumeration from a 'Fractional' number to a given
240+-- limit. @enumerateFromToFractional from to@ generates a finite stream whose
241+-- first element is @from@ and successive elements are in increments of @1@ up
242+-- to @to@.
243+--
244+-- This is the equivalent of 'enumFromTo' for 'Fractional' types. For
245+-- example:
246+--
247+-- @
248+-- > S.toList $ S.enumerateFromToFractional 1.1 4
249+-- [1.1,2.1,3.1,4.1]
250+-- > S.toList $ S.enumerateFromToFractional 1.1 4.6
251+-- [1.1,2.1,3.1,4.1,5.1]
252+-- @
253+--
254+-- Notice that the last element is equal to the specified @to@ value after
255+-- rounding to the nearest integer.
256+--
257+-- @since 0.6.0
258+{-# INLINE enumerateFromToFractional #-}
259+enumerateFromToFractional
260+ :: (IsStream t, Monad m, Fractional a, Ord a)
261+ => a -> a -> t m a
262+enumerateFromToFractional from to =
263+ fromStreamD $ D.enumerateFromToFractional from to
264+
265+-- | Numerically stable enumeration from a 'Fractional' number in steps up to a
266+-- given limit. @enumerateFromThenToFractional from then to@ generates a
267+-- finite stream whose first element is @from@, the second element is @then@
268+-- and the successive elements are in increments of @then - from@ up to @to@.
269+--
270+-- This is the equivalent of 'enumFromThenTo' for 'Fractional' types. For
271+-- example:
272+--
273+-- @
274+-- > S.toList $ S.enumerateFromThenToFractional 0.1 2 6
275+-- [0.1,2.0,3.9,5.799999999999999]
276+-- > S.toList $ S.enumerateFromThenToFractional 0.1 (-2) (-6)
277+-- [0.1,-2.0,-4.1000000000000005,-6.200000000000001]
278+-- @
279+--
280+--
281+-- @since 0.6.0
282+{-# INLINE enumerateFromThenToFractional #-}
283+enumerateFromThenToFractional
284+ :: (IsStream t, Monad m, Fractional a, Ord a)
285+ => a -> a -> a -> t m a
286+enumerateFromThenToFractional from next to =
287+ fromStreamD $ D.enumerateFromThenToFractional from next to
288+
289+-------------------------------------------------------------------------------
290+-- Enumeration of Enum types
291+-------------------------------------------------------------------------------
292+--
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.
297+{-# INLINE enumerateFromToSmall #-}
298+enumerateFromToSmall :: (IsStream t, Monad m, Enum a) => a -> a -> t m a
299+enumerateFromToSmall from to = Serial.map toEnum $
300+ enumerateFromToIntegral (fromEnum from) (fromEnum to)
301+
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.
314+{-# INLINE enumerateFromThenToSmall #-}
315+enumerateFromThenToSmall :: (IsStream t, Monad m, Enum a)
316+ => a -> a -> a -> t m a
317+enumerateFromThenToSmall from next to = Serial.map toEnum $
318+ enumerateFromThenToIntegral (fromEnum from) (fromEnum next) (fromEnum to)
319+
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.
324+{-# INLINE enumerateFromThenSmallBounded #-}
325+enumerateFromThenSmallBounded :: (IsStream t, Monad m, Enumerable a, Bounded a)
326+ => a -> a -> t m a
327+enumerateFromThenSmallBounded from next =
328+ case fromEnum next >= fromEnum from of
329+ True -> enumerateFromThenTo from next maxBound
330+ False -> enumerateFromThenTo from next minBound
331+
332+-------------------------------------------------------------------------------
333+-- Enumerable type class
334+-------------------------------------------------------------------------------
335+--
336+-- NOTE: We would like to rewrite calls to fromList [1..] etc. to stream
337+-- enumerations like this:
338+--
339+-- {-# RULES "fromList enumFrom" [1]
340+-- forall (a :: Int). D.fromList (enumFrom a) = D.enumerateFromIntegral a #-}
341+--
342+-- But this does not work because enumFrom is a class method and GHC rewrites
343+-- it quickly, so we do not get a chance to have our rule fired.
344+
345+-- | Types that can be enumerated as a stream. The operations in this type
346+-- class are equivalent to those in the 'Enum' type class, except that these
347+-- generate a stream instead of a list. Use the functions in
348+-- "Streamly.Enumeration" module to define new instances.
349+--
350+-- @since 0.6.0
351+class Enum a => Enumerable a where
352+ -- | @enumerateFrom from@ generates a stream starting with the element
353+ -- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
354+ -- generating an infinite stream when the type is not 'Bounded'.
355+ --
356+ -- @
357+ -- > S.toList $ S.take 4 $ S.enumerateFrom (0 :: Int)
358+ -- [0,1,2,3]
359+ -- @
360+ --
361+ -- For 'Fractional' types, enumeration is numerically stable. However, no
362+ -- overflow or underflow checks are performed.
363+ --
364+ -- @
365+ -- > S.toList $ S.take 4 $ S.enumerateFrom 1.1
366+ -- [1.1,2.1,3.1,4.1]
367+ -- @
368+ --
369+ enumerateFrom :: (IsStream t, Monad m) => a -> t m a
370+
371+ -- | Generate a finite stream starting with the element @from@, enumerating
372+ -- the type up to the value @to@. If @to@ is smaller than @from@ then an
373+ -- empty stream is returned.
374+ --
375+ -- @
376+ -- > S.toList $ S.enumerateFromTo 0 4
377+ -- [0,1,2,3,4]
378+ -- @
379+ --
380+ -- For 'Fractional' types, the last element is equal to the specified @to@
381+ -- value after rounding to the nearest integral value.
382+ --
383+ -- @
384+ -- > S.toList $ S.enumerateFromTo 1.1 4
385+ -- [1.1,2.1,3.1,4.1]
386+ -- > S.toList $ S.enumerateFromTo 1.1 4.6
387+ -- [1.1,2.1,3.1,4.1,5.1]
388+ -- @
389+ --
390+ enumerateFromTo :: (IsStream t, Monad m) => a -> a -> t m a
391+
392+ -- | @enumerateFromThen from then@ generates a stream whose first element
393+ -- is @from@, the second element is @then@ and the successive elements are
394+ -- in increments of @then - from@. Enumeration can occur downwards or
395+ -- upwards depending on whether @then@ comes before or after @from@. For
396+ -- 'Bounded' types the stream ends when 'maxBound' is reached, for
397+ -- unbounded types it keeps enumerating infinitely.
398+ --
399+ -- @
400+ -- > S.toList $ S.take 4 $ S.enumerateFromThen 0 2
401+ -- [0,2,4,6]
402+ -- > S.toList $ S.take 4 $ S.enumerateFromThen 0 (-2)
403+ -- [0,-2,-4,-6]
404+ -- @
405+ enumerateFromThen :: (IsStream t, Monad m) => a -> a -> t m a
406+
407+ -- | @enumerateFromThenTo from then to@ generates a finite stream whose
408+ -- first element is @from@, the second element is @then@ and the successive
409+ -- elements are in increments of @then - from@ up to @to@. Enumeration can
410+ -- occur downwards or upwards depending on whether @then@ comes before or
411+ -- after @from@.
412+ --
413+ -- @
414+ -- > S.toList $ S.enumerateFromThenTo 0 2 6
415+ -- [0,2,4,6]
416+ -- > S.toList $ S.enumerateFromThenTo 0 (-2) (-6)
417+ -- [0,-2,-4,-6]
418+ -- @
419+ enumerateFromThenTo :: (IsStream t, Monad m) => a -> a -> a -> t m a
420+
421+-- For Enum types smaller than or equal to Int size.
422+#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
423+instance Enumerable SMALL_TYPE where { \
424+ {-# INLINE enumerateFrom #-}; \
425+ enumerateFrom = enumerateFromBounded; \
426+ {-# INLINE enumerateFromThen #-}; \
427+ enumerateFromThen = enumerateFromThenSmallBounded; \
428+ {-# INLINE enumerateFromTo #-}; \
429+ enumerateFromTo = enumerateFromToSmall; \
430+ {-# INLINE enumerateFromThenTo #-}; \
431+ enumerateFromThenTo = enumerateFromThenToSmall }
432+
433+
434+ENUMERABLE_BOUNDED_SMALL(())
435+ENUMERABLE_BOUNDED_SMALL(Bool)
436+ENUMERABLE_BOUNDED_SMALL(Ordering)
437+ENUMERABLE_BOUNDED_SMALL(Char)
438+
439+-- For bounded Integral Enum types, may be larger than Int.
440+#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
441+instance Enumerable INTEGRAL_TYPE where { \
442+ {-# INLINE enumerateFrom #-}; \
443+ enumerateFrom = enumerateFromIntegral; \
444+ {-# INLINE enumerateFromThen #-}; \
445+ enumerateFromThen = enumerateFromThenIntegral; \
446+ {-# INLINE enumerateFromTo #-}; \
447+ enumerateFromTo = enumerateFromToIntegral; \
448+ {-# INLINE enumerateFromThenTo #-}; \
449+ enumerateFromThenTo = enumerateFromThenToIntegral }
450+
451+ENUMERABLE_BOUNDED_INTEGRAL(Int)
452+ENUMERABLE_BOUNDED_INTEGRAL(Int8)
453+ENUMERABLE_BOUNDED_INTEGRAL(Int16)
454+ENUMERABLE_BOUNDED_INTEGRAL(Int32)
455+ENUMERABLE_BOUNDED_INTEGRAL(Int64)
456+ENUMERABLE_BOUNDED_INTEGRAL(Word)
457+ENUMERABLE_BOUNDED_INTEGRAL(Word8)
458+ENUMERABLE_BOUNDED_INTEGRAL(Word16)
459+ENUMERABLE_BOUNDED_INTEGRAL(Word32)
460+ENUMERABLE_BOUNDED_INTEGRAL(Word64)
461+
462+-- For unbounded Integral Enum types.
463+#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
464+instance Enumerable INTEGRAL_TYPE where { \
465+ {-# INLINE enumerateFrom #-}; \
466+ enumerateFrom from = enumerateFromStepIntegral from 1; \
467+ {-# INLINE enumerateFromThen #-}; \
468+ enumerateFromThen from next = \
469+ enumerateFromStepIntegral from (next - from); \
470+ {-# INLINE enumerateFromTo #-}; \
471+ enumerateFromTo = enumerateFromToIntegral; \
472+ {-# INLINE enumerateFromThenTo #-}; \
473+ enumerateFromThenTo = enumerateFromThenToIntegral }
474+
475+ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
476+ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
477+
478+#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
479+instance (CONSTRAINT) => Enumerable (FRACTIONAL_TYPE) where { \
480+ {-# INLINE enumerateFrom #-}; \
481+ enumerateFrom = enumerateFromFractional; \
482+ {-# INLINE enumerateFromThen #-}; \
483+ enumerateFromThen = enumerateFromThenFractional; \
484+ {-# INLINE enumerateFromTo #-}; \
485+ enumerateFromTo = enumerateFromToFractional; \
486+ {-# INLINE enumerateFromThenTo #-}; \
487+ enumerateFromThenTo = enumerateFromThenToFractional }
488+
489+ENUMERABLE_FRACTIONAL(Float,)
490+ENUMERABLE_FRACTIONAL(Double,)
491+ENUMERABLE_FRACTIONAL(Fixed a,HasResolution a)
492+ENUMERABLE_FRACTIONAL(Ratio a,Integral a)
493+
494+#if __GLASGOW_HASKELL__ >= 800
495+instance Enumerable a => Enumerable (Identity a) where
496+ {-# INLINE enumerateFrom #-}
497+ enumerateFrom (Identity from) = Serial.map Identity $
498+ enumerateFrom from
499+ {-# INLINE enumerateFromThen #-}
500+ enumerateFromThen (Identity from) (Identity next) = Serial.map Identity $
501+ enumerateFromThen from next
502+ {-# INLINE enumerateFromTo #-}
503+ enumerateFromTo (Identity from) (Identity to) = Serial.map Identity $
504+ enumerateFromTo from to
505+ {-# INLINE enumerateFromThenTo #-}
506+ enumerateFromThenTo (Identity from) (Identity next) (Identity to) =
507+ Serial.map Identity $ enumerateFromThenTo from next to
508+#endif
509+{-
510+-- TODO
511+instance Enumerable a => Enumerable (Last a)
512+instance Enumerable a => Enumerable (First a)
513+instance Enumerable a => Enumerable (Max a)
514+instance Enumerable a => Enumerable (Min a)
515+instance Enumerable a => Enumerable (Const a b)
516+instance Enumerable (f a) => Enumerable (Alt f a)
517+instance Enumerable (f a) => Enumerable (Ap f a)
518+-}
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
src/Streamly/Prelude.hs+3−433
@@ -81,24 +81,7 @@ module Streamly.Prelude
8181 --
8282 -- However, this is not particularly efficient.
8383 -- The 'Enumerable' type class provides corresponding functions that
84− -- generate a stream instead of a list. This library implements generic
85− -- functions for 'Integral' type enumerations with bounds check and
86− -- numerically stable 'Fractional' type enumerations. These functions are
87− -- not exposed but can be exposed if needed to write new instances.
88− --
89− {-
90− , intFrom
91− , intFromTo
92− , intFromThen
93− , intFromThenTo
94− , intFromStep
95−
96− , fracFrom
97− , fracFromTo
98− , fracFromThen
99− , fracFromThenTo
100− , numFromStep
101− -}
84+ -- generate a stream instead of a list, efficiently.
10285
10386 , Enumerable (..)
10487 , enumerate
@@ -370,18 +353,11 @@ import Prelude
370353 reverse, iterate, init, and, or, lookup, foldr1, (!!),
371354 scanl, scanl1, replicate, concatMap)
372355
373−-- Numeric Types
374−import Data.Fixed
375−import Data.Int
376−import Data.Ratio
377−import Data.Word
378−import Numeric.Natural
379−import Data.Functor.Identity (Identity(..))
380−
381356import qualified Prelude
382357import qualified System.IO as IO
383358
384−import Streamly.SVar (MonadAsync, defState)
359+import Streamly.Enumeration (Enumerable(..), enumerate)
360+import Streamly.SVar (MonadAsync, defState, rstState)
385361import Streamly.Streams.Async (mkAsync')
386362import Streamly.Streams.Combinators (maxYields)
387363import Streamly.Streams.Prelude (fromStreamS, toStreamS)
@@ -539,412 +515,6 @@ yield = K.yield
539515yieldM :: (Monad m, IsStream t) => m a -> t m a
540516yieldM = K.yieldM
541517
542−-- | @intFromStep from step@ generates an infinite stream whose first element
543−-- is @from@ and the successive elements are in increments of @step@. This does
544−-- not check for overflow or underflow if the 'Integral' type is bounded.
545−--
546−-- @
547−-- > S.toList $ S.take 4 $ S.intFromStep 0 2
548−-- [0,2,4,6]
549−-- > S.toList $ S.take 3 $ S.intFromStep 0 (-2)
550−-- [0,-2,-4]
551−-- @
552−--
553−-- @since 0.6.0
554−{-# INLINE intFromStep #-}
555−intFromStep :: (IsStream t, Monad m, Integral a) => a -> a -> t m a
556−intFromStep from stride = fromStreamD $ D.intFromStep from stride
557−
558−-- | Enumerate an 'Integral' type. @intFrom from@ generates a stream whose
559−-- first element is @from@ and the successive elements are in increments of
560−-- @1@. The stream is bounded by the size of the 'Integral' type.
561−--
562−-- @
563−-- > S.toList $ S.take 4 $ S.intFrom (0 :: Int)
564−-- [0,1,2,3]
565−-- @
566−--
567−-- @since 0.6.0
568−{-# INLINE intFrom #-}
569−intFrom :: (IsStream t, Monad m, Integral a, Bounded a) => a -> t m a
570−intFrom from = fromStreamD $ D.intFrom from
571−
572−-- | Enumerate an 'Integral' type in steps. @intFromThen from then@ generates a
573−-- stream whose first element is @from@, the second element is @then@ and the
574−-- successive elements are in increments of @then - from@. The stream is
575−-- bounded by the size of the 'Integral' type.
576−--
577−-- @
578−-- > S.toList $ S.take 4 $ S.intFromThen (0 :: Int) 2
579−-- [0,2,4,6]
580−-- > S.toList $ S.take 4 $ S.intFromThen (0 :: Int) (-2)
581−-- [0,-2,-4,-6]
582−-- @
583−--
584−-- @since 0.6.0
585−{-# INLINE intFromThen #-}
586−intFromThen :: (IsStream t, Monad m, Integral a, Bounded a) => a -> a -> t m a
587−intFromThen from next = fromStreamD $ D.intFromThen from next
588−
589−-- | Enumerate an 'Integral' type up to a given limit. @intFromTo from to@
590−-- generates a finite stream whose first element is @from@ and successive
591−-- elements are in increments of @1@ up to @to@.
592−--
593−-- @
594−-- > S.toList $ S.intFromTo 0 4
595−-- [0,1,2,3,4]
596−-- @
597−--
598−-- @since 0.6.0
599−{-# INLINE intFromTo #-}
600−intFromTo :: (IsStream t, Monad m, Integral a) => a -> a -> t m a
601−intFromTo from to = fromStreamD $ D.intFromTo from to
602−
603−-- | Enumerate an 'Integral' type in steps up to a given limit. @intFromThenTo
604−-- from then to@ generates a finite stream whose first element is @from@, the
605−-- second element is @then@ and the successive elements are in increments of
606−-- @then - from@ up to @to@.
607−--
608−-- @
609−-- > S.toList $ S.intFromThenTo 0 2 6
610−-- [0,2,4,6]
611−-- > S.toList $ S.intFromThenTo 0 (-2) (-6)
612−-- [0,-2,-4,-6]
613−-- @
614−--
615−-- @since 0.6.0
616−{-# INLINE intFromThenTo #-}
617−intFromThenTo :: (IsStream t, Monad m, Integral a) => a -> a -> a -> t m a
618−intFromThenTo from next to = fromStreamD $ D.intFromThenTo from next to
619−
620−-- | @numFromStep from step@ generates an infinite stream whose first element
621−-- is @from@ and the successive elements are in increments of @step@. This is
622−-- numerically stable but does not check for overflow or underflow for bounded
623−-- types. Note, for 'Integral' types 'intFromStep' is faster.
624−--
625−--
626−-- @
627−-- > S.toList $ S.take 4 $ S.numFromStep 0.1 2
628−-- [0.1,2.1,4.1,6.1]
629−-- > S.toList $ S.take 3 $ S.numFromStep 0.1 (-2)
630−-- [0.1,-1.9,-3.9,-5.9]
631−-- @
632−--
633−-- @since 0.6.0
634−{-# INLINE _numFromStep #-}
635−_numFromStep :: (IsStream t, Monad m, Num a) => a -> a -> t m a
636−_numFromStep from stride = fromStreamD $ D.numFromStep from stride
637−
638−-- Even though the underlying implementation of fracFrom and fracFromThen works
639−-- for any 'Num' we have restricted these to 'Fractional' because these do not
640−-- perform any bounds check, in contrast to int versions and are therefore not
641−-- equivalent substitutes for those.
642−--
643−-- | Numerically stable enumeration from a 'Fractional' number in steps of size
644−-- @1@. @fracFrom from@ generates a stream whose first element is @from@ and
645−-- the successive elements are in increments of @1@. No overflow or underflow
646−-- checks are performed.
647−--
648−-- This is the equivalent to 'enumFrom' for 'Fractional' types. For example:
649−--
650−-- @
651−-- > S.toList $ S.take 4 $ S.fracFrom 1.1
652−-- [1.1,2.1,3.1,4.1]
653−-- @
654−--
655−--
656−-- @since 0.6.0
657−{-# INLINE fracFrom #-}
658−fracFrom :: (IsStream t, Monad m, Fractional a) => a -> t m a
659−fracFrom from = fromStreamD $ D.numFrom from
660−
661−-- | Numerically stable enumeration from a 'Fractional' number in steps.
662−-- @fracFromThen from then@ generates a stream whose first element is @from@,
663−-- the second element is @then@ and the successive elements are in increments
664−-- of @then - from@. No overflow or underflow checks are performed.
665−--
666−-- This is the equivalent of 'enumFromThen' for 'Fractional' types. For
667−-- example:
668−--
669−-- @
670−-- > S.toList $ S.take 4 $ S.fracFromThen 1.1 2.1
671−-- [1.1,2.1,3.1,4.1]
672−-- > S.toList $ S.take 4 $ S.fracFromThen 1.1 (-2.1)
673−-- [1.1,-2.1,-5.300000000000001,-8.500000000000002]
674−-- @
675−--
676−-- @since 0.6.0
677−{-# INLINE fracFromThen #-}
678−fracFromThen :: (IsStream t, Monad m, Fractional a) => a -> a -> t m a
679−fracFromThen from next = fromStreamD $ D.numFromThen from next
680−
681−-- | Numerically stable enumeration from a 'Fractional' number to a given
682−-- limit. @fracFromTo from to@ generates a finite stream whose first element
683−-- is @from@ and successive elements are in increments of @1@ up to @to@.
684−--
685−-- This is the equivalent of 'enumFromTo' for 'Fractional' types. For
686−-- example:
687−--
688−-- @
689−-- > S.toList $ S.fracFromTo 1.1 4
690−-- [1.1,2.1,3.1,4.1]
691−-- > S.toList $ S.fracFromTo 1.1 4.6
692−-- [1.1,2.1,3.1,4.1,5.1]
693−-- @
694−--
695−-- Notice that the last element is equal to the specified @to@ value after
696−-- rounding to the nearest integer.
697−--
698−-- @since 0.6.0
699−{-# INLINE fracFromTo #-}
700−fracFromTo :: (IsStream t, Monad m, Fractional a, Ord a) => a -> a -> t m a
701−fracFromTo from to = fromStreamD $ D.fracFromTo from to
702−
703−-- | Numerically stable enumeration from a 'Fractional' number in steps up to a
704−-- given limit. @fracFromThenTo from then to@ generates a finite stream whose
705−-- first element is @from@, the second element is @then@ and the successive
706−-- elements are in increments of @then - from@ up to @to@.
707−--
708−-- This is the equivalent of 'enumFromThenTo' for 'Fractional' types. For
709−-- example:
710−--
711−-- @
712−-- > S.toList $ S.fracFromThenTo 0.1 2 6
713−-- [0.1,2.0,3.9,5.799999999999999]
714−-- > S.toList $ S.fracFromThenTo 0.1 (-2) (-6)
715−-- [0.1,-2.0,-4.1000000000000005,-6.200000000000001]
716−-- @
717−--
718−--
719−-- @since 0.6.0
720−{-# INLINE fracFromThenTo #-}
721−fracFromThenTo
722− :: (IsStream t, Monad m, Fractional a, Ord a)
723− => a -> a -> a -> t m a
724−fracFromThenTo from next to = fromStreamD $ D.fracFromThenTo from next to
725−
726−-------------------------------------------------------------------------------
727−-- Enumeration of Enum types
728−-------------------------------------------------------------------------------
729−--
730−-- | 'enumerateFromTo' for 'Enum' types not larger than 'Int'.
731−{-# INLINE enumerateFromToSmall #-}
732−enumerateFromToSmall :: (IsStream t, Monad m, Enum a) => a -> a -> t m a
733−enumerateFromToSmall from to = Serial.map toEnum $
734− intFromTo (fromEnum from) (fromEnum to)
735−
736−-- | 'enumerateFrom' for 'Bounded' 'Enum' types.
737−{-# INLINE enumerateFromBounded #-}
738−enumerateFromBounded :: (IsStream t, Monad m, Enumerable a, Bounded a)
739− => a -> t m a
740−enumerateFromBounded from = enumerateFromTo from maxBound
741−
742−{-# INLINE enumerateFromThenToSmall #-}
743−enumerateFromThenToSmall :: (IsStream t, Monad m, Enum a)
744− => a -> a -> a -> t m a
745−enumerateFromThenToSmall from next to = Serial.map toEnum $
746− intFromThenTo (fromEnum from) (fromEnum next) (fromEnum to)
747−
748−-- | 'enumerateFromThen' for 'Bounded' 'Enum' types not larger than 'Int'. For
749−-- types smaller than 'Int' we know it is 'Bounded' as well. Though it is not
750−-- necessary to require 'Bounded' instance for all small types, we require it
751−-- anyway because it is safe that way.
752−{-# INLINE enumerateFromThenBoundedSmall #-}
753−enumerateFromThenBoundedSmall :: (IsStream t, Monad m, Enumerable a, Bounded a)
754− => a -> a -> t m a
755−enumerateFromThenBoundedSmall from next =
756− case fromEnum next >= fromEnum from of
757− True -> enumerateFromThenTo from next maxBound
758− False -> enumerateFromThenTo from next minBound
759−
760−-- NOTE: We would like to rewrite calls to fromList [1..] etc. to stream
761−-- enumerations like this:
762−--
763−-- {-# RULES "fromList enumFrom" [1]
764−-- forall (a :: Int). D.fromList (enumFrom a) = D.intFrom a #-}
765−--
766−-- But this does not work because enumFrom is a class method and GHC rewrites
767−-- it quickly, so we do not get a chance to have our rule fired.
768−--
769−-- | Types that can be enumerated as a stream. The operations in this type
770−-- class are equivalent to those in the 'Enum' type class, except that these
771−-- generate a stream instead of a list. Use the functions in
772−-- "Streamly.Enumeration" module to define new instances.
773−--
774−-- @since 0.6.0
775−class Enum a => Enumerable a where
776− -- | @enumerateFrom from@ generates a stream starting with the element
777− -- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
778− -- generating an infinite stream when the type is not 'Bounded'.
779− --
780− -- @
781− -- > S.toList $ S.take 4 $ S.enumerateFrom (0 :: Int)
782− -- [0,1,2,3]
783− -- @
784− --
785− -- For 'Fractional' types, enumeration is numerically stable. However, no
786− -- overflow or underflow checks are performed.
787− --
788− -- @
789− -- > S.toList $ S.take 4 $ S.enumerateFrom 1.1
790− -- [1.1,2.1,3.1,4.1]
791− -- @
792− --
793− enumerateFrom :: (IsStream t, Monad m) => a -> t m a
794−
795− -- | Generate a finite stream starting with the element @from@, enumerating
796− -- the type up to the value @to@. If @to@ is smaller than @from@ then an
797− -- empty stream is returned.
798− --
799− -- @
800− -- > S.toList $ S.enumerateFromTo 0 4
801− -- [0,1,2,3,4]
802− -- @
803− --
804− -- For 'Fractional' types, the last element is equal to the specified @to@
805− -- value after rounding to the nearest integral value.
806− --
807− -- @
808− -- > S.toList $ S.enumerateFromTo 1.1 4
809− -- [1.1,2.1,3.1,4.1]
810− -- > S.toList $ S.enumerateFromTo 1.1 4.6
811− -- [1.1,2.1,3.1,4.1,5.1]
812− -- @
813− --
814− enumerateFromTo :: (IsStream t, Monad m) => a -> a -> t m a
815−
816− -- | @enumerateFromThen from then@ generates a stream whose first element
817− -- is @from@, the second element is @then@ and the successive elements are
818− -- in increments of @then - from@. Enumeration can occur downwards or
819− -- upwards depending on whether @then@ comes before or after @from@. For
820− -- 'Bounded' types the stream ends when 'maxBound' is reached, for
821− -- unbounded types it keeps enumerating infinitely.
822− --
823− -- @
824− -- > S.toList $ S.take 4 $ S.enumerateFromThen 0 2
825− -- [0,2,4,6]
826− -- > S.toList $ S.take 4 $ S.enumerateFromThen 0 (-2)
827− -- [0,-2,-4,-6]
828− -- @
829− enumerateFromThen :: (IsStream t, Monad m) => a -> a -> t m a
830−
831− -- | @enumerateFromThenTo from then to@ generates a finite stream whose
832− -- first element is @from@, the second element is @then@ and the successive
833− -- elements are in increments of @then - from@ up to @to@. Enumeration can
834− -- occur downwards or upwards depending on whether @then@ comes before or
835− -- after @from@.
836− --
837− -- @
838− -- > S.toList $ S.enumerateFromThenTo 0 2 6
839− -- [0,2,4,6]
840− -- > S.toList $ S.enumerateFromThenTo 0 (-2) (-6)
841− -- [0,-2,-4,-6]
842− -- @
843− enumerateFromThenTo :: (IsStream t, Monad m) => a -> a -> a -> t m a
844−
845−-- For Enum types smaller than or equal to Int size.
846−#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
847−instance Enumerable SMALL_TYPE where { \
848− {-# INLINE enumerateFrom #-}; \
849− enumerateFrom = enumerateFromBounded; \
850− {-# INLINE enumerateFromThen #-}; \
851− enumerateFromThen = enumerateFromThenBoundedSmall; \
852− {-# INLINE enumerateFromTo #-}; \
853− enumerateFromTo = enumerateFromToSmall; \
854− {-# INLINE enumerateFromThenTo #-}; \
855− enumerateFromThenTo = enumerateFromThenToSmall }
856−
857−
858−ENUMERABLE_BOUNDED_SMALL(())
859−ENUMERABLE_BOUNDED_SMALL(Bool)
860−ENUMERABLE_BOUNDED_SMALL(Ordering)
861−ENUMERABLE_BOUNDED_SMALL(Char)
862−
863−-- For bounded Integral Enum types, may be larger than Int.
864−#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
865−instance Enumerable INTEGRAL_TYPE where { \
866− {-# INLINE enumerateFrom #-}; \
867− enumerateFrom = intFrom; \
868− {-# INLINE enumerateFromThen #-}; \
869− enumerateFromThen = intFromThen; \
870− {-# INLINE enumerateFromTo #-}; \
871− enumerateFromTo = intFromTo; \
872− {-# INLINE enumerateFromThenTo #-}; \
873− enumerateFromThenTo = intFromThenTo }
874−
875−ENUMERABLE_BOUNDED_INTEGRAL(Int)
876−ENUMERABLE_BOUNDED_INTEGRAL(Int8)
877−ENUMERABLE_BOUNDED_INTEGRAL(Int16)
878−ENUMERABLE_BOUNDED_INTEGRAL(Int32)
879−ENUMERABLE_BOUNDED_INTEGRAL(Int64)
880−ENUMERABLE_BOUNDED_INTEGRAL(Word)
881−ENUMERABLE_BOUNDED_INTEGRAL(Word8)
882−ENUMERABLE_BOUNDED_INTEGRAL(Word16)
883−ENUMERABLE_BOUNDED_INTEGRAL(Word32)
884−ENUMERABLE_BOUNDED_INTEGRAL(Word64)
885−
886−-- For unbounded Integral Enum types.
887−#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
888−instance Enumerable INTEGRAL_TYPE where { \
889− {-# INLINE enumerateFrom #-}; \
890− enumerateFrom from = intFromStep from 1; \
891− {-# INLINE enumerateFromThen #-}; \
892− enumerateFromThen from next = intFromStep from (next - from); \
893− {-# INLINE enumerateFromTo #-}; \
894− enumerateFromTo = intFromTo; \
895− {-# INLINE enumerateFromThenTo #-}; \
896− enumerateFromThenTo = intFromThenTo }
897−
898−ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
899−ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
900−
901−#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
902−instance (CONSTRAINT) => Enumerable (FRACTIONAL_TYPE) where { \
903− {-# INLINE enumerateFrom #-}; \
904− enumerateFrom = fracFrom; \
905− {-# INLINE enumerateFromThen #-}; \
906− enumerateFromThen = fracFromThen; \
907− {-# INLINE enumerateFromTo #-}; \
908− enumerateFromTo = fracFromTo; \
909− {-# INLINE enumerateFromThenTo #-}; \
910− enumerateFromThenTo = fracFromThenTo }
911−
912−ENUMERABLE_FRACTIONAL(Float,)
913−ENUMERABLE_FRACTIONAL(Double,)
914−ENUMERABLE_FRACTIONAL(Fixed a,HasResolution a)
915−ENUMERABLE_FRACTIONAL(Ratio a,Integral a)
916−
917−#if __GLASGOW_HASKELL__ >= 800
918−instance Enumerable a => Enumerable (Identity a) where
919− {-# INLINE enumerateFrom #-}
920− enumerateFrom (Identity from) = Serial.map Identity $
921− enumerateFrom from
922− {-# INLINE enumerateFromThen #-}
923− enumerateFromThen (Identity from) (Identity next) = Serial.map Identity $
924− enumerateFromThen from next
925− {-# INLINE enumerateFromTo #-}
926− enumerateFromTo (Identity from) (Identity to) = Serial.map Identity $
927− enumerateFromTo from to
928− {-# INLINE enumerateFromThenTo #-}
929− enumerateFromThenTo (Identity from) (Identity next) (Identity to) =
930− Serial.map Identity $ enumerateFromThenTo from next to
931−#endif
932−{-
933−-- TODO
934−instance Enumerable a => Enumerable (Last a)
935−instance Enumerable a => Enumerable (First a)
936−instance Enumerable a => Enumerable (Max a)
937−instance Enumerable a => Enumerable (Min a)
938−instance Enumerable a => Enumerable (Const a b)
939−instance Enumerable (f a) => Enumerable (Alt f a)
940−instance Enumerable (f a) => Enumerable (Ap f a)
941−-}
942−
943−-- | Enumerate a finite ('Bounded') data type from its 'minBound' to 'maxBound'
944−{-# INLINE enumerate #-}
945−enumerate :: (IsStream t, Monad m, Bounded a, Enumerable a) => t m a
946−enumerate = enumerateFrom minBound
947−
948518-- |
949519-- @
950520-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
src/Streamly/Streams/StreamD.hs+63−48
@@ -62,17 +62,17 @@ module Streamly.Streams.StreamD
6262 , generateM
6363
6464 -- ** Enumerations
65− , intFromStep
66− , intFrom
67− , intFromThen
68− , intFromTo
69− , intFromThenTo
65+ , enumerateFromStepIntegral
66+ , enumerateFromIntegral
67+ , enumerateFromThenIntegral
68+ , enumerateFromToIntegral
69+ , enumerateFromThenToIntegral
7070
71− , numFromStep
71+ , enumerateFromStepNum
7272 , numFrom
7373 , numFromThen
74− , fracFromTo
75− , fracFromThenTo
74+ , enumerateFromToFractional
75+ , enumerateFromThenToFractional
7676
7777 -- ** Conversions
7878 -- | Transform an input structure into a stream.
@@ -288,9 +288,9 @@ replicate n x = replicateM n (return x)
288288-- constraint.
289289-- | Can be used to enumerate unbounded integrals. This does not check for
290290-- overflow or underflow for bounded integrals.
291−{-# INLINE_NORMAL intFromStep #-}
292−intFromStep :: (Integral a, Monad m) => a -> a -> Stream m a
293−intFromStep from stride =
291+{-# INLINE_NORMAL enumerateFromStepIntegral #-}
292+enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
293+enumerateFromStepIntegral from stride =
294294 from `seq` stride `seq` Stream step from
295295 where
296296 {-# INLINE_LATE step #-}
@@ -298,19 +298,22 @@ intFromStep from stride =
298298
299299-- We are assuming that "to" is constrained by the type to be within
300300-- max/min bounds.
301−{-# INLINE intFromTo #-}
302−intFromTo :: (Monad m, Integral a) => a -> a -> Stream m a
303−intFromTo from to = takeWhile (<= to) $ intFromStep from 1
301+{-# INLINE enumerateFromToIntegral #-}
302+enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
303+enumerateFromToIntegral from to =
304+ takeWhile (<= to) $ enumerateFromStepIntegral from 1
304305
305−{-# INLINE intFrom #-}
306−intFrom :: (Monad m, Integral a, Bounded a) => a -> Stream m a
307−intFrom from = intFromTo from maxBound
306+{-# INLINE enumerateFromIntegral #-}
307+enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
308+enumerateFromIntegral from = enumerateFromToIntegral from maxBound
308309
309310data EnumState a = EnumInit | EnumYield a a a | EnumStop
310311
311−{-# INLINE_NORMAL intFromThenToUp #-}
312−intFromThenToUp :: (Monad m, Integral a) => a -> a -> a -> Stream m a
313−intFromThenToUp from next to = Stream step EnumInit
312+{-# INLINE_NORMAL enumerateFromThenToIntegralUp #-}
313+enumerateFromThenToIntegralUp
314+ :: (Monad m, Integral a)
315+ => a -> a -> a -> Stream m a
316+enumerateFromThenToIntegralUp from next to = Stream step EnumInit
314317 where
315318 {-# INLINE_LATE step #-}
316319 step _ EnumInit =
@@ -331,9 +334,11 @@ intFromThenToUp from next to = Stream step EnumInit
331334
332335 step _ EnumStop = return Stop
333336
334−{-# INLINE_NORMAL intFromThenToDn #-}
335−intFromThenToDn :: (Monad m, Integral a) => a -> a -> a -> Stream m a
336−intFromThenToDn from next to = Stream step EnumInit
337+{-# INLINE_NORMAL enumerateFromThenToIntegralDn #-}
338+enumerateFromThenToIntegralDn
339+ :: (Monad m, Integral a)
340+ => a -> a -> a -> Stream m a
341+enumerateFromThenToIntegralDn from next to = Stream step EnumInit
337342 where
338343 {-# INLINE_LATE step #-}
339344 step _ EnumInit =
@@ -353,18 +358,22 @@ intFromThenToDn from next to = Stream step EnumInit
353358
354359 step _ EnumStop = return Stop
355360
356−{-# INLINE_NORMAL intFromThenTo #-}
357−intFromThenTo :: (Monad m, Integral a) => a -> a -> a -> Stream m a
358−intFromThenTo from next to
359− | next >= from = intFromThenToUp from next to
360− | otherwise = intFromThenToDn from next to
361−
362−{-# INLINE_NORMAL intFromThen #-}
363−intFromThen :: (Monad m, Integral a, Bounded a) => a -> a -> Stream m a
364−intFromThen from next =
361+{-# INLINE_NORMAL enumerateFromThenToIntegral #-}
362+enumerateFromThenToIntegral
363+ :: (Monad m, Integral a)
364+ => a -> a -> a -> Stream m a
365+enumerateFromThenToIntegral from next to
366+ | next >= from = enumerateFromThenToIntegralUp from next to
367+ | otherwise = enumerateFromThenToIntegralDn from next to
368+
369+{-# INLINE_NORMAL enumerateFromThenIntegral #-}
370+enumerateFromThenIntegral
371+ :: (Monad m, Integral a, Bounded a)
372+ => a -> a -> Stream m a
373+enumerateFromThenIntegral from next =
365374 if next > from
366− then intFromThenToUp from next maxBound
367− else intFromThenToDn from next minBound
375+ then enumerateFromThenToIntegralUp from next maxBound
376+ else enumerateFromThenToIntegralDn from next minBound
368377
369378-- For floating point numbers if the increment is less than the precision then
370379-- it just gets lost. Therefore we cannot always increment it correctly by just
@@ -375,33 +384,39 @@ intFromThen from next =
375384-- Instead we accumulate the increment counter and compute the increment
376385-- everytime before adding it to the starting number.
377386--
378−-- This works for Integrals as well as floating point numbers, but intFromStep
379−-- is faster for integrals.
380−{-# INLINE_NORMAL numFromStep #-}
381−numFromStep :: (Monad m, Num a) => a -> a -> Stream m a
382−numFromStep from stride = Stream step 0
387+-- This works for Integrals as well as floating point numbers, but
388+-- enumerateFromStepIntegral is faster for integrals.
389+{-# INLINE_NORMAL enumerateFromStepNum #-}
390+enumerateFromStepNum :: (Monad m, Num a) => a -> a -> Stream m a
391+enumerateFromStepNum from stride = Stream step 0
383392 where
384393 {-# INLINE_LATE step #-}
385394 step _ !i = return $ (Yield $! (from + i * stride)) $! (i + 1)
386395
387396{-# INLINE_NORMAL numFrom #-}
388397numFrom :: (Monad m, Num a) => a -> Stream m a
389−numFrom from = numFromStep from 1
398+numFrom from = enumerateFromStepNum from 1
390399
391400{-# INLINE_NORMAL numFromThen #-}
392401numFromThen :: (Monad m, Num a) => a -> a -> Stream m a
393−numFromThen from next = numFromStep from (next - from)
402+numFromThen from next = enumerateFromStepNum from (next - from)
394403
395404-- We cannot write a general function for Num. The only way to write code
396405-- portable between the two is to use a 'Real' constraint and convert between
397406-- Fractional and Integral using fromRational which is horribly slow.
398−{-# INLINE_NORMAL fracFromTo #-}
399−fracFromTo :: (Monad m, Fractional a, Ord a) => a -> a -> Stream m a
400−fracFromTo from to = takeWhile (<= to + 1/2) $ numFromStep from 1
401−
402−{-# INLINE_NORMAL fracFromThenTo #-}
403−fracFromThenTo :: (Monad m, Fractional a, Ord a) => a -> a -> a -> Stream m a
404−fracFromThenTo from next to = takeWhile predicate $ numFromThen from next
407+{-# INLINE_NORMAL enumerateFromToFractional #-}
408+enumerateFromToFractional
409+ :: (Monad m, Fractional a, Ord a)
410+ => a -> a -> Stream m a
411+enumerateFromToFractional from to =
412+ takeWhile (<= to + 1 / 2) $ enumerateFromStepNum from 1
413+
414+{-# INLINE_NORMAL enumerateFromThenToFractional #-}
415+enumerateFromThenToFractional
416+ :: (Monad m, Fractional a, Ord a)
417+ => a -> a -> a -> Stream m a
418+enumerateFromThenToFractional from next to =
419+ takeWhile predicate $ numFromThen from next
405420 where
406421 mid = (next - from) / 2
407422 predicate | next >= from = (<= to + mid)
streamly.cabal+1
@@ -146,6 +146,7 @@ library
146146 exposed-modules: Streamly.Prelude
147147 , Streamly.List
148148 , Streamly.String
149+ , Streamly.Enumeration
149150 , Streamly.Time
150151 , Streamly
151152 , Streamly.Tutorial