@@ -0,0 +1,336 @@
1+#include "inline.hs"
2+-- |
3+-- Module : Streamly.Internal.Data.Unfold.Enumeration
4+-- Copyright : (c) 2018 Composewell Technologies
5+--
6+-- License : BSD3
7+-- Maintainer : streamly@composewell.com
8+-- Stability : experimental
9+-- Portability : GHC
10+--
11+-- The functions defined in this module should be rarely needed for direct use,
12+-- try to use the operations from the 'Enumerable' type class
13+-- instances instead.
14+--
15+-- This module provides an 'Enumerable' type class to enumerate 'Enum' types
16+-- into a stream. The operations in this type class correspond to similar
17+-- perations in the 'Enum' type class, the only difference is that they produce
18+-- a stream instead of a list. These operations cannot be defined generically
19+-- based on the 'Enum' type class. We provide instances for commonly used
20+-- types. If instances for other types are needed convenience functions defined
21+-- in this module can be used to define them. Alternatively, these functions
22+-- can be used directly.
23+--
24+module Streamly.Internal.Data.Unfold.Enumeration
25+(
26+ -- * Enumerations
27+ Enumerable (..)
28+ -- ** Enumerate Num
29+ , enumerateFromStepNum
30+ , numFrom
31+
32+ -- ** Enumerating 'Bounded' 'Integral' Types
33+ , enumerateFromIntegral
34+ , enumerateFromThenIntegral
35+
36+ -- ** Enumerating 'Integral' Types
37+ , enumerateFromToIntegral
38+ , enumerateFromThenToIntegral
39+
40+ -- ** Enumerating unbounded 'Integral' Types
41+ , enumerateFromStepIntegral
42+
43+ -- ** Enumerating 'Fractional' Types
44+ , enumerateFromFractional
45+ , enumerateFromToFractional
46+ , enumerateFromThenFractional
47+ , enumerateFromThenToFractional
48+ )
49+where
50+
51+import Data.Fixed
52+import Data.Int
53+import Data.Ratio
54+import Data.Word
55+import Numeric.Natural
56+import Data.Functor.Identity (Identity(..))
57+import Streamly.Internal.Data.Unfold.Type
58+import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
59+import Prelude
60+ hiding (map, mapM, takeWhile, take, filter, const, zipWith
61+ , drop, dropWhile)
62+
63+------------------------------------------------------------------------------
64+-- Enumeration of Num
65+------------------------------------------------------------------------------
66+-- | Generate an infinite stream starting from a starting value with increments
67+-- of the given stride. The implementation is numerically stable for floating
68+-- point values.
69+--
70+-- Note 'enumerateFromStepIntegral' is faster for integrals.
71+--
72+-- /Pre-release/
73+--
74+{-# INLINE enumerateFromStepNum #-}
75+enumerateFromStepNum :: (Monad m, Num a) => a -> Unfold m a a
76+enumerateFromStepNum stride = Unfold step inject
77+
78+ where
79+
80+ inject !from = return (from, 0)
81+
82+ {-# INLINE_LATE step #-}
83+ step (from, !i) = return $ (Yield $! (from + i * stride)) $! (from, i + 1)
84+
85+-- | @numFrom = enumerateFromStepNum 1@
86+--
87+-- /Pre-release/
88+--
89+{-# INLINE_NORMAL numFrom #-}
90+numFrom :: (Monad m, Num a) => Unfold m a a
91+numFrom = enumerateFromStepNum 1
92+
93+{-# INLINE_NORMAL numFromThen #-}
94+numFromThen :: (Monad m, Num a) => a -> Unfold m a a
95+numFromThen = enumerateFromStepNum
96+
97+------------------------------------------------------------------------------
98+-- Enumeration of Integrals
99+------------------------------------------------------------------------------
100+
101+-- | Can be used to enumerate unbounded integrals. This does not check for
102+-- overflow or underflow for bounded integrals.
103+{-# INLINE_NORMAL enumerateFromStepIntegral #-}
104+enumerateFromStepIntegral :: (Integral a, Monad m) => Unfold m (a, a) a
105+enumerateFromStepIntegral = Unfold step inject
106+ where
107+ inject (from, stride) = from `seq` stride `seq` return (from, stride)
108+ {-# INLINE_LATE step #-}
109+ step (x, stride) = return $ Yield x $! (x + stride, stride)
110+
111+-- We are assuming that "to" is constrained by the type to be within
112+-- max/min bounds.
113+{-# INLINE enumerateFromToIntegral #-}
114+enumerateFromToIntegral :: (Monad m, Integral a) => a -> Unfold m a a
115+enumerateFromToIntegral to =
116+ takeWhile (<= to) $ supplySecond 1 enumerateFromStepIntegral
117+
118+{-# INLINE enumerateFromThenToIntegral #-}
119+enumerateFromThenToIntegral :: (Monad m, Integral a) => a -> a -> Unfold m a a
120+enumerateFromThenToIntegral stride to =
121+ takeWhile (<= to) $ supplySecond stride enumerateFromStepIntegral
122+
123+{-# INLINE enumerateFromIntegral #-}
124+enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
125+enumerateFromIntegral = enumerateFromToIntegral maxBound
126+
127+{-# INLINE enumerateFromThenIntegral #-}
128+enumerateFromThenIntegral :: (Monad m, Integral a, Bounded a) => a -> Unfold m a a
129+enumerateFromThenIntegral stride = enumerateFromThenToIntegral stride maxBound
130+
131+------------------------------------------------------------------------------
132+-- Enumeration of Fractionals
133+------------------------------------------------------------------------------
134+
135+-- | /Internal/
136+--
137+-- > enumerateFromToFractional to = takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
138+--
139+{-# INLINE_NORMAL enumerateFromToFractional #-}
140+enumerateFromToFractional :: (Monad m, Fractional a, Ord a) => a -> Unfold m a a
141+enumerateFromToFractional to =
142+ takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
143+
144+{-# INLINE_NORMAL enumerateFromFractional #-}
145+enumerateFromFractional :: (Monad m, Fractional a) => Unfold m a a
146+enumerateFromFractional = enumerateFromStepNum 1
147+
148+{-# INLINE_NORMAL enumerateFromThenToFractional #-}
149+enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) => a -> a -> Unfold m a a
150+enumerateFromThenToFractional stride to =
151+ takeWhile (<= to + 1 / 2) $ enumerateFromStepNum stride
152+
153+{-# INLINE_NORMAL enumerateFromThenFractional #-}
154+enumerateFromThenFractional :: (Monad m, Fractional a) => a -> Unfold m a a
155+enumerateFromThenFractional = enumerateFromStepNum
156+
157+-------------------------------------------------------------------------------
158+-- Enumerable type class
159+-------------------------------------------------------------------------------
160+-- | Types that can be enumerated as a stream. The operations in this type
161+-- class are equivalent to those in the 'Enum' type class, except that these
162+-- generate a stream instead of a list. Use the functions in
163+-- "Streamly.Internal.Data.Unfold.Enumeration" module to define new instances.
164+--
165+-- /Pre-release/
166+class Enum a => Enumerable a where
167+
168+-- @enumerateFrom from@ generates a stream starting with the element
169+-- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
170+-- generating an infinite stream when the type is not 'Bounded'.
171+--
172+-- @
173+-- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFrom (0 :: Int)
174+-- [0,1,2,3]
175+--
176+-- @
177+--
178+-- For 'Fractional' types, enumeration is numerically stable. However, no
179+-- overflow or underflow checks are performed.
180+--
181+-- @
182+-- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFrom 1.1
183+-- [1.1,2.1,3.1,4.1]
184+--
185+-- @
186+--
187+-- /Pre-release/
188+--
189+ enumerateFrom :: (Integral a, Monad m) => Unfold m a a
190+
191+-- Generate a finite stream starting with the element @from@, enumerating
192+-- the type up to the value @to@. If @to@ is smaller than @from@ then an
193+-- empty stream is returned.
194+--
195+-- @
196+-- >>> Stream.toList $ Stream.unfold (Unfold.enumerateFromTo 4) 0
197+-- [0,1,2,3,4]
198+--
199+-- @
200+--
201+-- For 'Fractional' types, the last element is equal to the specified @to@
202+-- value after rounding to the nearest integral value.
203+--
204+-- @
205+-- >>> Stream.toList $ Stream.unfold (Unfold.enumerateFromTo 4) 1.1
206+-- [1.1,2.1,3.1,4.1]
207+--
208+-- >>> Stream.toList $ Stream.unfold (Unfold.enumerateFromTo 4.6) 1.1
209+-- [1.1,2.1,3.1,4.1,5.1]
210+--
211+-- @
212+--
213+-- /Pre-release/
214+ enumerateFromTo :: (Integral a, Monad m) => a -> Unfold m a a
215+
216+-- @enumerateFromThen from then@ generates a stream whose first element
217+-- is @from@ and the successive elements are
218+-- in increments of @then@. Enumeration can occur downwards or
219+-- upwards depending on whether @then@ comes before or after @from@. For
220+-- 'Bounded' types the stream ends when 'maxBound' is reached, for
221+-- unbounded types it keeps enumerating infinitely.
222+--
223+-- @
224+-- >>> Stream.toList $ Stream.take 4 $ Stream.unfold (Unfold.enumerateFromThen 2) 0
225+-- [0,2,4,6]
226+--
227+-- >>> Stream.toList $ Stream.take 4 $ Stream.unfold (Unfold.enumerateFromThen (-2)) 0
228+-- [0,-2,-4,-6]
229+--
230+-- @
231+--
232+-- /Pre-release/
233+ enumerateFromThen :: (Integral a, Monad m) => a -> Unfold m a a
234+
235+-- @enumerateFromThenTo from then to@ generates a finite stream whose
236+-- first element is @from@ and the successive elements are in
237+-- increments of @then@ up to @to@. Enumeration can
238+-- occur downwards or upwards depending on whether @then@ comes before or
239+-- after @from@.
240+--
241+-- @
242+-- >>> Stream.toList $ Stream.unfold (Unfold.enumerateFromThenTo 2 6) 0
243+-- [0,2,4,6]
244+--
245+-- >>> Stream.toList $ Stream.unfold (Unfold.enumerateFromThenTo (-2) (-6)) 0
246+-- [0,-2,-4,-6]
247+--
248+-- @
249+--
250+-- /Pre-release/
251+ enumerateFromThenTo :: (Integral a, Monad m) => a-> a -> Unfold m a a
252+
253+-------------------------------------------------------------------------------
254+-- Enumerable Instances
255+-------------------------------------------------------------------------------
256+--
257+-- For Enum types smaller than or equal to Int size.
258+#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
259+instance Enumerable SMALL_TYPE where { \
260+ {-# INLINE enumerateFrom #-}; \
261+ enumerateFrom = enumerateFromIntegral; \
262+ {-# INLINE enumerateFromTo #-}; \
263+ enumerateFromTo = enumerateFromToIntegral; \
264+ {-# INLINE enumerateFromThen #-}; \
265+ enumerateFromThen = enumerateFromThenIntegral; \
266+ {-# INLINE enumerateFromThenTo #-}; \
267+ enumerateFromThenTo = enumerateFromThenToIntegral }
268+
269+ENUMERABLE_BOUNDED_SMALL(())
270+ENUMERABLE_BOUNDED_SMALL(Bool)
271+ENUMERABLE_BOUNDED_SMALL(Ordering)
272+ENUMERABLE_BOUNDED_SMALL(Char)
273+
274+-- For bounded Integral Enum types, may be larger than Int.
275+#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
276+instance Enumerable INTEGRAL_TYPE where { \
277+ {-# INLINE enumerateFrom #-}; \
278+ enumerateFrom = enumerateFromIntegral; \
279+ {-# INLINE enumerateFromTo #-}; \
280+ enumerateFromTo = enumerateFromToIntegral; \
281+ {-# INLINE enumerateFromThen #-}; \
282+ enumerateFromThen = enumerateFromThenIntegral; \
283+ {-# INLINE enumerateFromThenTo #-}; \
284+ enumerateFromThenTo = enumerateFromThenToIntegral }
285+
286+ENUMERABLE_BOUNDED_INTEGRAL(Int)
287+ENUMERABLE_BOUNDED_INTEGRAL(Int8)
288+ENUMERABLE_BOUNDED_INTEGRAL(Int16)
289+ENUMERABLE_BOUNDED_INTEGRAL(Int32)
290+ENUMERABLE_BOUNDED_INTEGRAL(Int64)
291+ENUMERABLE_BOUNDED_INTEGRAL(Word)
292+ENUMERABLE_BOUNDED_INTEGRAL(Word8)
293+ENUMERABLE_BOUNDED_INTEGRAL(Word16)
294+ENUMERABLE_BOUNDED_INTEGRAL(Word32)
295+ENUMERABLE_BOUNDED_INTEGRAL(Word64)
296+
297+-- For unbounded Integral Enum types.
298+#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
299+instance Enumerable INTEGRAL_TYPE where { \
300+ {-# INLINE enumerateFrom #-}; \
301+ enumerateFrom = numFrom; \
302+ {-# INLINE enumerateFromTo #-}; \
303+ enumerateFromTo = enumerateFromToIntegral; \
304+ {-# INLINE enumerateFromThen #-}; \
305+ enumerateFromThen = numFromThen; \
306+ {-# INLINE enumerateFromThenTo #-}; \
307+ enumerateFromThenTo = enumerateFromThenToIntegral }
308+
309+ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
310+ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
311+
312+#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
313+instance (CONSTRAINT) => Enumerable FRACTIONAL_TYPE where { \
314+ {-# INLINE enumerateFrom #-}; \
315+ enumerateFrom = enumerateFromFractional; \
316+ {-# INLINE enumerateFromThen #-}; \
317+ enumerateFromThen = enumerateFromThenFractional; \
318+ {-# INLINE enumerateFromTo #-}; \
319+ enumerateFromTo = enumerateFromToFractional; \
320+ {-# INLINE enumerateFromThenTo #-}; \
321+ enumerateFromThenTo = enumerateFromThenToFractional }
322+
323+ENUMERABLE_FRACTIONAL(Float,)
324+ENUMERABLE_FRACTIONAL(Double,)
325+ENUMERABLE_FRACTIONAL((Fixed a),HasResolution a)
326+ENUMERABLE_FRACTIONAL((Ratio a),Integral a)
327+
328+instance Enumerable a => Enumerable (Identity a) where
329+ {-# INLINE enumerateFrom #-}
330+ enumerateFrom = enumerateFrom
331+ {-# INLINE enumerateFromThen #-}
332+ enumerateFromThen = enumerateFromThen
333+ {-# INLINE enumerateFromTo #-}
334+ enumerateFromTo = enumerateFromTo
335+ {-# INLINE enumerateFromThenTo #-}
336+ enumerateFromThenTo = enumerateFromThenTo