on master help sign in
Move enumeration functions in a separate module
bcd787eHarendra Kumar
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
81 --
81 --
82 -- However, this is not particularly efficient.
82 -- However, this is not particularly efficient.
83 -- The 'Enumerable' type class provides corresponding functions that
83 -- The 'Enumerable' type class provides corresponding functions that
84− -- generate a stream instead of a list. This library implements generic
84+ -- generate a stream instead of a list, efficiently.
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− -}
102
85
103 , Enumerable (..)
86 , Enumerable (..)
104 , enumerate
87 , enumerate
@@ -370,18 +353,11 @@ import Prelude
370 reverse, iterate, init, and, or, lookup, foldr1, (!!),
353 reverse, iterate, init, and, or, lookup, foldr1, (!!),
371 scanl, scanl1, replicate, concatMap)
354 scanl, scanl1, replicate, concatMap)
372
355
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−
381import qualified Prelude
356import qualified Prelude
382import qualified System.IO as IO
357import qualified System.IO as IO
383
358
359+import Streamly.Enumeration (Enumerable(..), enumerate)
384−import Streamly.SVar (MonadAsync, defState)
360+import Streamly.SVar (MonadAsync, defState, rstState)
385import Streamly.Streams.Async (mkAsync')
361import Streamly.Streams.Async (mkAsync')
386import Streamly.Streams.Combinators (maxYields)
362import Streamly.Streams.Combinators (maxYields)
387import Streamly.Streams.Prelude (fromStreamS, toStreamS)
363import Streamly.Streams.Prelude (fromStreamS, toStreamS)
@@ -539,412 +515,6 @@ yield = K.yield
539yieldM :: (Monad m, IsStream t) => m a -> t m a
515yieldM :: (Monad m, IsStream t) => m a -> t m a
540yieldM = K.yieldM
516yieldM = K.yieldM
541
517
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−
948-- |
518-- |
949-- @
519-- @
950-- fromIndices f = let g i = f i \`cons` g (i + 1) in g 0
520-- 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
62 , generateM
62 , generateM
63
63
64 -- ** Enumerations
64 -- ** Enumerations
65− , intFromStep
65+ , enumerateFromStepIntegral
66− , intFrom
66+ , enumerateFromIntegral
67− , intFromThen
67+ , enumerateFromThenIntegral
68− , intFromTo
68+ , enumerateFromToIntegral
69− , intFromThenTo
69+ , enumerateFromThenToIntegral
70
70
71− , numFromStep
71+ , enumerateFromStepNum
72 , numFrom
72 , numFrom
73 , numFromThen
73 , numFromThen
74− , fracFromTo
74+ , enumerateFromToFractional
75− , fracFromThenTo
75+ , enumerateFromThenToFractional
76
76
77 -- ** Conversions
77 -- ** Conversions
78 -- | Transform an input structure into a stream.
78 -- | Transform an input structure into a stream.
@@ -288,9 +288,9 @@ replicate n x = replicateM n (return x)
288-- constraint.
288-- constraint.
289-- | Can be used to enumerate unbounded integrals. This does not check for
289-- | Can be used to enumerate unbounded integrals. This does not check for
290-- overflow or underflow for bounded integrals.
290-- overflow or underflow for bounded integrals.
291−{-# INLINE_NORMAL intFromStep #-}
291+{-# INLINE_NORMAL enumerateFromStepIntegral #-}
292−intFromStep :: (Integral a, Monad m) => a -> a -> Stream m a
292+enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
293−intFromStep from stride =
293+enumerateFromStepIntegral from stride =
294 from `seq` stride `seq` Stream step from
294 from `seq` stride `seq` Stream step from
295 where
295 where
296 {-# INLINE_LATE step #-}
296 {-# INLINE_LATE step #-}
@@ -298,19 +298,22 @@ intFromStep from stride =
298
298
299-- We are assuming that "to" is constrained by the type to be within
299-- We are assuming that "to" is constrained by the type to be within
300-- max/min bounds.
300-- max/min bounds.
301−{-# INLINE intFromTo #-}
301+{-# INLINE enumerateFromToIntegral #-}
302−intFromTo :: (Monad m, Integral a) => a -> a -> Stream m a
302+enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
303−intFromTo from to = takeWhile (<= to) $ intFromStep from 1
303+enumerateFromToIntegral from to =
304+ takeWhile (<= to) $ enumerateFromStepIntegral from 1
304
305
305−{-# INLINE intFrom #-}
306+{-# INLINE enumerateFromIntegral #-}
306−intFrom :: (Monad m, Integral a, Bounded a) => a -> Stream m a
307+enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
307−intFrom from = intFromTo from maxBound
308+enumerateFromIntegral from = enumerateFromToIntegral from maxBound
308
309
309data EnumState a = EnumInit | EnumYield a a a | EnumStop
310data EnumState a = EnumInit | EnumYield a a a | EnumStop
310
311
311−{-# INLINE_NORMAL intFromThenToUp #-}
312+{-# INLINE_NORMAL enumerateFromThenToIntegralUp #-}
313+enumerateFromThenToIntegralUp
312−intFromThenToUp :: (Monad m, Integral a) => a -> a -> a -> Stream m a
314+ :: (Monad m, Integral a)
315+ => a -> a -> a -> Stream m a
313−intFromThenToUp from next to = Stream step EnumInit
316+enumerateFromThenToIntegralUp from next to = Stream step EnumInit
314 where
317 where
315 {-# INLINE_LATE step #-}
318 {-# INLINE_LATE step #-}
316 step _ EnumInit =
319 step _ EnumInit =
@@ -331,9 +334,11 @@ intFromThenToUp from next to = Stream step EnumInit
331
334
332 step _ EnumStop = return Stop
335 step _ EnumStop = return Stop
333
336
334−{-# INLINE_NORMAL intFromThenToDn #-}
337+{-# INLINE_NORMAL enumerateFromThenToIntegralDn #-}
338+enumerateFromThenToIntegralDn
335−intFromThenToDn :: (Monad m, Integral a) => a -> a -> a -> Stream m a
339+ :: (Monad m, Integral a)
340+ => a -> a -> a -> Stream m a
336−intFromThenToDn from next to = Stream step EnumInit
341+enumerateFromThenToIntegralDn from next to = Stream step EnumInit
337 where
342 where
338 {-# INLINE_LATE step #-}
343 {-# INLINE_LATE step #-}
339 step _ EnumInit =
344 step _ EnumInit =
@@ -353,18 +358,22 @@ intFromThenToDn from next to = Stream step EnumInit
353
358
354 step _ EnumStop = return Stop
359 step _ EnumStop = return Stop
355
360
356−{-# INLINE_NORMAL intFromThenTo #-}
361+{-# INLINE_NORMAL enumerateFromThenToIntegral #-}
362+enumerateFromThenToIntegral
357−intFromThenTo :: (Monad m, Integral a) => a -> a -> a -> Stream m a
363+ :: (Monad m, Integral a)
358−intFromThenTo from next to
364+ => a -> a -> a -> Stream m a
365+enumerateFromThenToIntegral from next to
359− | next >= from = intFromThenToUp from next to
366+ | next >= from = enumerateFromThenToIntegralUp from next to
360− | otherwise = intFromThenToDn from next to
367+ | otherwise = enumerateFromThenToIntegralDn from next to
361−
368+
362−{-# INLINE_NORMAL intFromThen #-}
369+{-# INLINE_NORMAL enumerateFromThenIntegral #-}
370+enumerateFromThenIntegral
363−intFromThen :: (Monad m, Integral a, Bounded a) => a -> a -> Stream m a
371+ :: (Monad m, Integral a, Bounded a)
364−intFromThen from next =
372+ => a -> a -> Stream m a
373+enumerateFromThenIntegral from next =
365 if next > from
374 if next > from
366− then intFromThenToUp from next maxBound
375+ then enumerateFromThenToIntegralUp from next maxBound
367− else intFromThenToDn from next minBound
376+ else enumerateFromThenToIntegralDn from next minBound
368
377
369-- For floating point numbers if the increment is less than the precision then
378-- For floating point numbers if the increment is less than the precision then
370-- it just gets lost. Therefore we cannot always increment it correctly by just
379-- it just gets lost. Therefore we cannot always increment it correctly by just
@@ -375,33 +384,39 @@ intFromThen from next =
375-- Instead we accumulate the increment counter and compute the increment
384-- Instead we accumulate the increment counter and compute the increment
376-- everytime before adding it to the starting number.
385-- everytime before adding it to the starting number.
377--
386--
378−-- This works for Integrals as well as floating point numbers, but intFromStep
387+-- This works for Integrals as well as floating point numbers, but
379−-- is faster for integrals.
388+-- enumerateFromStepIntegral is faster for integrals.
380−{-# INLINE_NORMAL numFromStep #-}
389+{-# INLINE_NORMAL enumerateFromStepNum #-}
381−numFromStep :: (Monad m, Num a) => a -> a -> Stream m a
390+enumerateFromStepNum :: (Monad m, Num a) => a -> a -> Stream m a
382−numFromStep from stride = Stream step 0
391+enumerateFromStepNum from stride = Stream step 0
383 where
392 where
384 {-# INLINE_LATE step #-}
393 {-# INLINE_LATE step #-}
385 step _ !i = return $ (Yield $! (from + i * stride)) $! (i + 1)
394 step _ !i = return $ (Yield $! (from + i * stride)) $! (i + 1)
386
395
387{-# INLINE_NORMAL numFrom #-}
396{-# INLINE_NORMAL numFrom #-}
388numFrom :: (Monad m, Num a) => a -> Stream m a
397numFrom :: (Monad m, Num a) => a -> Stream m a
389−numFrom from = numFromStep from 1
398+numFrom from = enumerateFromStepNum from 1
390
399
391{-# INLINE_NORMAL numFromThen #-}
400{-# INLINE_NORMAL numFromThen #-}
392numFromThen :: (Monad m, Num a) => a -> a -> Stream m a
401numFromThen :: (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)
394
403
395-- We cannot write a general function for Num. The only way to write code
404-- We cannot write a general function for Num. The only way to write code
396-- portable between the two is to use a 'Real' constraint and convert between
405-- portable between the two is to use a 'Real' constraint and convert between
397-- Fractional and Integral using fromRational which is horribly slow.
406-- Fractional and Integral using fromRational which is horribly slow.
398−{-# INLINE_NORMAL fracFromTo #-}
407+{-# INLINE_NORMAL enumerateFromToFractional #-}
408+enumerateFromToFractional
399−fracFromTo :: (Monad m, Fractional a, Ord a) => a -> a -> Stream m a
409+ :: (Monad m, Fractional a, Ord a)
410+ => a -> a -> Stream m a
411+enumerateFromToFractional from to =
400−fracFromTo from to = takeWhile (<= to + 1/2) $ numFromStep from 1
412+ takeWhile (<= to + 1 / 2) $ enumerateFromStepNum from 1
401−
413+
402−{-# INLINE_NORMAL fracFromThenTo #-}
414+{-# INLINE_NORMAL enumerateFromThenToFractional #-}
415+enumerateFromThenToFractional
403−fracFromThenTo :: (Monad m, Fractional a, Ord a) => a -> a -> a -> Stream m a
416+ :: (Monad m, Fractional a, Ord a)
417+ => a -> a -> a -> Stream m a
418+enumerateFromThenToFractional from next to =
404−fracFromThenTo from next to = takeWhile predicate $ numFromThen from next
419+ takeWhile predicate $ numFromThen from next
405 where
420 where
406 mid = (next - from) / 2
421 mid = (next - from) / 2
407 predicate | next >= from = (<= to + mid)
422 predicate | next >= from = (<= to + mid)
streamly.cabal+1
@@ -146,6 +146,7 @@ library
146 exposed-modules: Streamly.Prelude
146 exposed-modules: Streamly.Prelude
147 , Streamly.List
147 , Streamly.List
148 , Streamly.String
148 , Streamly.String
149+ , Streamly.Enumeration
149 , Streamly.Time
150 , Streamly.Time
150 , Streamly
151 , Streamly
151 , Streamly.Tutorial
152 , Streamly.Tutorial