2-- Module : Streamly.Internal.Data.Unfold.Enumeration
3-- Copyright : (c) 2019, 2021 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : experimental
9-- The functions defined in this module should be rarely needed for direct use,
10-- try to use the operations from the 'Enumerable' type class
13-- This module provides an 'Enumerable' type class to enumerate 'Enum' types
14-- into a stream. The operations in this type class correspond to similar
15-- operations in the 'Enum' type class, the only difference is that they produce
16-- a stream instead of a list. These operations cannot be defined generically
17-- based on the 'Enum' type class. We provide instances for commonly used
18-- types. If instances for other types are needed convenience functions defined
19-- in this module can be used to define them. Alternatively, these functions
20-- can be used directly.
22module Streamly.Internal.Data.Unfold.Enumeration
26 -- ** Enumerating 'Num' Types
27 , enumerateFromStepNum
29 , enumerateFromThenNum
31 -- ** Enumerating unbounded 'Integral' Types
32 , enumerateFromStepIntegral
33 , enumerateFromIntegral
34 , enumerateFromThenIntegral
35 , enumerateFromToIntegral
36 , enumerateFromThenToIntegral
38 -- ** Enumerating 'Bounded' 'Integral' Types
39 , enumerateFromIntegralBounded
40 , enumerateFromThenIntegralBounded
41 , enumerateFromToIntegralBounded
42 , enumerateFromThenToIntegralBounded
44 -- ** Enumerating small 'Integral' Types
45 -- | Small types are always bounded.
46 , enumerateFromSmallBounded
47 , enumerateFromThenSmallBounded
48 , enumerateFromToSmall
49 , enumerateFromThenToSmall
51 -- ** Enumerating 'Fractional' Types
52 -- | Enumeration of 'Num' specialized to 'Fractional' types.
53 , enumerateFromFractional
54 , enumerateFromThenFractional
55 , enumerateFromToFractional
56 , enumerateFromThenToFractional
62import Data.Bifunctor (bimap)
67import Data.Functor.Identity (Identity(..))
68import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
69import Streamly.Internal.Data.Unfold.Type
71 hiding (map, mapM, takeWhile, take, filter, const, zipWith
76-- >>> import qualified Streamly.Prelude as Stream
77-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
78-- >>> import Streamly.Internal.Data.Unfold.Type
79-- >>> import Data.Word
81------------------------------------------------------------------------------
83------------------------------------------------------------------------------
85-- | Unfolds @(from, stride)@ generating an infinite stream starting from
86-- @from@ and incrementing every time by @stride@. For 'Bounded' types, after
87-- the value overflows it keeps enumerating in a cycle:
90-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold Unfold.enumerateFromStepNum (255::Word8,1)
91-- [255,0,1,2,3,4,5,6,7,8]
95-- The implementation is numerically stable for floating point values.
97-- Note 'enumerateFromStepIntegral' is faster for integrals.
101{-# INLINE enumerateFromStepNum #-}
102enumerateFromStepNum :: (Monad m, Num a) => Unfold m (a, a) a
103enumerateFromStepNum = Unfold step inject
107 inject (!from, !stride) = return (from, stride, 0)
109 -- Note that the counter "i" is the same type as the type being enumerated.
110 -- It may overflow, for example, if we are enumerating Word8, after 255 the
111 -- counter will become 0, but the overflow does not affect the enumeration
113 {-# INLINE_LATE step #-}
114 step (from, stride, i) =
116 (Yield $! (from + i * stride)) $! (from, stride, i + 1)
118-- | Same as 'enumerateFromStepNum (from, next)' using a stride of @next - from@:
121-- >>> enumerateFromThenNum = lmap (\(from, next) -> (from, next - from)) Unfold.enumerateFromStepNum
127-- >>> Stream.toList $ Stream.take 10 $ Stream.unfold enumerateFromThenNum (255::Word8,0)
128-- [255,0,1,2,3,4,5,6,7,8]
132-- The implementation is numerically stable for floating point values.
134-- Note that 'enumerateFromThenIntegral' is faster for integrals.
136-- Note that in the strange world of floating point numbers, using
137-- @enumerateFromThenNum (from, from + 1)@ is almost exactly the same as
138-- @enumerateFromStepNum (from, 1) but not precisely the same. Because @(from +
139-- 1) - from@ is not exactly 1, it may lose some precision, the loss may also
140-- be aggregated in each step, if you want that precision then use
141-- 'enumerateFromStepNum' instead.
145{-# INLINE enumerateFromThenNum #-}
146enumerateFromThenNum :: (Monad m, Num a) => Unfold m (a, a) a
147enumerateFromThenNum =
148 lmap (\(from, next) -> (from, next - from)) enumerateFromStepNum
150-- | Same as 'enumerateFromStepNum' using a stride of 1:
153-- >>> enumerateFromNum = lmap (\from -> (from, 1)) Unfold.enumerateFromStepNum
154-- >>> Stream.toList $ Stream.take 6 $ Stream.unfold enumerateFromNum (0.9)
155-- [0.9,1.9,2.9,3.9,4.9,5.9]
159-- Also, same as 'enumerateFromThenNum' using a stride of 1 but see the note in
160-- 'enumerateFromThenNum' about the loss of precision:
163-- >>> enumerateFromNum = lmap (\from -> (from, from + 1)) Unfold.enumerateFromThenNum
164-- >>> Stream.toList $ Stream.take 6 $ Stream.unfold enumerateFromNum (0.9)
165-- [0.9,1.9,2.9,3.8999999999999995,4.8999999999999995,5.8999999999999995]
171{-# INLINE enumerateFromNum #-}
172enumerateFromNum :: (Monad m, Num a) => Unfold m a a
173enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum
175------------------------------------------------------------------------------
176-- Enumeration of Integrals
177------------------------------------------------------------------------------
179-- | Can be used to enumerate unbounded integrals. This does not check for
180-- overflow or underflow for bounded integrals.
183{-# INLINE_NORMAL enumerateFromStepIntegral #-}
184enumerateFromStepIntegral :: (Monad m, Integral a) => Unfold m (a, a) a
185enumerateFromStepIntegral = Unfold step inject
189 inject (from, stride) = from `seq` stride `seq` return (from, stride)
191 {-# INLINE_LATE step #-}
192 step (x, stride) = return $ Yield x $! (x + stride, stride)
194-- Enumerate Unbounded Integrals ----------------------------------------------
195{-# INLINE enumerateFromIntegral #-}
196enumerateFromIntegral :: (Monad m, Integral a) => Unfold m a a
197enumerateFromIntegral = lmap (\from -> (from, 1)) enumerateFromStepIntegral
199{-# INLINE enumerateFromThenIntegral #-}
200enumerateFromThenIntegral :: (Monad m, Integral a ) => Unfold m (a, a) a
201enumerateFromThenIntegral =
202 lmap (\(from, next) -> (from, next - from)) enumerateFromStepIntegral
204{-# INLINE enumerateFromToIntegral #-}
205enumerateFromToIntegral :: (Monad m, Integral a) => Unfold m (a, a) a
206enumerateFromToIntegral =
207 takeWhileMWithInput (\(_, to) b -> return $ b <= to)
208 $ lmap (\(from, _) -> (from, 1)) enumerateFromStepIntegral
210{-# INLINE enumerateFromThenToIntegral #-}
211enumerateFromThenToIntegral :: (Monad m, Integral a) => Unfold m (a, a, a) a
212enumerateFromThenToIntegral =
213 takeWhileMWithInput cond $ lmap toFromStep enumerateFromStepIntegral
217 toFromStep (from, next, _) = (from, next - from)
219 cond (from, next, to) b =
225-- Enumerate Bounded Integrals ------------------------------------------------
226{-# INLINE enumerateFromIntegralBounded #-}
227enumerateFromIntegralBounded :: (Monad m, Integral a, Bounded a) =>
229enumerateFromIntegralBounded = second maxBound enumerateFromToIntegral
231{-# INLINE enumerateFromThenIntegralBounded #-}
232enumerateFromThenIntegralBounded :: (Monad m, Integral a, Bounded a ) =>
234enumerateFromThenIntegralBounded =
235 takeWhileMWithInput cond $ lmap toFromStep enumerateFromStepIntegral
239 toFromStep (from, next) = (from, next - from)
241 cond (from, next) b =
247{-# INLINE enumerateFromToIntegralBounded #-}
248enumerateFromToIntegralBounded :: (Monad m, Integral a, Bounded a) =>
250enumerateFromToIntegralBounded =
251 takeWhileMWithInput (\(_, to) b -> return $ b <= to)
252 $ lmap fst enumerateFromIntegralBounded
254{-# INLINE enumerateFromThenToIntegralBounded #-}
255enumerateFromThenToIntegralBounded :: (Monad m, Integral a, Bounded a) =>
257enumerateFromThenToIntegralBounded =
258 takeWhileMWithInput cond $ lmap toFromThen enumerateFromThenIntegralBounded
262 toFromThen (from, next, _) = (from, next)
264 cond (from, next, to) b =
270------------------------------------------------------------------------------
271-- Enumeration of Fractionals
272------------------------------------------------------------------------------
274{-# INLINE_NORMAL enumerateFromFractional #-}
275enumerateFromFractional :: (Monad m, Fractional a) => Unfold m a a
276enumerateFromFractional = enumerateFromNum
278{-# INLINE_NORMAL enumerateFromThenFractional #-}
279enumerateFromThenFractional :: (Monad m, Fractional a) => Unfold m (a, a) a
280enumerateFromThenFractional = enumerateFromThenNum
282-- | Same as 'enumerateFromStepNum' with a step of 1 and enumerating up to the
283-- specified upper limit rounded to the nearest integral value:
286-- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromToFractional (0.1, 6.3)
287-- [0.1,1.1,2.1,3.1,4.1,5.1,6.1]
293{-# INLINE_NORMAL enumerateFromToFractional #-}
294enumerateFromToFractional :: (Monad m, Fractional a, Ord a) =>
296enumerateFromToFractional =
297 takeWhileMWithInput (\(_, to) b -> return $ b <= to + 1 / 2)
298 $ lmap (\(from, _) -> (from, 1)) enumerateFromStepNum
300{-# INLINE enumerateFromThenToFractional #-}
301enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) =>
303enumerateFromThenToFractional =
304 takeWhileMWithInput cond $ lmap toFromStep enumerateFromStepNum
308 toFromStep (from, next, _) = (from, next - from)
310 cond (from, next, to) b =
311 let stride = next - from
314 then b <= to + stride / 2
315 else b >= to + stride / 2
317-------------------------------------------------------------------------------
318-- Enumeration of Enum types not larger than Int
319-------------------------------------------------------------------------------
321-- | Enumerate from given starting Enum value 'from' and to Enum value 'to'
322-- with stride of 1 till to value.
326{-# INLINE enumerateFromToSmall #-}
327enumerateFromToSmall :: (Monad m, Enum a) => Unfold m (a, a) a
328enumerateFromToSmall =
329 fmap toEnum (lmap (bimap fromEnum fromEnum) enumerateFromToIntegral)
331-- | Enumerate from given starting Enum value 'from' and then Enum value 'next'
332-- and to Enum value 'to' with stride of (fromEnum next - fromEnum from)
337{-# INLINE enumerateFromThenToSmall #-}
338enumerateFromThenToSmall :: (Monad m, Enum a) => Unfold m (a, a, a) a
339enumerateFromThenToSmall =
340 let toInts (x, y, z) = (fromEnum x, fromEnum y, fromEnum z)
341 in fmap toEnum (lmap toInts enumerateFromThenToIntegral)
343-------------------------------------------------------------------------------
344-- Bounded Enumeration of Enum types not larger than Int
345-------------------------------------------------------------------------------
347-- | Enumerate from given starting Enum value 'from' with stride of 1 till
352{-# INLINE enumerateFromSmallBounded #-}
353enumerateFromSmallBounded :: (Monad m, Enum a, Bounded a) => Unfold m a a
354enumerateFromSmallBounded = second maxBound enumerateFromToSmall
356-- | Enumerate from given starting Enum value 'from' and next Enum value 'next'
357-- with stride of (fromEnum next - fromEnum from) till maxBound.
361{-# INLINE enumerateFromThenSmallBounded #-}
362enumerateFromThenSmallBounded :: forall m a. (Monad m, Enum a, Bounded a) =>
364enumerateFromThenSmallBounded =
365 let adapt (from, next) =
366 let frm = fromEnum from
370 then fromEnum (maxBound :: a)
371 else fromEnum (minBound :: a)
373 in fmap toEnum (lmap adapt enumerateFromThenToIntegral)
375-------------------------------------------------------------------------------
376-- Enumerable type class
377-------------------------------------------------------------------------------
379-- | Types that can be enumerated as a stream. The operations in this type
380-- class are equivalent to those in the 'Enum' type class, except that these
381-- generate a stream instead of a list. Use the functions in
382-- "Streamly.Internal.Data.Unfold.Enumeration" module to define new instances.
385class Enum a => Enumerable a where
387 -- | Unfolds @from@ generating a stream starting with the element
388 -- @from@, enumerating up to 'maxBound' when the type is 'Bounded' or
389 -- generating an infinite stream when the type is not 'Bounded'.
391 -- >>> import qualified Streamly.Prelude as Stream
392 -- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
395 -- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFrom (0 :: Int)
400 -- For 'Fractional' types, enumeration is numerically stable. However, no
401 -- overflow or underflow checks are performed.
404 -- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFrom 1.1
411 enumerateFrom :: Monad m => Unfold m a a
413 -- | Unfolds @(from, to)@ generating a finite stream starting with the element
414 -- @from@, enumerating the type up to the value @to@. If @to@ is smaller than
415 -- @from@ then an empty stream is returned.
417 -- >>> import qualified Streamly.Prelude as Stream
418 -- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
421 -- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromTo (0, 4)
426 -- For 'Fractional' types, the last element is equal to the specified @to@
427 -- value after rounding to the nearest integral value.
430 -- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromTo (1.1, 4)
433 -- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromTo (1.1, 4.6)
434 -- [1.1,2.1,3.1,4.1,5.1]
439 enumerateFromTo :: Monad m => Unfold m (a, a) a
441 -- | Unfolds @(from, then)@ generating a stream whose first element is
442 -- @from@ and the successive elements are in increments of @then@. Enumeration
443 -- can occur downwards or upwards depending on whether @then@ comes before or
444 -- after @from@. For 'Bounded' types the stream ends when 'maxBound' is
445 -- reached, for unbounded types it keeps enumerating infinitely.
447 -- >>> import qualified Streamly.Prelude as Stream
448 -- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
451 -- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFromThen (0, 2)
454 -- >>> Stream.toList $ Stream.take 4 $ Stream.unfold Unfold.enumerateFromThen (0,(-2))
460 enumerateFromThen :: Monad m => Unfold m (a, a) a
462 -- | Unfolds @(from, then, to)@ generating a finite stream whose first element
463 -- is @from@ and the successive elements are in increments of @then@ up to
464 -- @to@. Enumeration can occur downwards or upwards depending on whether @then@
465 -- comes before or after @from@.
467 -- >>> import qualified Streamly.Prelude as Stream
468 -- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
471 -- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromThenTo (0, 2, 6)
474 -- >>> Stream.toList $ Stream.unfold Unfold.enumerateFromThenTo (0, (-2), (-6))
480 enumerateFromThenTo :: Monad m => Unfold m (a, a, a) a
482-------------------------------------------------------------------------------
483-- Enumerable Instances
484-------------------------------------------------------------------------------
486-- For Enum types smaller than or equal to Int size.
487#define ENUMERABLE_BOUNDED_SMALL(SMALL_TYPE) \
488instance Enumerable SMALL_TYPE where { \
489 {-# INLINE enumerateFrom #-}; \
490 enumerateFrom = enumerateFromSmallBounded; \
491 {-# INLINE enumerateFromThen #-}; \
492 enumerateFromThen = enumerateFromThenSmallBounded; \
493 {-# INLINE enumerateFromTo #-}; \
494 enumerateFromTo = enumerateFromToSmall; \
495 {-# INLINE enumerateFromThenTo #-}; \
496 enumerateFromThenTo = enumerateFromThenToSmall }
498ENUMERABLE_BOUNDED_SMALL(())
499ENUMERABLE_BOUNDED_SMALL(Bool)
500ENUMERABLE_BOUNDED_SMALL(Ordering)
501ENUMERABLE_BOUNDED_SMALL(Char)
503-- For bounded Integral Enum types, may be larger than Int.
504#define ENUMERABLE_BOUNDED_INTEGRAL(INTEGRAL_TYPE) \
505instance Enumerable INTEGRAL_TYPE where { \
506 {-# INLINE enumerateFrom #-}; \
507 enumerateFrom = enumerateFromIntegralBounded; \
508 {-# INLINE enumerateFromThen #-}; \
509 enumerateFromThen = enumerateFromThenIntegralBounded; \
510 {-# INLINE enumerateFromTo #-}; \
511 enumerateFromTo = enumerateFromToIntegralBounded; \
512 {-# INLINE enumerateFromThenTo #-}; \
513 enumerateFromThenTo = enumerateFromThenToIntegralBounded }
515ENUMERABLE_BOUNDED_INTEGRAL(Int)
516ENUMERABLE_BOUNDED_INTEGRAL(Int8)
517ENUMERABLE_BOUNDED_INTEGRAL(Int16)
518ENUMERABLE_BOUNDED_INTEGRAL(Int32)
519ENUMERABLE_BOUNDED_INTEGRAL(Int64)
520ENUMERABLE_BOUNDED_INTEGRAL(Word)
521ENUMERABLE_BOUNDED_INTEGRAL(Word8)
522ENUMERABLE_BOUNDED_INTEGRAL(Word16)
523ENUMERABLE_BOUNDED_INTEGRAL(Word32)
524ENUMERABLE_BOUNDED_INTEGRAL(Word64)
526-- For unbounded Integral Enum types.
527#define ENUMERABLE_UNBOUNDED_INTEGRAL(INTEGRAL_TYPE) \
528instance Enumerable INTEGRAL_TYPE where { \
529 {-# INLINE enumerateFrom #-}; \
530 enumerateFrom = enumerateFromIntegral; \
531 {-# INLINE enumerateFromThen #-}; \
532 enumerateFromThen = enumerateFromThenIntegral; \
533 {-# INLINE enumerateFromTo #-}; \
534 enumerateFromTo = enumerateFromToIntegral; \
535 {-# INLINE enumerateFromThenTo #-}; \
536 enumerateFromThenTo = enumerateFromThenToIntegral }
538ENUMERABLE_UNBOUNDED_INTEGRAL(Integer)
539ENUMERABLE_UNBOUNDED_INTEGRAL(Natural)
541#define ENUMERABLE_FRACTIONAL(FRACTIONAL_TYPE,CONSTRAINT) \
542instance (CONSTRAINT) => Enumerable FRACTIONAL_TYPE where { \
543 {-# INLINE enumerateFrom #-}; \
544 enumerateFrom = enumerateFromFractional; \
545 {-# INLINE enumerateFromThen #-}; \
546 enumerateFromThen = enumerateFromThenFractional; \
547 {-# INLINE enumerateFromTo #-}; \
548 enumerateFromTo = enumerateFromToFractional; \
549 {-# INLINE enumerateFromThenTo #-}; \
550 enumerateFromThenTo = enumerateFromThenToFractional }
552ENUMERABLE_FRACTIONAL(Float,)
553ENUMERABLE_FRACTIONAL(Double,)
554ENUMERABLE_FRACTIONAL((Fixed a),HasResolution a)
555ENUMERABLE_FRACTIONAL((Ratio a),Integral a)
557instance Enumerable a => Enumerable (Identity a) where
558 {-# INLINE enumerateFrom #-}
560 map Identity $ lmap runIdentity enumerateFrom
561 {-# INLINE enumerateFromThen #-}
563 map Identity $ lmap (bimap runIdentity runIdentity) enumerateFromThen
564 {-# INLINE enumerateFromTo #-}
566 map Identity $ lmap (bimap runIdentity runIdentity) enumerateFromThen
567 {-# INLINE enumerateFromThenTo #-}
568 enumerateFromThenTo =
571 (\(from, next, to) ->
572 (runIdentity from, runIdentity next, runIdentity to))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list