on 5054813 help sign in
1339 lines 39 kB history raw
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE ExistentialQuantification #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE RecordWildCards #-}
7{-# LANGUAGE ScopedTypeVariables #-}
9-- |
10-- Module : Streamly.Internal.Data.Fold
11-- Copyright : (c) 2019 Composewell Technologies
12-- (c) 2013 Gabriel Gonzalez
13-- License : BSD3
14-- Maintainer : streamly@composewell.com
15-- Stability : experimental
16-- Portability : GHC
18-- Also see the "Streamly.Internal.Data.Sink" module that provides specialized left folds
19-- that discard the outputs.
20--
21-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
23module Streamly.Internal.Data.Fold
24 (
25 -- * Fold Type
26 Fold (..)
28 , hoist
29 , generally
31 -- , tail
32 -- , init
34 -- * Fold Creation Utilities
35 , mkPure
36 , mkPureId
37 , mkFold
38 , mkFoldId
40 -- ** Full Folds
41 , drain
42 , drainBy
43 , drainBy2
44 , last
45 , length
46 , sum
47 , product
48 , maximumBy
49 , maximum
50 , minimumBy
51 , minimum
52 -- , the
53 , mean
54 , variance
55 , stdDev
56 , rollingHash
57 , rollingHashWithSalt
58 , rollingHashFirstN
59 -- , rollingHashLastN
61 -- ** Full Folds (Monoidal)
62 , mconcat
63 , foldMap
64 , foldMapM
66 -- ** Full Folds (To Containers)
68 , toList
69 , toListRevF -- experimental
71 -- ** Partial Folds
72 , drainN
73 , drainWhile
74 -- , lastN
75 -- , (!!)
76 -- , genericIndex
77 , index
78 , head
79 -- , findM
80 , find
81 , lookup
82 , findIndex
83 , elemIndex
84 , null
85 , elem
86 , notElem
87 -- XXX these are slower than right folds even when full input is used
88 , all
89 , any
90 , and
91 , or
93 -- * Transformations
95 -- ** Covariant Operations
96 , sequence
97 , mapM
99 -- ** Mapping
100 , transform
101 , lmap
102 --, lsequence
103 , lmapM
104 -- ** Filtering
105 , lfilter
106 , lfilterM
107 -- , ldeleteBy
108 -- , luniq
109 , lcatMaybes
111 {-
112 -- ** Mapping Filters
113 , lmapMaybe
114 , lmapMaybeM
116 -- ** Scanning Filters
117 , lfindIndices
118 , lelemIndices
120 -- ** Insertion
121 -- | Insertion adds more elements to the stream.
123 , linsertBy
124 , lintersperseM
126 -- ** Reordering
127 , lreverse
128 -}
130 -- * Parsing
131 -- ** Trimming
132 , ltake
133 -- , lrunFor -- time
134 , ltakeWhile
135 {-
136 , ltakeWhileM
137 , ldrop
138 , ldropWhile
139 , ldropWhileM
140 -}
142 , lsessionsOf
143 , lchunksOf
145 -- * Distributing
147 , tee
148 , distribute
149 , distribute_
151 -- * Partitioning
153 -- , partitionByM
154 -- , partitionBy
155 , partition
157 -- * Demultiplexing
159 , demux
160 -- , demuxWith
161 , demux_
162 , demuxDefault_
163 -- , demuxWith_
164 , demuxWithDefault_
166 -- * Classifying
168 , classify
169 -- , classifyWith
171 -- * Unzipping
172 , unzip
173 -- These can be expressed using lmap/lmapM and unzip
174 -- , unzipWith
175 -- , unzipWithM
177 -- * Running Folds
178 , initialize
179 , runStep
181 -- * Nested Folds
182 -- , concatMap
183 -- , chunksOf
184 , duplicate -- experimental
186 -- * Folding to SVar
187 , toParallelSVar
188 , toParallelSVarLimited
189 )
190where
192import Control.Monad (void)
193import Control.Monad.IO.Class (MonadIO(..))
194import Data.Functor.Identity (Identity(..))
195import Data.Map.Strict (Map)
197import Prelude
198 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
199 foldl, map, mapM_, sequence, all, any, sum, product, elem,
200 notElem, maximum, minimum, head, last, tail, length, null,
201 reverse, iterate, init, and, or, lookup, foldr1, (!!),
202 scanl, scanl1, replicate, concatMap, mconcat, foldMap, unzip,
203 span, splitAt, break, mapM)
205import qualified Data.Map.Strict as Map
206import qualified Prelude
208import Streamly.Internal.Data.Pipe.Types (Pipe (..), PipeState(..))
209import Streamly.Internal.Data.Fold.Types
210import Streamly.Internal.Data.Strict
211import Streamly.Internal.Data.SVar
213import qualified Streamly.Internal.Data.Pipe.Types as Pipe
215------------------------------------------------------------------------------
216-- Smart constructors
217------------------------------------------------------------------------------
219-- | Make a fold using a pure step function, a pure initial state and
220-- a pure state extraction function.
221--
222-- /Internal/
223--
224{-# INLINE mkPure #-}
225mkPure :: Monad m => (s -> a -> s) -> s -> (s -> b) -> Fold m a b
226mkPure step initial extract =
227 Fold (\s a -> return $ step s a) (return initial) (return . extract)
229-- | Make a fold using a pure step function and a pure initial state. The
230-- final state extracted is identical to the intermediate state.
231--
232-- /Internal/
233--
234{-# INLINE mkPureId #-}
235mkPureId :: Monad m => (b -> a -> b) -> b -> Fold m a b
236mkPureId step initial = mkPure step initial id
238-- | Make a fold with an effectful step function and initial state, and a state
239-- extraction function.
240--
241-- > mkFold = Fold
242--
243-- We can just use 'Fold' but it is provided for completeness.
244--
245-- /Internal/
246--
247{-# INLINE mkFold #-}
248mkFold :: (s -> a -> m s) -> m s -> (s -> m b) -> Fold m a b
249mkFold = Fold
251-- | Make a fold with an effectful step function and initial state. The final
252-- state extracted is identical to the intermediate state.
253--
254-- /Internal/
255--
256{-# INLINE mkFoldId #-}
257mkFoldId :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
258mkFoldId step initial = Fold step initial return
260------------------------------------------------------------------------------
261-- hoist
262------------------------------------------------------------------------------
264-- | Change the underlying monad of a fold
265--
266-- /Internal/
267hoist :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
268hoist f (Fold step initial extract) =
269 Fold (\x a -> f $ step x a) (f initial) (f . extract)
271-- | Adapt a pure fold to any monad
272--
273-- > generally = hoist (return . runIdentity)
274--
275-- /Internal/
276generally :: Monad m => Fold Identity a b -> Fold m a b
277generally = hoist (return . runIdentity)
279------------------------------------------------------------------------------
280-- Transformations on fold inputs
281------------------------------------------------------------------------------
283-- | Flatten the monadic output of a fold to pure output.
284--
285-- @since 0.7.0
286{-# INLINE sequence #-}
287sequence :: Monad m => Fold m a (m b) -> Fold m a b
288sequence (Fold step initial extract) = Fold step initial extract'
289 where
290 extract' x = do
291 act <- extract x
292 act >>= return
294-- | Map a monadic function on the output of a fold.
295--
296-- @since 0.7.0
297{-# INLINE mapM #-}
298mapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
299mapM f = sequence . fmap f
301------------------------------------------------------------------------------
302-- Transformations on fold inputs
303------------------------------------------------------------------------------
305-- rename to lpipe?
306--
307-- | Apply a transformation on a 'Fold' using a 'Pipe'.
308--
309-- @since 0.7.0
310{-# INLINE transform #-}
311transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
312transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
313 Fold step initial extract
315 where
317 initial = Tuple' <$> return pinitial <*> finitial
318 step (Tuple' ps fs) x = do
319 r <- pstep1 ps x
320 go fs r
322 where
323 -- XXX use SPEC?
324 go acc (Pipe.Yield b (Consume ps')) = do
325 acc' <- fstep acc b
326 return (Tuple' ps' acc')
328 go acc (Pipe.Yield b (Produce ps')) = do
329 acc' <- fstep acc b
330 r <- pstep2 ps'
331 go acc' r
333 go acc (Pipe.Continue (Consume ps')) = return (Tuple' ps' acc)
335 go acc (Pipe.Continue (Produce ps')) = do
336 r <- pstep2 ps'
337 go acc r
339 extract (Tuple' _ fs) = fextract fs
341------------------------------------------------------------------------------
342-- Utilities
343------------------------------------------------------------------------------
345-- | @_Fold1 step@ returns a new 'Fold' using just a step function that has the
346-- same type for the accumulator and the element. The result type is the
347-- accumulator type wrapped in 'Maybe'. The initial accumulator is retrieved
348-- from the 'Foldable', the result is 'None' for empty containers.
349{-# INLINABLE _Fold1 #-}
350_Fold1 :: Monad m => (a -> a -> a) -> Fold m a (Maybe a)
351_Fold1 step = Fold step_ (return Nothing') fromStrictMaybe
352 where
353 step_ mx a = return $ Just' $
354 case mx of
355 Nothing' -> a
356 Just' x -> step x a
358------------------------------------------------------------------------------
359-- Left folds
360------------------------------------------------------------------------------
362------------------------------------------------------------------------------
363-- Run Effects
364------------------------------------------------------------------------------
366-- | A fold that drains all its input, running the effects and discarding the
367-- results.
368--
369-- @since 0.7.0
370{-# INLINABLE drain #-}
371drain :: Monad m => Fold m a ()
372drain = Fold step begin done
373 where
374 begin = return ()
375 step _ _ = return ()
376 done = return
378-- |
379-- > drainBy f = lmapM f drain
380--
381-- Drain all input after passing it through a monadic function. This is the
382-- dual of mapM_ on stream producers.
383--
384-- @since 0.7.0
385{-# INLINABLE drainBy #-}
386drainBy :: Monad m => (a -> m b) -> Fold m a ()
387drainBy f = Fold (const (void . f)) (return ()) return
389{-# INLINABLE drainBy2 #-}
390drainBy2 :: Monad m => (a -> m b) -> Fold2 m c a ()
391drainBy2 f = Fold2 (const (void . f)) (\_ -> return ()) return
393-- | Extract the last element of the input stream, if any.
394--
395-- @since 0.7.0
396{-# INLINABLE last #-}
397last :: Monad m => Fold m a (Maybe a)
398last = _Fold1 (flip const)
400------------------------------------------------------------------------------
401-- To Summary
402------------------------------------------------------------------------------
404-- | Like 'length', except with a more general 'Num' return value
405--
406-- @since 0.7.0
407{-# INLINABLE genericLength #-}
408genericLength :: (Monad m, Num b) => Fold m a b
409genericLength = Fold (\n _ -> return $ n + 1) (return 0) return
411-- | Determine the length of the input stream.
412--
413-- @since 0.7.0
414{-# INLINABLE length #-}
415length :: Monad m => Fold m a Int
416length = genericLength
418-- | Determine the sum of all elements of a stream of numbers. Returns additive
419-- identity (@0@) when the stream is empty. Note that this is not numerically
420-- stable for floating point numbers.
421--
422-- @since 0.7.0
423{-# INLINABLE sum #-}
424sum :: (Monad m, Num a) => Fold m a a
425sum = Fold (\x a -> return $ x + a) (return 0) return
427-- | Determine the product of all elements of a stream of numbers. Returns
428-- multiplicative identity (@1@) when the stream is empty.
429--
430-- @since 0.7.0
431{-# INLINABLE product #-}
432product :: (Monad m, Num a) => Fold m a a
433product = Fold (\x a -> return $ x * a) (return 1) return
435------------------------------------------------------------------------------
436-- To Summary (Maybe)
437------------------------------------------------------------------------------
439-- | Determine the maximum element in a stream using the supplied comparison
440-- function.
441--
442-- @since 0.7.0
443{-# INLINABLE maximumBy #-}
444maximumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
445maximumBy cmp = _Fold1 max'
446 where
447 max' x y = case cmp x y of
448 GT -> x
449 _ -> y
451-- |
452-- @
453-- maximum = 'maximumBy' compare
454-- @
455--
456-- Determine the maximum element in a stream.
457--
458-- @since 0.7.0
459{-# INLINABLE maximum #-}
460maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
461maximum = _Fold1 max
463-- | Computes the minimum element with respect to the given comparison function
464--
465-- @since 0.7.0
466{-# INLINABLE minimumBy #-}
467minimumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
468minimumBy cmp = _Fold1 min'
469 where
470 min' x y = case cmp x y of
471 GT -> y
472 _ -> x
474-- | Determine the minimum element in a stream using the supplied comparison
475-- function.
476--
477-- @since 0.7.0
478{-# INLINABLE minimum #-}
479minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
480minimum = _Fold1 min
482------------------------------------------------------------------------------
483-- To Summary (Statistical)
484------------------------------------------------------------------------------
486-- | Compute a numerically stable arithmetic mean of all elements in the input
487-- stream.
488--
489-- @since 0.7.0
490{-# INLINABLE mean #-}
491mean :: (Monad m, Fractional a) => Fold m a a
492mean = Fold step (return begin) (return . done)
493 where
494 begin = Tuple' 0 0
495 step (Tuple' x n) y = return $
496 let n' = n + 1
497 in Tuple' (x + (y - x) / n') n'
498 done (Tuple' x _) = x
500-- | Compute a numerically stable (population) variance over all elements in
501-- the input stream.
502--
503-- @since 0.7.0
504{-# INLINABLE variance #-}
505variance :: (Monad m, Fractional a) => Fold m a a
506variance = Fold step (return begin) (return . done)
507 where
508 begin = Tuple3' 0 0 0
510 step (Tuple3' n mean_ m2) x = return $ Tuple3' n' mean' m2'
511 where
512 n' = n + 1
513 mean' = (n * mean_ + x) / (n + 1)
514 delta = x - mean_
515 m2' = m2 + delta * delta * n / (n + 1)
517 done (Tuple3' n _ m2) = m2 / n
519-- | Compute a numerically stable (population) standard deviation over all
520-- elements in the input stream.
521--
522-- @since 0.7.0
523{-# INLINABLE stdDev #-}
524stdDev :: (Monad m, Floating a) => Fold m a a
525stdDev = sqrt variance
527-- | Compute an 'Int' sized polynomial rolling hash
528--
529-- > H = salt * k ^ n + c1 * k ^ (n - 1) + c2 * k ^ (n - 2) + ... + cn * k ^ 0
530--
531-- Where @c1@, @c2@, @cn@ are the elements in the input stream and @k@ is a
532-- constant.
533--
534-- This hash is often used in Rabin-Karp string search algorithm.
535--
536-- See https://en.wikipedia.org/wiki/Rolling_hash
537--
538-- @since 0.7.0
539{-# INLINABLE rollingHashWithSalt #-}
540rollingHashWithSalt :: (Monad m, Enum a) => Int -> Fold m a Int
541rollingHashWithSalt salt = Fold step initial extract
542 where
543 k = 2891336453
544 initial = return salt
545 step cksum a = return $ cksum * k + fromEnum a
546 extract = return
548-- | A default salt used in the implementation of 'rollingHash'.
549{-# INLINE defaultSalt #-}
550defaultSalt :: Int
551#if WORD_SIZE_IN_BITS == 64
552defaultSalt = 0xdc36d1615b7400a4
553#else
554defaultSalt = 0x087fc72c
555#endif
557-- | Compute an 'Int' sized polynomial rolling hash of a stream.
558--
559-- > rollingHash = rollingHashWithSalt defaultSalt
560--
561-- @since 0.7.0
562{-# INLINABLE rollingHash #-}
563rollingHash :: (Monad m, Enum a) => Fold m a Int
564rollingHash = rollingHashWithSalt defaultSalt
566-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
567-- a stream.
568--
569-- > rollingHashFirstN = ltake n rollingHash
570{-# INLINABLE rollingHashFirstN #-}
571rollingHashFirstN :: (Monad m, Enum a) => Int -> Fold m a Int
572rollingHashFirstN n = ltake n rollingHash
574------------------------------------------------------------------------------
575-- Monoidal left folds
576------------------------------------------------------------------------------
578-- | Fold an input stream consisting of monoidal elements using 'mappend'
579-- and 'mempty'.
580--
581-- > S.fold FL.mconcat (S.map Sum $ S.enumerateFromTo 1 10)
582--
583-- @since 0.7.0
584{-# INLINABLE mconcat #-}
585mconcat :: (Monad m, Monoid a) => Fold m a a
586mconcat = Fold (\x a -> return $ mappend x a) (return mempty) return
588-- |
589-- > foldMap f = map f mconcat
590--
591-- Make a fold from a pure function that folds the output of the function
592-- using 'mappend' and 'mempty'.
593--
594-- > S.fold (FL.foldMap Sum) $ S.enumerateFromTo 1 10
595--
596-- @since 0.7.0
597{-# INLINABLE foldMap #-}
598foldMap :: (Monad m, Monoid b) => (a -> b) -> Fold m a b
599foldMap f = lmap f mconcat
601-- |
602-- > foldMapM f = mapM f mconcat
603--
604-- Make a fold from a monadic function that folds the output of the function
605-- using 'mappend' and 'mempty'.
606--
607-- > S.fold (FL.foldMapM (return . Sum)) $ S.enumerateFromTo 1 10
608--
609-- @since 0.7.0
610{-# INLINABLE foldMapM #-}
611foldMapM :: (Monad m, Monoid b) => (a -> m b) -> Fold m a b
612foldMapM act = Fold step begin done
613 where
614 done = return
615 begin = return mempty
616 step m a = do
617 m' <- act a
618 return $! mappend m m'
620------------------------------------------------------------------------------
621-- To Containers
622------------------------------------------------------------------------------
624-- | Folds the input stream to a list.
625--
626-- /Warning!/ working on large lists accumulated as buffers in memory could be
627-- very inefficient, consider using "Streamly.Memory.Array" instead.
628--
629-- @since 0.7.0
631-- id . (x1 :) . (x2 :) . (x3 :) . ... . (xn :) $ []
632{-# INLINABLE toList #-}
633toList :: Monad m => Fold m a [a]
634toList = Fold (\f x -> return $ f . (x :))
635 (return id)
636 (return . ($ []))
638------------------------------------------------------------------------------
639-- Partial Folds
640------------------------------------------------------------------------------
642-- | A fold that drains the first n elements of its input, running the effects
643-- and discarding the results.
644{-# INLINABLE drainN #-}
645drainN :: Monad m => Int -> Fold m a ()
646drainN n = ltake n drain
648-- | A fold that drains elements of its input as long as the predicate succeeds,
649-- running the effects and discarding the results.
650{-# INLINABLE drainWhile #-}
651drainWhile :: Monad m => (a -> Bool) -> Fold m a ()
652drainWhile p = ltakeWhile p drain
654------------------------------------------------------------------------------
655-- To Elements
656------------------------------------------------------------------------------
658-- | Like 'index', except with a more general 'Integral' argument
659--
660-- @since 0.7.0
661{-# INLINABLE genericIndex #-}
662genericIndex :: (Integral i, Monad m) => i -> Fold m a (Maybe a)
663genericIndex i = Fold step (return $ Left' 0) done
664 where
665 step x a = return $
666 case x of
667 Left' j -> if i == j
668 then Right' a
669 else Left' (j + 1)
670 _ -> x
671 done x = return $
672 case x of
673 Left' _ -> Nothing
674 Right' a -> Just a
676-- | Lookup the element at the given index.
677--
678-- @since 0.7.0
679{-# INLINABLE index #-}
680index :: Monad m => Int -> Fold m a (Maybe a)
681index = genericIndex
683-- | Extract the first element of the stream, if any.
684--
685-- @since 0.7.0
686{-# INLINABLE head #-}
687head :: Monad m => Fold m a (Maybe a)
688head = _Fold1 const
690-- | Returns the first element that satisfies the given predicate.
691--
692-- @since 0.7.0
693{-# INLINABLE find #-}
694find :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
695find predicate = Fold step (return Nothing') fromStrictMaybe
696 where
697 step x a = return $
698 case x of
699 Nothing' -> if predicate a
700 then Just' a
701 else Nothing'
702 _ -> x
704-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
705-- first pair where the key equals the given value @a@.
706--
707-- @since 0.7.0
708{-# INLINABLE lookup #-}
709lookup :: (Eq a, Monad m) => a -> Fold m (a,b) (Maybe b)
710lookup a0 = Fold step (return Nothing') fromStrictMaybe
711 where
712 step x (a,b) = return $
713 case x of
714 Nothing' -> if a == a0
715 then Just' b
716 else Nothing'
717 _ -> x
719-- | Convert strict 'Either'' to lazy 'Maybe'
720{-# INLINABLE hush #-}
721hush :: Either' a b -> Maybe b
722hush (Left' _) = Nothing
723hush (Right' b) = Just b
725-- | Returns the first index that satisfies the given predicate.
726--
727-- @since 0.7.0
728{-# INLINABLE findIndex #-}
729findIndex :: Monad m => (a -> Bool) -> Fold m a (Maybe Int)
730findIndex predicate = Fold step (return $ Left' 0) (return . hush)
731 where
732 step x a = return $
733 case x of
734 Left' i ->
735 if predicate a
736 then Right' i
737 else Left' (i + 1)
738 _ -> x
740-- | Returns the first index where a given value is found in the stream.
741--
742-- @since 0.7.0
743{-# INLINABLE elemIndex #-}
744elemIndex :: (Eq a, Monad m) => a -> Fold m a (Maybe Int)
745elemIndex a = findIndex (a ==)
747------------------------------------------------------------------------------
748-- To Boolean
749------------------------------------------------------------------------------
751-- | Return 'True' if the input stream is empty.
752--
753-- @since 0.7.0
754{-# INLINABLE null #-}
755null :: Monad m => Fold m a Bool
756null = Fold (\_ _ -> return False) (return True) return
758-- |
759-- > any p = lmap p or
760--
761-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
762--
763-- @since 0.7.0
764{-# INLINABLE any #-}
765any :: Monad m => (a -> Bool) -> Fold m a Bool
766any predicate = Fold (\x a -> return $ x || predicate a) (return False) return
768-- | Return 'True' if the given element is present in the stream.
769--
770-- @since 0.7.0
771{-# INLINABLE elem #-}
772elem :: (Eq a, Monad m) => a -> Fold m a Bool
773elem a = any (a ==)
775-- |
776-- > all p = lmap p and
777--
778-- | Returns 'True' if all elements of a stream satisfy a predicate.
779--
780-- @since 0.7.0
781{-# INLINABLE all #-}
782all :: Monad m => (a -> Bool) -> Fold m a Bool
783all predicate = Fold (\x a -> return $ x && predicate a) (return True) return
785-- | Returns 'True' if the given element is not present in the stream.
786--
787-- @since 0.7.0
788{-# INLINABLE notElem #-}
789notElem :: (Eq a, Monad m) => a -> Fold m a Bool
790notElem a = all (a /=)
792-- | Returns 'True' if all elements are 'True', 'False' otherwise
793--
794-- @since 0.7.0
795{-# INLINABLE and #-}
796and :: Monad m => Fold m Bool Bool
797and = Fold (\x a -> return $ x && a) (return True) return
799-- | Returns 'True' if any element is 'True', 'False' otherwise
800--
801-- @since 0.7.0
802{-# INLINABLE or #-}
803or :: Monad m => Fold m Bool Bool
804or = Fold (\x a -> return $ x || a) (return False) return
806------------------------------------------------------------------------------
807-- Distributing
808------------------------------------------------------------------------------
809--
810-- | Distribute one copy of the stream to each fold and zip the results.
811--
812-- @
813-- |-------Fold m a b--------|
814-- ---stream m a---| |---m (b,c)
815-- |-------Fold m a c--------|
816-- @
817-- >>> S.fold (FL.tee FL.sum FL.length) (S.enumerateFromTo 1.0 100.0)
818-- (5050.0,100)
819--
820-- @since 0.7.0
821{-# INLINE tee #-}
822tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
823tee f1 f2 = (,) <$> f1 <*> f2
825{-# INLINE foldNil #-}
826foldNil :: Monad m => Fold m a [b]
827foldNil = Fold step begin done where
828 begin = return []
829 step _ _ = return []
830 done = return
832{-# INLINE foldCons #-}
833foldCons :: Monad m => Fold m a b -> Fold m a [b] -> Fold m a [b]
834foldCons (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
835 Fold step begin done
837 where
839 begin = Tuple' <$> beginL <*> beginR
840 step (Tuple' xL xR) a = Tuple' <$> stepL xL a <*> stepR xR a
841 done (Tuple' xL xR) = (:) <$> (doneL xL) <*> (doneR xR)
843-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
844-- number of consumers? For polymorphic case a vector could be helpful. For
845-- Storables we can use arrays. Will need separate APIs for those.
846--
847-- | Distribute one copy of the stream to each fold and collect the results in
848-- a container.
849--
850-- @
851--
852-- |-------Fold m a b--------|
853-- ---stream m a---| |---m [b]
854-- |-------Fold m a b--------|
855-- | |
856-- ...
857-- @
858--
859-- >>> S.fold (FL.distribute [FL.sum, FL.length]) (S.enumerateFromTo 1 5)
860-- [15,5]
861--
862-- This is the consumer side dual of the producer side 'sequence' operation.
863--
864-- @since 0.7.0
865{-# INLINE distribute #-}
866distribute :: Monad m => [Fold m a b] -> Fold m a [b]
867distribute [] = foldNil
868distribute (x:xs) = foldCons x (distribute xs)
870-- | Like 'distribute' but for folds that return (), this can be more efficient
871-- than 'distribute' as it does not need to maintain state.
872--
873{-# INLINE distribute_ #-}
874distribute_ :: Monad m => [Fold m a ()] -> Fold m a ()
875distribute_ fs = Fold step initial extract
876 where
877 initial = Prelude.mapM (\(Fold s i e) ->
878 i >>= \r -> return (Fold s (return r) e)) fs
879 step ss a = do
880 Prelude.mapM_ (\(Fold s i _) -> i >>= \r -> s r a >> return ()) ss
881 return ss
882 extract ss = do
883 Prelude.mapM_ (\(Fold _ i e) -> i >>= \r -> e r) ss
884 return ()
886------------------------------------------------------------------------------
887-- Partitioning
888------------------------------------------------------------------------------
889--
890-- | Partition the input over two folds using an 'Either' partitioning
891-- predicate.
892--
893-- @
894--
895-- |-------Fold b x--------|
896-- -----stream m a --> (Either b c)----| |----(x,y)
897-- |-------Fold c y--------|
898-- @
899--
900-- Send input to either fold randomly:
901--
902-- >>> import System.Random (randomIO)
903-- >>> randomly a = randomIO >>= \x -> return $ if x then Left a else Right a
904-- >>> S.fold (FL.partitionByM randomly FL.length FL.length) (S.enumerateFromTo 1 100)
905-- (59,41)
906--
907-- Send input to the two folds in a proportion of 2:1:
908--
909-- @
910-- import Data.IORef (newIORef, readIORef, writeIORef)
911-- proportionately m n = do
912-- ref <- newIORef $ cycle $ concat [replicate m Left, replicate n Right]
913-- return $ \\a -> do
914-- r <- readIORef ref
915-- writeIORef ref $ tail r
916-- return $ head r a
917--
918-- main = do
919-- f <- proportionately 2 1
920-- r <- S.fold (FL.partitionByM f FL.length FL.length) (S.enumerateFromTo (1 :: Int) 100)
921-- print r
922-- @
923-- @
924-- (67,33)
925-- @
926--
927-- This is the consumer side dual of the producer side 'mergeBy' operation.
928--
929-- @since 0.7.0
930{-# INLINE partitionByM #-}
931partitionByM :: Monad m
932 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
933partitionByM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
935 Fold step begin done
937 where
939 begin = Tuple' <$> beginL <*> beginR
940 step (Tuple' xL xR) a = do
941 r <- f a
942 case r of
943 Left b -> Tuple' <$> stepL xL b <*> return xR
944 Right c -> Tuple' <$> return xL <*> stepR xR c
945 done (Tuple' xL xR) = (,) <$> doneL xL <*> doneR xR
947-- Note: we could use (a -> Bool) instead of (a -> Either b c), but the latter
948-- makes the signature clearer as to which case belongs to which fold.
949-- XXX need to check the performance in both cases.
951-- | Same as 'partitionByM' but with a pure partition function.
952--
953-- Count even and odd numbers in a stream:
954--
955-- @
956-- >>> let f = FL.partitionBy (\\n -> if even n then Left n else Right n)
957-- (fmap (("Even " ++) . show) FL.length)
958-- (fmap (("Odd " ++) . show) FL.length)
959-- in S.fold f (S.enumerateFromTo 1 100)
960-- ("Even 50","Odd 50")
961-- @
962--
963-- @since 0.7.0
964{-# INLINE partitionBy #-}
965partitionBy :: Monad m
966 => (a -> Either b c) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
967partitionBy f = partitionByM (return . f)
969-- | Compose two folds such that the combined fold accepts a stream of 'Either'
970-- and routes the 'Left' values to the first fold and 'Right' values to the
971-- second fold.
972--
973-- > partition = partitionBy id
974--
975-- @since 0.7.0
976{-# INLINE partition #-}
977partition :: Monad m
978 => Fold m b x -> Fold m c y -> Fold m (Either b c) (x, y)
979partition = partitionBy id
981{-
982-- | Send one item to each fold in a round-robin fashion. This is the consumer
983-- side dual of producer side 'mergeN' operation.
984--
985-- partitionN :: Monad m => [Fold m a b] -> Fold m a [b]
986-- partitionN fs = Fold step begin done
987-}
989-- TODO Demultiplex an input element into a number of typed variants. We want
990-- to statically restrict the target values within a set of predefined types,
991-- an enumeration of a GADT. We also want to make sure that the Map contains
992-- only those types and the full set of those types.
993--
994-- TODO Instead of the input Map it should probably be a lookup-table using an
995-- array and not in GC memory. The same applies to the output Map as well.
996-- However, that would only be helpful if we have a very large data structure,
997-- need to measure and see how it scales.
998--
999-- This is the consumer side dual of the producer side 'mux' operation (XXX to
1000-- be implemented).
1002-- | Split the input stream based on a key field and fold each split using a
1003-- specific fold collecting the results in a map from the keys to the results.
1004-- Useful for cases like protocol handlers to handle different type of packets
1005-- using different handlers.
1007-- @
1009-- |-------Fold m a b
1010-- -----stream m a-----Map-----|
1011-- |-------Fold m a b
1012-- |
1013-- ...
1014-- @
1016-- @since 0.7.0
1017{-# INLINE demuxWith #-}
1018demuxWith :: (Monad m, Ord k)
1019 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a (Map k b)
1020demuxWith f kv = Fold step initial extract
1022 where
1024 initial = return kv
1025-- alterF is available only since containers version 0.5.8.2
1026#if MIN_VERSION_containers(0,5,8)
1027 step mp a = case f a of
1028 (k, a') -> Map.alterF twiddle k mp
1029 -- XXX should we raise an exception in Nothing case?
1030 -- Ideally we should enforce that it is a total map over k so that look
1031 -- up never fails
1032 -- XXX we could use a monadic update function for a single lookup and
1033 -- update in the map.
1034 where
1035 twiddle Nothing = pure Nothing
1036 twiddle (Just (Fold step' acc extract')) = do
1037 !r <- acc >>= \x -> step' x a'
1038 pure . Just $ Fold step' (return r) extract'
1039#else
1040 step mp a =
1041 let (k, a') = f a
1042 in case Map.lookup k mp of
1043 Nothing -> return mp
1044 Just (Fold step' acc extract') -> do
1045 !r <- acc >>= \x -> step' x a'
1046 return $ Map.insert k (Fold step' (return r) extract') mp
1047#endif
1048 extract = Prelude.mapM (\(Fold _ acc e) -> acc >>= e)
1050-- | Fold a stream of key value pairs using a map of specific folds for each
1051-- key into a map from keys to the results of fold outputs of the corresponding
1052-- values.
1054-- @
1055-- > let table = Data.Map.fromList [(\"SUM", FL.sum), (\"PRODUCT", FL.product)]
1056-- input = S.fromList [(\"SUM",1),(\"PRODUCT",2),(\"SUM",3),(\"PRODUCT",4)]
1057-- in S.fold (FL.demux table) input
1058-- One 1
1059-- Two 2
1060-- @
1062-- @since 0.7.0
1063{-# INLINE demux #-}
1064demux :: (Monad m, Ord k)
1065 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
1066demux = demuxWith id
1068{-# INLINE demuxWithDefault_ #-}
1069demuxWithDefault_ :: (Monad m, Ord k)
1070 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m (k, a') b -> Fold m a ()
1071demuxWithDefault_ f kv (Fold dstep dinitial dextract) =
1072 Fold step initial extract
1074 where
1076 initFold (Fold s i e) = i >>= \r -> return (Fold s (return r) e)
1077 initial = do
1078 mp <- Prelude.mapM initFold kv
1079 dacc <- dinitial
1080 return (Tuple' mp dacc)
1081 step (Tuple' mp dacc) a
1082 | (k, a') <- f a
1083 = case Map.lookup k mp of
1084 Nothing -> do
1085 acc <- dstep dacc (k, a')
1086 return (Tuple' mp acc)
1087 Just (Fold step' acc _) -> do
1088 _ <- acc >>= \x -> step' x a'
1089 return (Tuple' mp dacc)
1090 extract (Tuple' mp dacc) = do
1091 void $ dextract dacc
1092 Prelude.mapM_ (\(Fold _ acc e) -> acc >>= e) mp
1094-- | Split the input stream based on a key field and fold each split using a
1095-- specific fold without collecting the results. Useful for cases like protocol
1096-- handlers to handle different type of packets.
1098-- @
1100-- |-------Fold m a ()
1101-- -----stream m a-----Map-----|
1102-- |-------Fold m a ()
1103-- |
1104-- ...
1105-- @
1108-- @since 0.7.0
1110-- demuxWith_ can be slightly faster than demuxWith because we do not need to
1111-- update the Map in this case. This may be significant only if the map is
1112-- large.
1113{-# INLINE demuxWith_ #-}
1114demuxWith_ :: (Monad m, Ord k)
1115 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a ()
1116demuxWith_ f kv = Fold step initial extract
1118 where
1120 initial = do
1121 Prelude.mapM (\(Fold s i e) ->
1122 i >>= \r -> return (Fold s (return r) e)) kv
1123 step mp a
1124 -- XXX should we raise an exception in Nothing case?
1125 -- Ideally we should enforce that it is a total map over k so that look
1126 -- up never fails
1127 | (k, a') <- f a
1128 = case Map.lookup k mp of
1129 Nothing -> return mp
1130 Just (Fold step' acc _) -> do
1131 _ <- acc >>= \x -> step' x a'
1132 return mp
1133 extract mp = Prelude.mapM_ (\(Fold _ acc e) -> acc >>= e) mp
1135-- | Given a stream of key value pairs and a map from keys to folds, fold the
1136-- values for each key using the corresponding folds, discarding the outputs.
1138-- @
1139-- > let prn = FL.drainBy print
1140-- > let table = Data.Map.fromList [(\"ONE", prn), (\"TWO", prn)]
1141-- input = S.fromList [(\"ONE",1),(\"TWO",2)]
1142-- in S.fold (FL.demux_ table) input
1143-- One 1
1144-- Two 2
1145-- @
1147-- @since 0.7.0
1148{-# INLINE demux_ #-}
1149demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
1150demux_ = demuxWith_ id
1152{-# INLINE demuxDefault_ #-}
1153demuxDefault_ :: (Monad m, Ord k)
1154 => Map k (Fold m a ()) -> Fold m (k, a) () -> Fold m (k, a) ()
1155demuxDefault_ = demuxWithDefault_ id
1157-- TODO If the data is large we may need a map/hashmap in pinned memory instead
1158-- of a regular Map. That may require a serializable constraint though. We can
1159-- have another API for that.
1161-- | Split the input stream based on a key field and fold each split using the
1162-- given fold. Useful for map/reduce, bucketizing the input in different bins
1163-- or for generating histograms.
1165-- @
1166-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1167-- in S.fold (FL.classify FL.toList) input
1168-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1169-- @
1171-- @since 0.7.0
1172{-# INLINE classifyWith #-}
1173classifyWith :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1174classifyWith f (Fold step initial extract) = Fold step' initial' extract'
1176 where
1178 initial' = return Map.empty
1179 step' kv a =
1180 let k = f a
1181 in case Map.lookup k kv of
1182 Nothing -> do
1183 x <- initial
1184 r <- step x a
1185 return $ Map.insert k r kv
1186 Just x -> do
1187 r <- step x a
1188 return $ Map.insert k r kv
1189 extract' = Prelude.mapM extract
1191-- | Given an input stream of key value pairs and a fold for values, fold all
1192-- the values belonging to each key. Useful for map/reduce, bucketizing the
1193-- input in different bins or for generating histograms.
1195-- @
1196-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1197-- in S.fold (FL.classify FL.toList) input
1198-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1199-- @
1201-- @since 0.7.0
1203-- Same as:
1205-- > classify fld = classifyWith fst (lmap snd fld)
1207{-# INLINE classify #-}
1208classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
1209classify fld = classifyWith fst (lmap snd fld)
1211------------------------------------------------------------------------------
1212-- Unzipping
1213------------------------------------------------------------------------------
1215-- | Like 'unzipWith' but with a monadic splitter function.
1217-- @since 0.7.0
1218{-# INLINE unzipWithM #-}
1219unzipWithM :: Monad m
1220 => (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1221unzipWithM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1222 Fold step begin done
1224 where
1226 step (Tuple' xL xR) a = do
1227 (b,c) <- f a
1228 Tuple' <$> stepL xL b <*> stepR xR c
1229 begin = Tuple' <$> beginL <*> beginR
1230 done (Tuple' xL xR) = (,) <$> doneL xL <*> doneR xR
1232-- | Split elements in the input stream into two parts using a pure splitter
1233-- function, direct each part to a different fold and zip the results.
1235-- @since 0.7.0
1236{-# INLINE unzipWith #-}
1237unzipWith :: Monad m
1238 => (a -> (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1239unzipWith f = unzipWithM (return . f)
1241-- | Send the elements of tuples in a stream of tuples through two different
1242-- folds.
1244-- @
1246-- |-------Fold m a x--------|
1247-- ---------stream of (a,b)--| |----m (x,y)
1248-- |-------Fold m b y--------|
1250-- @
1252-- This is the consumer side dual of the producer side 'zip' operation.
1254-- @since 0.7.0
1255{-# INLINE unzip #-}
1256unzip :: Monad m => Fold m a x -> Fold m b y -> Fold m (a,b) (x,y)
1257unzip = unzipWith id
1259------------------------------------------------------------------------------
1260-- Nesting
1261------------------------------------------------------------------------------
1264-- All the stream flattening transformations can also be applied to a fold
1265-- input stream.
1267-- | This can be used to apply all the stream generation operations on folds.
1268lconcatMap ::(IsStream t, Monad m) => (a -> t m b)
1269 -> Fold m b c
1270 -> Fold m a c
1271lconcatMap s f1 f2 = undefined
1274-- All the grouping transformation that we apply to a stream can also be
1275-- applied to a fold input stream.
1278-- | Group the input stream into groups of elements between @low@ and @high@.
1279-- Collection starts in chunks of @low@ and then keeps doubling until we reach
1280-- @high@. Each chunk is folded using the provided fold function.
1282-- This could be useful, for example, when we are folding a stream of unknown
1283-- size to a stream of arrays and we want to minimize the number of
1284-- allocations.
1286-- @
1288-- XXX we should be able to implement it with parsers/terminating folds.
1290{-# INLINE lchunksInRange #-}
1291lchunksInRange :: Monad m
1292 => Int -> Int -> Fold m a b -> Fold m b c -> Fold m a c
1293lchunksInRange low high (Fold step1 initial1 extract1)
1294 (Fold step2 initial2 extract2) = undefined
1297------------------------------------------------------------------------------
1298-- Fold to a Parallel SVar
1299------------------------------------------------------------------------------
1301{-# INLINE toParallelSVar #-}
1302toParallelSVar :: MonadIO m => SVar t m a -> Maybe WorkerInfo -> Fold m a ()
1303toParallelSVar svar winfo = Fold step initial extract
1304 where
1306 initial = return ()
1308 step () x = liftIO $ do
1309 -- XXX we can have a separate fold for unlimited buffer case to avoid a
1310 -- branch in the step here.
1311 decrementBufferLimit svar
1312 void $ send svar (ChildYield x)
1314 extract () = liftIO $ do
1315 sendStop svar winfo
1317{-# INLINE toParallelSVarLimited #-}
1318toParallelSVarLimited :: MonadIO m
1319 => SVar t m a -> Maybe WorkerInfo -> Fold m a ()
1320toParallelSVarLimited svar winfo = Fold step initial extract
1321 where
1323 initial = return True
1325 step True x = liftIO $ do
1326 yieldLimitOk <- decrementYieldLimit svar
1327 if yieldLimitOk
1328 then do
1329 decrementBufferLimit svar
1330 void $ send svar (ChildYield x)
1331 return True
1332 else do
1333 cleanupSVarFromWorker svar
1334 sendStop svar winfo
1335 return False
1336 step False _ = return False
1338 extract True = liftIO $ sendStop svar winfo
1339 extract False = return ()