on cc8cd01 help sign in
1621 lines 48 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 , take
133 , ltake
134 -- , lrunFor -- time
135 , ltakeWhile
136 {-
137 , ltakeWhileM
138 , ldrop
139 , ldropWhile
140 , ldropWhileM
141 -}
143 , lsessionsOf
144 , lchunksOf
146 -- ** Breaking
148 -- Binary
149 , splitAt -- spanN
150 -- , splitIn -- sessionN
152 -- By elements
153 , span -- spanWhile
154 , break -- breakBefore
155 -- , breakAfter
156 -- , breakOn
157 -- , breakAround
158 , spanBy
159 , spanByRolling
161 -- By sequences
162 -- , breakOnSeq
163 -- , breakOnStream -- on a stream
165 -- * Distributing
167 , tee
168 , distribute
169 , distribute_
171 -- * Partitioning
173 -- , partitionByM
174 -- , partitionBy
175 , partition
177 -- * Demultiplexing
179 , demux
180 -- , demuxWith
181 , demux_
182 , demuxDefault_
183 -- , demuxWith_
184 , demuxWithDefault_
186 -- * Classifying
188 , classify
189 -- , classifyWith
191 -- * Unzipping
192 , unzip
193 -- These can be expressed using lmap/lmapM and unzip
194 -- , unzipWith
195 -- , unzipWithM
197 -- * Nested Folds
198 -- , concatMap
199 , foldChunks
200 , duplicate
202 -- * Running Folds
203 , initialize
204 , runStep
206 -- * Folding to SVar
207 , toParallelSVar
208 , toParallelSVarLimited
209 )
210where
212import Control.Monad (void)
213import Control.Monad.IO.Class (MonadIO(..))
214import Data.Functor.Identity (Identity(..))
215import Data.Int (Int64)
216import Data.Map.Strict (Map)
218import Prelude
219 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
220 foldl, map, mapM_, sequence, all, any, sum, product, elem,
221 notElem, maximum, minimum, head, last, tail, length, null,
222 reverse, iterate, init, and, or, lookup, foldr1, (!!),
223 scanl, scanl1, replicate, concatMap, mconcat, foldMap, unzip,
224 span, splitAt, break, mapM)
226import qualified Data.Map.Strict as Map
227import qualified Prelude
229import Streamly.Internal.Data.Pipe.Types (Pipe (..), PipeState(..))
230import Streamly.Internal.Data.Fold.Types
231import Streamly.Internal.Data.Parse.Types
232import Streamly.Internal.Data.Strict
233import Streamly.Internal.Data.SVar
235import qualified Streamly.Internal.Data.Pipe.Types as Pipe
237------------------------------------------------------------------------------
238-- Smart constructors
239------------------------------------------------------------------------------
241-- | Make a fold using a pure step function, a pure initial state and
242-- a pure state extraction function.
243--
244-- /Internal/
245--
246{-# INLINE mkPure #-}
247mkPure :: Monad m => (s -> a -> s) -> s -> (s -> b) -> Fold m a b
248mkPure step initial extract =
249 Fold (\s a -> return $ step s a) (return initial) (return . extract)
251-- | Make a fold using a pure step function and a pure initial state. The
252-- final state extracted is identical to the intermediate state.
253--
254-- /Internal/
255--
256{-# INLINE mkPureId #-}
257mkPureId :: Monad m => (b -> a -> b) -> b -> Fold m a b
258mkPureId step initial = mkPure step initial id
260-- | Make a fold with an effectful step function and initial state, and a state
261-- extraction function.
262--
263-- > mkFold = Fold
264--
265-- We can just use 'Fold' but it is provided for completeness.
266--
267-- /Internal/
268--
269{-# INLINE mkFold #-}
270mkFold :: (s -> a -> m s) -> m s -> (s -> m b) -> Fold m a b
271mkFold = Fold
273-- | Make a fold with an effectful step function and initial state. The final
274-- state extracted is identical to the intermediate state.
275--
276-- /Internal/
277--
278{-# INLINE mkFoldId #-}
279mkFoldId :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
280mkFoldId step initial = Fold step initial return
282------------------------------------------------------------------------------
283-- hoist
284------------------------------------------------------------------------------
286-- | Change the underlying monad of a fold
287--
288-- /Internal/
289hoist :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
290hoist f (Fold step initial extract) =
291 Fold (\x a -> f $ step x a) (f initial) (f . extract)
293-- | Adapt a pure fold to any monad
294--
295-- > generally = hoist (return . runIdentity)
296--
297-- /Internal/
298generally :: Monad m => Fold Identity a b -> Fold m a b
299generally = hoist (return . runIdentity)
301------------------------------------------------------------------------------
302-- Transformations on fold inputs
303------------------------------------------------------------------------------
305-- | Flatten the monadic output of a fold to pure output.
306--
307-- @since 0.7.0
308{-# INLINE sequence #-}
309sequence :: Monad m => Fold m a (m b) -> Fold m a b
310sequence (Fold step initial extract) = Fold step initial extract'
311 where
312 extract' x = do
313 act <- extract x
314 act >>= return
316-- | Map a monadic function on the output of a fold.
317--
318-- @since 0.7.0
319{-# INLINE mapM #-}
320mapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
321mapM f = sequence . fmap f
323------------------------------------------------------------------------------
324-- Transformations on fold inputs
325------------------------------------------------------------------------------
327-- rename to lpipe?
328--
329-- | Apply a transformation on a 'Fold' using a 'Pipe'.
330--
331-- @since 0.7.0
332{-# INLINE transform #-}
333transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
334transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
335 Fold step initial extract
337 where
339 initial = Tuple' <$> return pinitial <*> finitial
340 step (Tuple' ps fs) x = do
341 r <- pstep1 ps x
342 go fs r
344 where
345 -- XXX use SPEC?
346 go acc (Pipe.Yield b (Consume ps')) = do
347 acc' <- fstep acc b
348 return (Tuple' ps' acc')
350 go acc (Pipe.Yield b (Produce ps')) = do
351 acc' <- fstep acc b
352 r <- pstep2 ps'
353 go acc' r
355 go acc (Pipe.Continue (Consume ps')) = return (Tuple' ps' acc)
357 go acc (Pipe.Continue (Produce ps')) = do
358 r <- pstep2 ps'
359 go acc r
361 extract (Tuple' _ fs) = fextract fs
363------------------------------------------------------------------------------
364-- Utilities
365------------------------------------------------------------------------------
367-- | @_Fold1 step@ returns a new 'Fold' using just a step function that has the
368-- same type for the accumulator and the element. The result type is the
369-- accumulator type wrapped in 'Maybe'. The initial accumulator is retrieved
370-- from the 'Foldable', the result is 'None' for empty containers.
371{-# INLINABLE _Fold1 #-}
372_Fold1 :: Monad m => (a -> a -> a) -> Fold m a (Maybe a)
373_Fold1 step = Fold step_ (return Nothing') (return . toMaybe)
374 where
375 step_ mx a = return $ Just' $
376 case mx of
377 Nothing' -> a
378 Just' x -> step x a
380------------------------------------------------------------------------------
381-- Left folds
382------------------------------------------------------------------------------
384------------------------------------------------------------------------------
385-- Run Effects
386------------------------------------------------------------------------------
388-- | A fold that drains all its input, running the effects and discarding the
389-- results.
390--
391-- @since 0.7.0
392{-# INLINABLE drain #-}
393drain :: Monad m => Fold m a ()
394drain = Fold step begin done
395 where
396 begin = return ()
397 step _ _ = return ()
398 done = return
400-- |
401-- > drainBy f = lmapM f drain
402--
403-- Drain all input after passing it through a monadic function. This is the
404-- dual of mapM_ on stream producers.
405--
406-- @since 0.7.0
407{-# INLINABLE drainBy #-}
408drainBy :: Monad m => (a -> m b) -> Fold m a ()
409drainBy f = Fold (const (void . f)) (return ()) return
411{-# INLINABLE drainBy2 #-}
412drainBy2 :: Monad m => (a -> m b) -> Fold2 m c a ()
413drainBy2 f = Fold2 (const (void . f)) (\_ -> return ()) return
415-- | Extract the last element of the input stream, if any.
416--
417-- @since 0.7.0
418{-# INLINABLE last #-}
419last :: Monad m => Fold m a (Maybe a)
420last = _Fold1 (flip const)
422------------------------------------------------------------------------------
423-- To Summary
424------------------------------------------------------------------------------
426-- | Like 'length', except with a more general 'Num' return value
427--
428-- @since 0.7.0
429{-# INLINABLE genericLength #-}
430genericLength :: (Monad m, Num b) => Fold m a b
431genericLength = Fold (\n _ -> return $ n + 1) (return 0) return
433-- | Determine the length of the input stream.
434--
435-- @since 0.7.0
436{-# INLINABLE length #-}
437length :: Monad m => Fold m a Int
438length = genericLength
440-- | Determine the sum of all elements of a stream of numbers. Returns additive
441-- identity (@0@) when the stream is empty. Note that this is not numerically
442-- stable for floating point numbers.
443--
444-- @since 0.7.0
445{-# INLINABLE sum #-}
446sum :: (Monad m, Num a) => Fold m a a
447sum = Fold (\x a -> return $ x + a) (return 0) return
449-- | Determine the product of all elements of a stream of numbers. Returns
450-- multiplicative identity (@1@) when the stream is empty.
451--
452-- @since 0.7.0
453{-# INLINABLE product #-}
454product :: (Monad m, Num a) => Fold m a a
455product = Fold (\x a -> return $ x * a) (return 1) return
457------------------------------------------------------------------------------
458-- To Summary (Maybe)
459------------------------------------------------------------------------------
461-- | Determine the maximum element in a stream using the supplied comparison
462-- function.
463--
464-- @since 0.7.0
465{-# INLINABLE maximumBy #-}
466maximumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
467maximumBy cmp = _Fold1 max'
468 where
469 max' x y = case cmp x y of
470 GT -> x
471 _ -> y
473-- |
474-- @
475-- maximum = 'maximumBy' compare
476-- @
477--
478-- Determine the maximum element in a stream.
479--
480-- @since 0.7.0
481{-# INLINABLE maximum #-}
482maximum :: (Monad m, Ord a) => Fold m a (Maybe a)
483maximum = _Fold1 max
485-- | Computes the minimum element with respect to the given comparison function
486--
487-- @since 0.7.0
488{-# INLINABLE minimumBy #-}
489minimumBy :: Monad m => (a -> a -> Ordering) -> Fold m a (Maybe a)
490minimumBy cmp = _Fold1 min'
491 where
492 min' x y = case cmp x y of
493 GT -> y
494 _ -> x
496-- | Determine the minimum element in a stream using the supplied comparison
497-- function.
498--
499-- @since 0.7.0
500{-# INLINABLE minimum #-}
501minimum :: (Monad m, Ord a) => Fold m a (Maybe a)
502minimum = _Fold1 min
504------------------------------------------------------------------------------
505-- To Summary (Statistical)
506------------------------------------------------------------------------------
508-- | Compute a numerically stable arithmetic mean of all elements in the input
509-- stream.
510--
511-- @since 0.7.0
512{-# INLINABLE mean #-}
513mean :: (Monad m, Fractional a) => Fold m a a
514mean = Fold step (return begin) (return . done)
515 where
516 begin = Tuple' 0 0
517 step (Tuple' x n) y = return $
518 let n' = n + 1
519 in Tuple' (x + (y - x) / n') n'
520 done (Tuple' x _) = x
522-- | Compute a numerically stable (population) variance over all elements in
523-- the input stream.
524--
525-- @since 0.7.0
526{-# INLINABLE variance #-}
527variance :: (Monad m, Fractional a) => Fold m a a
528variance = Fold step (return begin) (return . done)
529 where
530 begin = Tuple3' 0 0 0
532 step (Tuple3' n mean_ m2) x = return $ Tuple3' n' mean' m2'
533 where
534 n' = n + 1
535 mean' = (n * mean_ + x) / (n + 1)
536 delta = x - mean_
537 m2' = m2 + delta * delta * n / (n + 1)
539 done (Tuple3' n _ m2) = m2 / n
541-- | Compute a numerically stable (population) standard deviation over all
542-- elements in the input stream.
543--
544-- @since 0.7.0
545{-# INLINABLE stdDev #-}
546stdDev :: (Monad m, Floating a) => Fold m a a
547stdDev = sqrt variance
549-- | Compute an 'Int' sized polynomial rolling hash
550--
551-- > H = salt * k ^ n + c1 * k ^ (n - 1) + c2 * k ^ (n - 2) + ... + cn * k ^ 0
552--
553-- Where @c1@, @c2@, @cn@ are the elements in the input stream and @k@ is a
554-- constant.
555--
556-- This hash is often used in Rabin-Karp string search algorithm.
557--
558-- See https://en.wikipedia.org/wiki/Rolling_hash
559--
560-- @since 0.7.0
561{-# INLINABLE rollingHashWithSalt #-}
562rollingHashWithSalt :: (Monad m, Enum a) => Int64 -> Fold m a Int64
563rollingHashWithSalt salt = Fold step initial extract
564 where
565 k = 2891336453 :: Int64
566 initial = return salt
567 step cksum a = return $ cksum * k + fromIntegral (fromEnum a)
568 extract = return
570-- | A default salt used in the implementation of 'rollingHash'.
571{-# INLINE defaultSalt #-}
572defaultSalt :: Int64
573defaultSalt = -2578643520546668380
575-- | Compute an 'Int' sized polynomial rolling hash of a stream.
576--
577-- > rollingHash = rollingHashWithSalt defaultSalt
578--
579-- @since 0.7.0
580{-# INLINABLE rollingHash #-}
581rollingHash :: (Monad m, Enum a) => Fold m a Int64
582rollingHash = rollingHashWithSalt defaultSalt
584-- | Compute an 'Int' sized polynomial rolling hash of the first n elements of
585-- a stream.
586--
587-- > rollingHashFirstN = ltake n rollingHash
588{-# INLINABLE rollingHashFirstN #-}
589rollingHashFirstN :: (Monad m, Enum a) => Int -> Fold m a Int64
590rollingHashFirstN n = ltake n rollingHash
592------------------------------------------------------------------------------
593-- Monoidal left folds
594------------------------------------------------------------------------------
596-- | Fold an input stream consisting of monoidal elements using 'mappend'
597-- and 'mempty'.
598--
599-- > S.fold FL.mconcat (S.map Sum $ S.enumerateFromTo 1 10)
600--
601-- @since 0.7.0
602{-# INLINABLE mconcat #-}
603mconcat :: (Monad m, Monoid a) => Fold m a a
604mconcat = Fold (\x a -> return $ mappend x a) (return mempty) return
606-- |
607-- > foldMap f = map f mconcat
608--
609-- Make a fold from a pure function that folds the output of the function
610-- using 'mappend' and 'mempty'.
611--
612-- > S.fold (FL.foldMap Sum) $ S.enumerateFromTo 1 10
613--
614-- @since 0.7.0
615{-# INLINABLE foldMap #-}
616foldMap :: (Monad m, Monoid b) => (a -> b) -> Fold m a b
617foldMap f = lmap f mconcat
619-- |
620-- > foldMapM f = mapM f mconcat
621--
622-- Make a fold from a monadic function that folds the output of the function
623-- using 'mappend' and 'mempty'.
624--
625-- > S.fold (FL.foldMapM (return . Sum)) $ S.enumerateFromTo 1 10
626--
627-- @since 0.7.0
628{-# INLINABLE foldMapM #-}
629foldMapM :: (Monad m, Monoid b) => (a -> m b) -> Fold m a b
630foldMapM act = Fold step begin done
631 where
632 done = return
633 begin = return mempty
634 step m a = do
635 m' <- act a
636 return $! mappend m m'
638------------------------------------------------------------------------------
639-- To Containers
640------------------------------------------------------------------------------
642-- | Folds the input stream to a list.
643--
644-- /Warning!/ working on large lists accumulated as buffers in memory could be
645-- very inefficient, consider using "Streamly.Memory.Array" instead.
646--
647-- @since 0.7.0
649-- id . (x1 :) . (x2 :) . (x3 :) . ... . (xn :) $ []
650{-# INLINABLE toList #-}
651toList :: Monad m => Fold m a [a]
652toList = Fold (\f x -> return $ f . (x :))
653 (return id)
654 (return . ($ []))
656------------------------------------------------------------------------------
657-- Partial Folds
658------------------------------------------------------------------------------
660-- | A fold that drains the first n elements of its input, running the effects
661-- and discarding the results.
662{-# INLINABLE drainN #-}
663drainN :: Monad m => Int -> Fold m a ()
664drainN n = ltake n drain
666-- | A fold that drains elements of its input as long as the predicate succeeds,
667-- running the effects and discarding the results.
668{-# INLINABLE drainWhile #-}
669drainWhile :: Monad m => (a -> Bool) -> Fold m a ()
670drainWhile p = ltakeWhile p drain
672------------------------------------------------------------------------------
673-- To Elements
674------------------------------------------------------------------------------
676-- | Like 'index', except with a more general 'Integral' argument
677--
678-- @since 0.7.0
679{-# INLINABLE genericIndex #-}
680genericIndex :: (Integral i, Monad m) => i -> Fold m a (Maybe a)
681genericIndex i = Fold step (return $ Left' 0) done
682 where
683 step x a = return $
684 case x of
685 Left' j -> if i == j
686 then Right' a
687 else Left' (j + 1)
688 _ -> x
689 done x = return $
690 case x of
691 Left' _ -> Nothing
692 Right' a -> Just a
694-- | Lookup the element at the given index.
695--
696-- @since 0.7.0
697{-# INLINABLE index #-}
698index :: Monad m => Int -> Fold m a (Maybe a)
699index = genericIndex
701-- | Extract the first element of the stream, if any.
702--
703-- @since 0.7.0
704{-# INLINABLE head #-}
705head :: Monad m => Fold m a (Maybe a)
706head = _Fold1 const
708-- | Returns the first element that satisfies the given predicate.
709--
710-- @since 0.7.0
711{-# INLINABLE find #-}
712find :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
713find predicate = Fold step (return Nothing') (return . toMaybe)
714 where
715 step x a = return $
716 case x of
717 Nothing' -> if predicate a
718 then Just' a
719 else Nothing'
720 _ -> x
722-- | In a stream of (key-value) pairs @(a, b)@, return the value @b@ of the
723-- first pair where the key equals the given value @a@.
724--
725-- @since 0.7.0
726{-# INLINABLE lookup #-}
727lookup :: (Eq a, Monad m) => a -> Fold m (a,b) (Maybe b)
728lookup a0 = Fold step (return Nothing') (return . toMaybe)
729 where
730 step x (a,b) = return $
731 case x of
732 Nothing' -> if a == a0
733 then Just' b
734 else Nothing'
735 _ -> x
737-- | Convert strict 'Either'' to lazy 'Maybe'
738{-# INLINABLE hush #-}
739hush :: Either' a b -> Maybe b
740hush (Left' _) = Nothing
741hush (Right' b) = Just b
743-- | Returns the first index that satisfies the given predicate.
744--
745-- @since 0.7.0
746{-# INLINABLE findIndex #-}
747findIndex :: Monad m => (a -> Bool) -> Fold m a (Maybe Int)
748findIndex predicate = Fold step (return $ Left' 0) (return . hush)
749 where
750 step x a = return $
751 case x of
752 Left' i ->
753 if predicate a
754 then Right' i
755 else Left' (i + 1)
756 _ -> x
758-- | Returns the first index where a given value is found in the stream.
759--
760-- @since 0.7.0
761{-# INLINABLE elemIndex #-}
762elemIndex :: (Eq a, Monad m) => a -> Fold m a (Maybe Int)
763elemIndex a = findIndex (a ==)
765------------------------------------------------------------------------------
766-- To Boolean
767------------------------------------------------------------------------------
769-- | Return 'True' if the input stream is empty.
770--
771-- @since 0.7.0
772{-# INLINABLE null #-}
773null :: Monad m => Fold m a Bool
774null = Fold (\_ _ -> return False) (return True) return
776-- |
777-- > any p = lmap p or
778--
779-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
780--
781-- @since 0.7.0
782{-# INLINABLE any #-}
783any :: Monad m => (a -> Bool) -> Fold m a Bool
784any predicate = Fold (\x a -> return $ x || predicate a) (return False) return
786-- | Return 'True' if the given element is present in the stream.
787--
788-- @since 0.7.0
789{-# INLINABLE elem #-}
790elem :: (Eq a, Monad m) => a -> Fold m a Bool
791elem a = any (a ==)
793-- |
794-- > all p = lmap p and
795--
796-- | Returns 'True' if all elements of a stream satisfy a predicate.
797--
798-- @since 0.7.0
799{-# INLINABLE all #-}
800all :: Monad m => (a -> Bool) -> Fold m a Bool
801all predicate = Fold (\x a -> return $ x && predicate a) (return True) return
803-- | Returns 'True' if the given element is not present in the stream.
804--
805-- @since 0.7.0
806{-# INLINABLE notElem #-}
807notElem :: (Eq a, Monad m) => a -> Fold m a Bool
808notElem a = all (a /=)
810-- | Returns 'True' if all elements are 'True', 'False' otherwise
811--
812-- @since 0.7.0
813{-# INLINABLE and #-}
814and :: Monad m => Fold m Bool Bool
815and = Fold (\x a -> return $ x && a) (return True) return
817-- | Returns 'True' if any element is 'True', 'False' otherwise
818--
819-- @since 0.7.0
820{-# INLINABLE or #-}
821or :: Monad m => Fold m Bool Bool
822or = Fold (\x a -> return $ x || a) (return False) return
824------------------------------------------------------------------------------
825-- Grouping/Splitting
826------------------------------------------------------------------------------
828------------------------------------------------------------------------------
829-- Grouping without looking at elements
830------------------------------------------------------------------------------
831--
832-- XXX Once we have terminating folds, this Parse should get replaced by Fold.
833-- Alternatively, we can name it "chunkOf" and the corresponding time domain
834-- combinator as "intervalOf" or even "chunk" and "interval".
835--
836-- | Take at most @n@ input elements and fold them using the supplied fold.
837--
838-- Stops after @n@ elements.
839-- Never fails.
840--
841-- /Internal/
842--
843{-# INLINE take #-}
844take :: Monad m => Int -> Fold m a b -> Parse m a b
845take n (Fold fstep finitial fextract) = Parse step initial extract
847 where
849 initial = (Tuple' 0) <$> finitial
851 step (Tuple' i r) a = do
852 res <- fstep r a
853 let i1 = i + 1
854 s1 = Tuple' i1 res
855 if i1 < n
856 then return $ Keep 0 s1
857 else return $ Halt 0 s1
859 extract (Tuple' _ r) = fmap Right (fextract r)
861------------------------------------------------------------------------------
862-- Binary APIs
863------------------------------------------------------------------------------
864--
865-- XXX These would just be applicative compositions of terminating folds.
867-- | @splitAt n f1 f2@ composes folds @f1@ and @f2@ such that first @n@
868-- elements of its input are consumed by fold @f1@ and the rest of the stream
869-- is consumed by fold @f2@.
870--
871-- > let splitAt_ n xs = S.fold (FL.splitAt n FL.toList FL.toList) $ S.fromList xs
872--
873-- >>> splitAt_ 6 "Hello World!"
874-- > ("Hello ","World!")
875--
876-- >>> splitAt_ (-1) [1,2,3]
877-- > ([],[1,2,3])
878--
879-- >>> splitAt_ 0 [1,2,3]
880-- > ([],[1,2,3])
881--
882-- >>> splitAt_ 1 [1,2,3]
883-- > ([1],[2,3])
884--
885-- >>> splitAt_ 3 [1,2,3]
886-- > ([1,2,3],[])
887--
888-- >>> splitAt_ 4 [1,2,3]
889-- > ([1,2,3],[])
890--
891-- /Internal/
893-- This can be considered as a two-fold version of 'ltake' where we take both
894-- the segments instead of discarding the leftover.
895--
896{-# INLINE splitAt #-}
897splitAt
898 :: Monad m
899 => Int
900 -> Fold m a b
901 -> Fold m a c
902 -> Fold m a (b, c)
903splitAt n (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
904 Fold step initial extract
905 where
906 initial = Tuple3' <$> return n <*> initialL <*> initialR
908 step (Tuple3' i xL xR) input =
909 if i > 0
910 then stepL xL input >>= (\a -> return (Tuple3' (i - 1) a xR))
911 else stepR xR input >>= (\b -> return (Tuple3' i xL b))
913 extract (Tuple3' _ a b) = (,) <$> extractL a <*> extractR b
915------------------------------------------------------------------------------
916-- Element Aware APIs
917------------------------------------------------------------------------------
918--
919------------------------------------------------------------------------------
920-- Binary APIs
921------------------------------------------------------------------------------
923-- | Break the input stream into two groups, the first group takes the input as
924-- long as the predicate applied to the first element of the stream and next
925-- input element holds 'True', the second group takes the rest of the input.
926--
927-- /Internal/
928--
929spanBy
930 :: Monad m
931 => (a -> a -> Bool)
932 -> Fold m a b
933 -> Fold m a c
934 -> Fold m a (b, c)
935spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
936 Fold step initial extract
938 where
939 initial = Tuple3' <$> initialL <*> initialR <*> return (Tuple' Nothing True)
941 step (Tuple3' a b (Tuple' (Just frst) isFirstG)) input =
942 if cmp frst input && isFirstG
943 then stepL a input
944 >>= (\a' -> return (Tuple3' a' b (Tuple' (Just frst) isFirstG)))
945 else stepR b input
946 >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
948 step (Tuple3' a b (Tuple' Nothing isFirstG)) input =
949 if isFirstG
950 then stepL a input
951 >>= (\a' -> return (Tuple3' a' b (Tuple' (Just input) isFirstG)))
952 else stepR b input
953 >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
955 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
957-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
958-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
959-- input.
960--
961-- > let span_ p xs = S.fold (S.span p FL.toList FL.toList) $ S.fromList xs
962--
963-- >>> span_ (< 1) [1,2,3]
964-- > ([],[1,2,3])
965--
966-- >>> span_ (< 2) [1,2,3]
967-- > ([1],[2,3])
968--
969-- >>> span_ (< 4) [1,2,3]
970-- > ([1,2,3],[])
971--
972-- /Internal/
974-- This can be considered as a two-fold version of 'ltakeWhile' where we take
975-- both the segments instead of discarding the leftover.
976{-# INLINE span #-}
977span
978 :: Monad m
979 => (a -> Bool)
980 -> Fold m a b
981 -> Fold m a c
982 -> Fold m a (b, c)
983span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
984 Fold step initial extract
986 where
988 initial = Tuple3' <$> initialL <*> initialR <*> return True
990 step (Tuple3' a b isFirstG) input =
991 if isFirstG && p input
992 then stepL a input >>= (\a' -> return (Tuple3' a' b True))
993 else stepR b input >>= (\a' -> return (Tuple3' a a' False))
995 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
997-- |
998-- > break p = span (not . p)
999--
1000-- Break as soon as the predicate becomes 'True'. @break p f1 f2@ composes
1001-- folds @f1@ and @f2@ such that @f1@ stops consuming input as soon as the
1002-- predicate @p@ becomes 'True'. The rest of the input is consumed @f2@.
1004-- This is the binary version of 'splitBy'.
1006-- > let break_ p xs = S.fold (S.break p FL.toList FL.toList) $ S.fromList xs
1008-- >>> break_ (< 1) [3,2,1]
1009-- > ([3,2,1],[])
1011-- >>> break_ (< 2) [3,2,1]
1012-- > ([3,2],[1])
1014-- >>> break_ (< 4) [3,2,1]
1015-- > ([],[3,2,1])
1017-- /Internal/
1018{-# INLINE break #-}
1019break
1020 :: Monad m
1021 => (a -> Bool)
1022 -> Fold m a b
1023 -> Fold m a c
1024 -> Fold m a (b, c)
1025break p = span (not . p)
1027-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1028-- predicate is applied to the previous and the next input elements.
1030-- /Internal/
1031{-# INLINE spanByRolling #-}
1032spanByRolling
1033 :: Monad m
1034 => (a -> a -> Bool)
1035 -> Fold m a b
1036 -> Fold m a c
1037 -> Fold m a (b, c)
1038spanByRolling cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1039 Fold step initial extract
1041 where
1042 initial = Tuple3' <$> initialL <*> initialR <*> return Nothing
1044 step (Tuple3' a b (Just frst)) input =
1045 if cmp input frst
1046 then stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1047 else stepR b input >>= (\b' -> return (Tuple3' a b' (Just input)))
1049 step (Tuple3' a b Nothing) input =
1050 stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1052 extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1054------------------------------------------------------------------------------
1055-- Binary splitting on a separator
1056------------------------------------------------------------------------------
1059-- | Find the first occurrence of the specified sequence in the input stream
1060-- and break the input stream into two parts, the first part consisting of the
1061-- stream before the sequence and the second part consisting of the sequence
1062-- and the rest of the stream.
1064-- > let breakOn_ pat xs = S.fold (S.breakOn pat FL.toList FL.toList) $ S.fromList xs
1066-- >>> breakOn_ "dear" "Hello dear world!"
1067-- > ("Hello ","dear world!")
1069{-# INLINE breakOn #-}
1070breakOn :: Monad m => Array a -> Fold m a b -> Fold m a c -> Fold m a (b,c)
1071breakOn pat f m = undefined
1074------------------------------------------------------------------------------
1075-- Distributing
1076------------------------------------------------------------------------------
1078-- | Distribute one copy of the stream to each fold and zip the results.
1080-- @
1081-- |-------Fold m a b--------|
1082-- ---stream m a---| |---m (b,c)
1083-- |-------Fold m a c--------|
1084-- @
1085-- >>> S.fold (FL.tee FL.sum FL.length) (S.enumerateFromTo 1.0 100.0)
1086-- (5050.0,100)
1088-- @since 0.7.0
1089{-# INLINE tee #-}
1090tee :: Monad m => Fold m a b -> Fold m a c -> Fold m a (b,c)
1091tee f1 f2 = (,) <$> f1 <*> f2
1093{-# INLINE foldNil #-}
1094foldNil :: Monad m => Fold m a [b]
1095foldNil = Fold step begin done where
1096 begin = return []
1097 step _ _ = return []
1098 done = return
1100{-# INLINE foldCons #-}
1101foldCons :: Monad m => Fold m a b -> Fold m a [b] -> Fold m a [b]
1102foldCons (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1103 Fold step begin done
1105 where
1107 begin = Tuple' <$> beginL <*> beginR
1108 step (Tuple' xL xR) a = Tuple' <$> stepL xL a <*> stepR xR a
1109 done (Tuple' xL xR) = (:) <$> (doneL xL) <*> (doneR xR)
1111-- XXX use "List" instead of "[]"?, use Array for output to scale it to a large
1112-- number of consumers? For polymorphic case a vector could be helpful. For
1113-- Storables we can use arrays. Will need separate APIs for those.
1115-- | Distribute one copy of the stream to each fold and collect the results in
1116-- a container.
1118-- @
1120-- |-------Fold m a b--------|
1121-- ---stream m a---| |---m [b]
1122-- |-------Fold m a b--------|
1123-- | |
1124-- ...
1125-- @
1127-- >>> S.fold (FL.distribute [FL.sum, FL.length]) (S.enumerateFromTo 1 5)
1128-- [15,5]
1130-- This is the consumer side dual of the producer side 'sequence' operation.
1132-- @since 0.7.0
1133{-# INLINE distribute #-}
1134distribute :: Monad m => [Fold m a b] -> Fold m a [b]
1135distribute [] = foldNil
1136distribute (x:xs) = foldCons x (distribute xs)
1138-- | Like 'distribute' but for folds that return (), this can be more efficient
1139-- than 'distribute' as it does not need to maintain state.
1141{-# INLINE distribute_ #-}
1142distribute_ :: Monad m => [Fold m a ()] -> Fold m a ()
1143distribute_ fs = Fold step initial extract
1144 where
1145 initial = Prelude.mapM (\(Fold s i e) ->
1146 i >>= \r -> return (Fold s (return r) e)) fs
1147 step ss a = do
1148 Prelude.mapM_ (\(Fold s i _) -> i >>= \r -> s r a >> return ()) ss
1149 return ss
1150 extract ss = do
1151 Prelude.mapM_ (\(Fold _ i e) -> i >>= \r -> e r) ss
1152 return ()
1154------------------------------------------------------------------------------
1155-- Partitioning
1156------------------------------------------------------------------------------
1158-- | Partition the input over two folds using an 'Either' partitioning
1159-- predicate.
1161-- @
1163-- |-------Fold b x--------|
1164-- -----stream m a --> (Either b c)----| |----(x,y)
1165-- |-------Fold c y--------|
1166-- @
1168-- Send input to either fold randomly:
1170-- >>> import System.Random (randomIO)
1171-- >>> randomly a = randomIO >>= \x -> return $ if x then Left a else Right a
1172-- >>> S.fold (FL.partitionByM randomly FL.length FL.length) (S.enumerateFromTo 1 100)
1173-- (59,41)
1175-- Send input to the two folds in a proportion of 2:1:
1177-- @
1178-- import Data.IORef (newIORef, readIORef, writeIORef)
1179-- proportionately m n = do
1180-- ref <- newIORef $ cycle $ concat [replicate m Left, replicate n Right]
1181-- return $ \\a -> do
1182-- r <- readIORef ref
1183-- writeIORef ref $ tail r
1184-- return $ head r a
1186-- main = do
1187-- f <- proportionately 2 1
1188-- r <- S.fold (FL.partitionByM f FL.length FL.length) (S.enumerateFromTo (1 :: Int) 100)
1189-- print r
1190-- @
1191-- @
1192-- (67,33)
1193-- @
1195-- This is the consumer side dual of the producer side 'mergeBy' operation.
1197-- @since 0.7.0
1198{-# INLINE partitionByM #-}
1199partitionByM :: Monad m
1200 => (a -> m (Either b c)) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1201partitionByM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1203 Fold step begin done
1205 where
1207 begin = Tuple' <$> beginL <*> beginR
1208 step (Tuple' xL xR) a = do
1209 r <- f a
1210 case r of
1211 Left b -> Tuple' <$> stepL xL b <*> return xR
1212 Right c -> Tuple' <$> return xL <*> stepR xR c
1213 done (Tuple' xL xR) = (,) <$> doneL xL <*> doneR xR
1215-- Note: we could use (a -> Bool) instead of (a -> Either b c), but the latter
1216-- makes the signature clearer as to which case belongs to which fold.
1217-- XXX need to check the performance in both cases.
1219-- | Same as 'partitionByM' but with a pure partition function.
1221-- Count even and odd numbers in a stream:
1223-- @
1224-- >>> let f = FL.partitionBy (\\n -> if even n then Left n else Right n)
1225-- (fmap (("Even " ++) . show) FL.length)
1226-- (fmap (("Odd " ++) . show) FL.length)
1227-- in S.fold f (S.enumerateFromTo 1 100)
1228-- ("Even 50","Odd 50")
1229-- @
1231-- @since 0.7.0
1232{-# INLINE partitionBy #-}
1233partitionBy :: Monad m
1234 => (a -> Either b c) -> Fold m b x -> Fold m c y -> Fold m a (x, y)
1235partitionBy f = partitionByM (return . f)
1237-- | Compose two folds such that the combined fold accepts a stream of 'Either'
1238-- and routes the 'Left' values to the first fold and 'Right' values to the
1239-- second fold.
1241-- > partition = partitionBy id
1243-- @since 0.7.0
1244{-# INLINE partition #-}
1245partition :: Monad m
1246 => Fold m b x -> Fold m c y -> Fold m (Either b c) (x, y)
1247partition = partitionBy id
1250-- | Send one item to each fold in a round-robin fashion. This is the consumer
1251-- side dual of producer side 'mergeN' operation.
1253-- partitionN :: Monad m => [Fold m a b] -> Fold m a [b]
1254-- partitionN fs = Fold step begin done
1257-- TODO Demultiplex an input element into a number of typed variants. We want
1258-- to statically restrict the target values within a set of predefined types,
1259-- an enumeration of a GADT. We also want to make sure that the Map contains
1260-- only those types and the full set of those types.
1262-- TODO Instead of the input Map it should probably be a lookup-table using an
1263-- array and not in GC memory. The same applies to the output Map as well.
1264-- However, that would only be helpful if we have a very large data structure,
1265-- need to measure and see how it scales.
1267-- This is the consumer side dual of the producer side 'mux' operation (XXX to
1268-- be implemented).
1270-- | Split the input stream based on a key field and fold each split using a
1271-- specific fold collecting the results in a map from the keys to the results.
1272-- Useful for cases like protocol handlers to handle different type of packets
1273-- using different handlers.
1275-- @
1277-- |-------Fold m a b
1278-- -----stream m a-----Map-----|
1279-- |-------Fold m a b
1280-- |
1281-- ...
1282-- @
1284-- @since 0.7.0
1285{-# INLINE demuxWith #-}
1286demuxWith :: (Monad m, Ord k)
1287 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a (Map k b)
1288demuxWith f kv = Fold step initial extract
1290 where
1292 initial = return kv
1293-- alterF is available only since containers version 0.5.8.2
1294#if MIN_VERSION_containers(0,5,8)
1295 step mp a = case f a of
1296 (k, a') -> Map.alterF twiddle k mp
1297 -- XXX should we raise an exception in Nothing case?
1298 -- Ideally we should enforce that it is a total map over k so that look
1299 -- up never fails
1300 -- XXX we could use a monadic update function for a single lookup and
1301 -- update in the map.
1302 where
1303 twiddle Nothing = pure Nothing
1304 twiddle (Just (Fold step' acc extract')) = do
1305 !r <- acc >>= \x -> step' x a'
1306 pure . Just $ Fold step' (return r) extract'
1307#else
1308 step mp a =
1309 let (k, a') = f a
1310 in case Map.lookup k mp of
1311 Nothing -> return mp
1312 Just (Fold step' acc extract') -> do
1313 !r <- acc >>= \x -> step' x a'
1314 return $ Map.insert k (Fold step' (return r) extract') mp
1315#endif
1316 extract = Prelude.mapM (\(Fold _ acc e) -> acc >>= e)
1318-- | Fold a stream of key value pairs using a map of specific folds for each
1319-- key into a map from keys to the results of fold outputs of the corresponding
1320-- values.
1322-- @
1323-- > let table = Data.Map.fromList [(\"SUM", FL.sum), (\"PRODUCT", FL.product)]
1324-- input = S.fromList [(\"SUM",1),(\"PRODUCT",2),(\"SUM",3),(\"PRODUCT",4)]
1325-- in S.fold (FL.demux table) input
1326-- fromList [("PRODUCT",8),("SUM",4)]
1327-- @
1329-- @since 0.7.0
1330{-# INLINE demux #-}
1331demux :: (Monad m, Ord k)
1332 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
1333demux = demuxWith id
1335{-# INLINE demuxWithDefault_ #-}
1336demuxWithDefault_ :: (Monad m, Ord k)
1337 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m (k, a') b -> Fold m a ()
1338demuxWithDefault_ f kv (Fold dstep dinitial dextract) =
1339 Fold step initial extract
1341 where
1343 initFold (Fold s i e) = i >>= \r -> return (Fold s (return r) e)
1344 initial = do
1345 mp <- Prelude.mapM initFold kv
1346 dacc <- dinitial
1347 return (Tuple' mp dacc)
1348 step (Tuple' mp dacc) a
1349 | (k, a') <- f a
1350 = case Map.lookup k mp of
1351 Nothing -> do
1352 acc <- dstep dacc (k, a')
1353 return (Tuple' mp acc)
1354 Just (Fold step' acc _) -> do
1355 _ <- acc >>= \x -> step' x a'
1356 return (Tuple' mp dacc)
1357 extract (Tuple' mp dacc) = do
1358 void $ dextract dacc
1359 Prelude.mapM_ (\(Fold _ acc e) -> acc >>= e) mp
1361-- | Split the input stream based on a key field and fold each split using a
1362-- specific fold without collecting the results. Useful for cases like protocol
1363-- handlers to handle different type of packets.
1365-- @
1367-- |-------Fold m a ()
1368-- -----stream m a-----Map-----|
1369-- |-------Fold m a ()
1370-- |
1371-- ...
1372-- @
1375-- @since 0.7.0
1377-- demuxWith_ can be slightly faster than demuxWith because we do not need to
1378-- update the Map in this case. This may be significant only if the map is
1379-- large.
1380{-# INLINE demuxWith_ #-}
1381demuxWith_ :: (Monad m, Ord k)
1382 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a ()
1383demuxWith_ f kv = Fold step initial extract
1385 where
1387 initial = do
1388 Prelude.mapM (\(Fold s i e) ->
1389 i >>= \r -> return (Fold s (return r) e)) kv
1390 step mp a
1391 -- XXX should we raise an exception in Nothing case?
1392 -- Ideally we should enforce that it is a total map over k so that look
1393 -- up never fails
1394 | (k, a') <- f a
1395 = case Map.lookup k mp of
1396 Nothing -> return mp
1397 Just (Fold step' acc _) -> do
1398 _ <- acc >>= \x -> step' x a'
1399 return mp
1400 extract mp = Prelude.mapM_ (\(Fold _ acc e) -> acc >>= e) mp
1402-- | Given a stream of key value pairs and a map from keys to folds, fold the
1403-- values for each key using the corresponding folds, discarding the outputs.
1405-- @
1406-- > let prn = FL.drainBy print
1407-- > let table = Data.Map.fromList [(\"ONE", prn), (\"TWO", prn)]
1408-- input = S.fromList [(\"ONE",1),(\"TWO",2)]
1409-- in S.fold (FL.demux_ table) input
1410-- One 1
1411-- Two 2
1412-- @
1414-- @since 0.7.0
1415{-# INLINE demux_ #-}
1416demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
1417demux_ = demuxWith_ id
1419{-# INLINE demuxDefault_ #-}
1420demuxDefault_ :: (Monad m, Ord k)
1421 => Map k (Fold m a ()) -> Fold m (k, a) () -> Fold m (k, a) ()
1422demuxDefault_ = demuxWithDefault_ id
1424-- TODO If the data is large we may need a map/hashmap in pinned memory instead
1425-- of a regular Map. That may require a serializable constraint though. We can
1426-- have another API for that.
1428-- | Split the input stream based on a key field and fold each split using the
1429-- given fold. Useful for map/reduce, bucketizing the input in different bins
1430-- or for generating histograms.
1432-- @
1433-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1434-- in S.fold (FL.classify FL.toList) input
1435-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1436-- @
1438-- @since 0.7.0
1439{-# INLINE classifyWith #-}
1440classifyWith :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1441classifyWith f (Fold step initial extract) = Fold step' initial' extract'
1443 where
1445 initial' = return Map.empty
1446 step' kv a =
1447 let k = f a
1448 in case Map.lookup k kv of
1449 Nothing -> do
1450 x <- initial
1451 r <- step x a
1452 return $ Map.insert k r kv
1453 Just x -> do
1454 r <- step x a
1455 return $ Map.insert k r kv
1456 extract' = Prelude.mapM extract
1458-- | Given an input stream of key value pairs and a fold for values, fold all
1459-- the values belonging to each key. Useful for map/reduce, bucketizing the
1460-- input in different bins or for generating histograms.
1462-- @
1463-- > let input = S.fromList [(\"ONE",1),(\"ONE",1.1),(\"TWO",2), (\"TWO",2.2)]
1464-- in S.fold (FL.classify FL.toList) input
1465-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1466-- @
1468-- @since 0.7.0
1470-- Same as:
1472-- > classify fld = classifyWith fst (lmap snd fld)
1474{-# INLINE classify #-}
1475classify :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
1476classify fld = classifyWith fst (lmap snd fld)
1478------------------------------------------------------------------------------
1479-- Unzipping
1480------------------------------------------------------------------------------
1482-- | Like 'unzipWith' but with a monadic splitter function.
1484-- @since 0.7.0
1485{-# INLINE unzipWithM #-}
1486unzipWithM :: Monad m
1487 => (a -> m (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1488unzipWithM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1489 Fold step begin done
1491 where
1493 step (Tuple' xL xR) a = do
1494 (b,c) <- f a
1495 Tuple' <$> stepL xL b <*> stepR xR c
1496 begin = Tuple' <$> beginL <*> beginR
1497 done (Tuple' xL xR) = (,) <$> doneL xL <*> doneR xR
1499-- | Split elements in the input stream into two parts using a pure splitter
1500-- function, direct each part to a different fold and zip the results.
1502-- @since 0.7.0
1503{-# INLINE unzipWith #-}
1504unzipWith :: Monad m
1505 => (a -> (b,c)) -> Fold m b x -> Fold m c y -> Fold m a (x,y)
1506unzipWith f = unzipWithM (return . f)
1508-- | Send the elements of tuples in a stream of tuples through two different
1509-- folds.
1511-- @
1513-- |-------Fold m a x--------|
1514-- ---------stream of (a,b)--| |----m (x,y)
1515-- |-------Fold m b y--------|
1517-- @
1519-- This is the consumer side dual of the producer side 'zip' operation.
1521-- @since 0.7.0
1522{-# INLINE unzip #-}
1523unzip :: Monad m => Fold m a x -> Fold m b y -> Fold m (a,b) (x,y)
1524unzip = unzipWith id
1526------------------------------------------------------------------------------
1527-- Nesting
1528------------------------------------------------------------------------------
1531-- All the stream flattening transformations can also be applied to a fold
1532-- input stream.
1534-- | This can be used to apply all the stream generation operations on folds.
1535lconcatMap ::(IsStream t, Monad m) => (a -> t m b)
1536 -> Fold m b c
1537 -> Fold m a c
1538lconcatMap s f1 f2 = undefined
1541-- All the grouping transformation that we apply to a stream can also be
1542-- applied to a fold input stream. groupBy et al can be written as terminating
1543-- folds and then we can apply foldChunks to use those repeatedly on a stream.
1545-- | Apply a terminating fold repeatedly to the input of another fold.
1547-- Compare with: Streamly.Prelude.concatMap, Streamly.Prelude.foldChunks
1549-- /Unimplemented/
1551{-# INLINABLE foldChunks #-}
1552foldChunks ::
1553 -- Monad m =>
1554 Fold m a b -> Fold m b c -> Fold m a c
1555foldChunks = undefined
1558-- XXX this would be an application of foldChunks using a terminating fold.
1560-- | Group the input stream into groups of elements between @low@ and @high@.
1561-- Collection starts in chunks of @low@ and then keeps doubling until we reach
1562-- @high@. Each chunk is folded using the provided fold function.
1564-- This could be useful, for example, when we are folding a stream of unknown
1565-- size to a stream of arrays and we want to minimize the number of
1566-- allocations.
1568-- @
1570-- XXX we should be able to implement it with parsers/terminating folds.
1572{-# INLINE lchunksInRange #-}
1573lchunksInRange :: Monad m
1574 => Int -> Int -> Fold m a b -> Fold m b c -> Fold m a c
1575lchunksInRange low high (Fold step1 initial1 extract1)
1576 (Fold step2 initial2 extract2) = undefined
1579------------------------------------------------------------------------------
1580-- Fold to a Parallel SVar
1581------------------------------------------------------------------------------
1583{-# INLINE toParallelSVar #-}
1584toParallelSVar :: MonadIO m => SVar t m a -> Maybe WorkerInfo -> Fold m a ()
1585toParallelSVar svar winfo = Fold step initial extract
1586 where
1588 initial = return ()
1590 step () x = liftIO $ do
1591 -- XXX we can have a separate fold for unlimited buffer case to avoid a
1592 -- branch in the step here.
1593 decrementBufferLimit svar
1594 void $ send svar (ChildYield x)
1596 extract () = liftIO $ do
1597 sendStop svar winfo
1599{-# INLINE toParallelSVarLimited #-}
1600toParallelSVarLimited :: MonadIO m
1601 => SVar t m a -> Maybe WorkerInfo -> Fold m a ()
1602toParallelSVarLimited svar winfo = Fold step initial extract
1603 where
1605 initial = return True
1607 step True x = liftIO $ do
1608 yieldLimitOk <- decrementYieldLimit svar
1609 if yieldLimitOk
1610 then do
1611 decrementBufferLimit svar
1612 void $ send svar (ChildYield x)
1613 return True
1614 else do
1615 cleanupSVarFromWorker svar
1616 sendStop svar winfo
1617 return False
1618 step False _ = return False
1620 extract True = liftIO $ sendStop svar winfo
1621 extract False = return ()