@@ -6,9 +6,8 @@
6-- Maintainer : streamly@composewell.com
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
10−-- Also see the "Streamly.Internal.Data.Sink" module that provides specialized
10+-- See "Streamly.Data.Fold" for an overview.
11−-- left folds that discard the outputs.
13-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
12-- IMPORTANT: keep the signatures consistent with the folds in Streamly.Prelude
@@ -18,13 +17,7 @@ module Streamly.Internal.Data.Fold
19 , Fold (..)
18 , Fold (..)
21− , hoist
20+ -- * Creating
27− -- * Fold Creation Utilities
29 , mkAccum_
22 , mkAccum_
30 , mkAccumM
23 , mkAccumM
@@ -34,19 +27,23 @@ module Streamly.Internal.Data.Fold
35 , mkFoldM_
28 , mkFoldM_
37− -- ** Full Folds
30+ -- * Generators
35+ -- ** Semigroups and Monoids
40 , drainBy2
44 , drainBy2
51 , variance
48 , variance
@@ -55,22 +52,24 @@ module Streamly.Internal.Data.Fold
55 , rollingHashFirstN
52 , rollingHashFirstN
56 -- , rollingHashLastN
53 -- , rollingHashLastN
58− -- ** Fold Semigroups
55+ -- ** Saturating Reducers
59− , sconcat
56+ -- | 'product' terminates if it becomes 0. Other folds can theoretically
60−
57+ -- saturate on bounded types, and therefore terminate, however, they will
61− -- ** Full Folds (Monoidal)
58+ -- run forever on unbounded types like Integer/Double.
63− , foldMap
60+ , product
64− , foldMapM
61+ , maximumBy
66− -- ** Full Folds (To Containers)
63+ , minimumBy
69 , toListRevF -- experimental
68 , toListRevF -- experimental
71− -- ** Partial Folds
71+ -- * Terminating Folds
74 -- , lastN
73 -- , lastN
76 -- , genericIndex
75 -- , genericIndex
@@ -84,18 +83,27 @@ module Streamly.Internal.Data.Fold
87− -- XXX these are slower than right folds even when full input is used
91+ , toParallelSVarLimited
93− -- * Transformations
93+ -- * Adapting
97+ -- * Running Incrementally
95− -- ** Covariant Operations
101+ -- * Output Transformations
96 , sequence
102 , sequence
105+ -- * Input Transformations
99 -- ** Mapping
107 -- ** Mapping
100 , transform
108 , transform
@@ -127,37 +135,35 @@ module Streamly.Internal.Data.Fold
127 , lreverse
135 , lreverse
131 -- ** Trimming
138 -- ** Trimming
133− -- , lrunFor -- time
140+ , takeByTime
134− , takeSepBy
141+ -- By elements
138 , ldropWhile
149 , ldropWhile
139 , ldropWhileM
150 , ldropWhileM
142− , lsessionsOf
153+ -- * Splitting
147 -- Binary
155 -- Binary
148 , splitAt -- spanN
158 , splitAt -- spanN
149 -- , splitIn -- sessionN
159 -- , splitIn -- sessionN
151− -- By elements
161+ -- XXX To be moved to parsers
152 , span -- spanWhile
162 , span -- spanWhile
153 , break -- breakBefore
163 , break -- breakBefore
156 -- , breakAround
164 -- , breakAround
158 , spanByRolling
166 , spanByRolling
162 -- By sequences
168 -- By sequences
163 -- , breakOnSeq
169 -- , breakOnSeq
@@ -166,8 +172,12 @@ module Streamly.Internal.Data.Fold
166 -- * Distributing
172 -- * Distributing
169 , distribute
178 , distribute
170− , distribute_
179+ -- , distributeFst
172 -- * Partitioning
182 -- * Partitioning
@@ -179,17 +189,19 @@ module Streamly.Internal.Data.Fold
180 -- * Demultiplexing
190 -- * Demultiplexing
182− , demux
192+ , demux -- XXX rename this to demux_
183 , demuxWith
193 , demuxWith
184− , demux_
194+ , demuxDefault -- XXX rename this to demux
185− , demuxDefault_
195+ , demuxDefaultWith
186− , demuxWith_
196+ -- , demuxWithSel
187− , demuxWithDefault_
197+ -- , demuxWithMin
189 -- * Classifying
199 -- * Classifying
191 , classify
201 , classify
192 , classifyWith
202 , classifyWith
203+ -- , classifyWithSel
204+ -- , classifyWithMin
194 -- * Unzipping
206 -- * Unzipping
@@ -198,18 +210,15 @@ module Streamly.Internal.Data.Fold
198 , unzipWithFstM
210 , unzipWithFstM
199 , unzipWithMinM
211 , unzipWithMinM
201− -- * Nested Folds
213+ -- * Nesting
204− , duplicate
215+ , lsessionsOf
206− -- * Running Folds
217+ , chunksBetween
210− -- * Folding to SVar
219+ , concatSequence
211− , toParallelSVar
220+ , concatMap
212− , toParallelSVarLimited
221+ , duplicate
@@ -222,15 +231,14 @@ import Data.Maybe (isJust, fromJust)
222#if __GLASGOW_HASKELL__ < 804
231#if __GLASGOW_HASKELL__ < 804
223import Data.Semigroup (Semigroup((<>)))
232import Data.Semigroup (Semigroup((<>)))
234+import Streamly.Internal.Data.Either.Strict (Either'(..))
235+import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
225import Streamly.Internal.Data.Pipe.Types (Pipe (..), PipeState(..))
236import Streamly.Internal.Data.Pipe.Types (Pipe (..), PipeState(..))
226import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
237import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
227−import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
228−import Streamly.Internal.Data.Either.Strict (Either'(..))
239+import qualified Data.Map.Strict as Map
230import qualified Streamly.Internal.Data.Fold.Types as FL
240import qualified Streamly.Internal.Data.Fold.Types as FL
231import qualified Streamly.Internal.Data.Pipe.Types as Pipe
241import qualified Streamly.Internal.Data.Pipe.Types as Pipe
232−import qualified Data.Map.Strict as Map
233−import qualified Data.Set as Set
234import qualified Prelude
242import qualified Prelude
236import Prelude hiding
244import Prelude hiding
@@ -542,7 +550,7 @@ sum = Fold (\x a -> return $ Partial $ x + a) (return 0) return
542-- > product = fmap getProduct $ FL.foldMap Product
550-- > product = fmap getProduct $ FL.foldMap Product
544-- @since 0.7.0
552-- @since 0.7.0
545−-- /since 0.8.0 (Added 'Eq' constraint)/
553+-- /Since 0.8.0 (Added 'Eq' constraint)/
546{-# INLINE product #-}
554{-# INLINE product #-}
547product :: (Monad m, Num a, Eq a) => Fold m a a
555product :: (Monad m, Num a, Eq a) => Fold m a a
548product = Fold step (return 1) return
556product = Fold step (return 1) return
@@ -758,7 +766,7 @@ mconcat = sconcat mempty
758-- @since 0.7.0
766-- @since 0.7.0
759{-# INLINABLE foldMap #-}
767{-# INLINABLE foldMap #-}
760foldMap :: (Monad m, Monoid b
768foldMap :: (Monad m, Monoid b
761−#if __GLASGOW_HASKELL__ < 804
769+#if !MIN_VERSION_base(4,11,0)
762 , Semigroup b
770 , Semigroup b
764 ) => (a -> b) -> Fold m a b
772 ) => (a -> b) -> Fold m a b
@@ -816,12 +824,6 @@ toList = Fold (\f x -> return $ Partial $ f . (x :))
816drainN :: Monad m => Int -> Fold m a ()
824drainN :: Monad m => Int -> Fold m a ()
817drainN n = ltake n drain
825drainN n = ltake n drain
819−-- | A fold that drains elements of its input as long as the predicate succeeds,
820−-- running the effects and discarding the results.
821−{-# INLINABLE drainSepBy #-}
822−drainSepBy :: Monad m => (a -> Bool) -> Fold m a ()
823−drainSepBy p = takeSepBy p drain
825------------------------------------------------------------------------------
827------------------------------------------------------------------------------
826-- To Elements
828-- To Elements
827------------------------------------------------------------------------------
829------------------------------------------------------------------------------
@@ -932,12 +934,15 @@ elemIndex a = findIndex (a ==)
932null :: Monad m => Fold m a Bool
934null :: Monad m => Fold m a Bool
933null = Fold (\() _ -> return $ Done False) (return ()) (\() -> return True)
935null = Fold (\() _ -> return $ Done False) (return ()) (\() -> return True)
936-- > any p = lmap p or
938-- > any p = lmap p or
937-- > any p = fmap getAny . FL.foldMap (Any . p)
939-- > any p = fmap getAny . FL.foldMap (Any . p)
939-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
941-- | Returns 'True' if any of the elements of a stream satisfies a predicate.
943+-- >>> Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]
941-- @since 0.7.0
946-- @since 0.7.0
942{-# INLINE any #-}
947{-# INLINE any #-}
943any :: Monad m => (a -> Bool) -> Fold m a Bool
948any :: Monad m => (a -> Bool) -> Fold m a Bool
@@ -962,12 +967,15 @@ any predicate = Fold step initial return
962elem :: (Eq a, Monad m) => a -> Fold m a Bool
967elem :: (Eq a, Monad m) => a -> Fold m a Bool
963elem a = any (a ==)
968elem a = any (a ==)
966-- > all p = lmap p and
971-- > all p = lmap p and
967-- > all p = fmap getAll . FL.foldMap (All . p)
972-- > all p = fmap getAll . FL.foldMap (All . p)
969-- | Returns 'True' if all elements of a stream satisfy a predicate.
974-- | Returns 'True' if all elements of a stream satisfy a predicate.
976+-- >>> Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]
971-- @since 0.7.0
979-- @since 0.7.0
972{-# INLINABLE all #-}
980{-# INLINABLE all #-}
973all :: Monad m => (a -> Bool) -> Fold m a Bool
981all :: Monad m => (a -> Bool) -> Fold m a Bool
@@ -1050,11 +1058,10 @@ or = any (== True)
1050-- >>> splitAt_ 4 [1,2,3]
1058-- >>> splitAt_ 4 [1,2,3]
1051-- > ([1,2,3],[])
1059-- > ([1,2,3],[])
1061+-- > splitAt n f1 f2 = splitWith (,) (ltake n f1) f2
1053-- /Internal/
1063-- /Internal/
1055−-- This can be considered as a two-fold version of 'ltake' where we take both
1056−-- the segments instead of discarding the leftover.
1058{-# INLINE splitAt #-}
1065{-# INLINE splitAt #-}
1060 :: Monad m
1067 :: Monad m
@@ -1062,7 +1069,7 @@ splitAt
1062 -> Fold m a b
1069 -> Fold m a b
1063 -> Fold m a c
1070 -> Fold m a c
1064 -> Fold m a (b, c)
1071 -> Fold m a (b, c)
1065−splitAt n fld1 = splitWith (,) (ltake n fld1)
1072+splitAt n fld = splitWith (,) (ltake n fld)
1067------------------------------------------------------------------------------
1074------------------------------------------------------------------------------
1068-- Element Aware APIs
1075-- Element Aware APIs
@@ -1072,7 +1079,18 @@ splitAt n fld1 = splitWith (,) (ltake n fld1)
1072-- Binary APIs
1079-- Binary APIs
1073------------------------------------------------------------------------------
1080------------------------------------------------------------------------------
1082+-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1083+-- S.splitOn in favor of the fold.
1075−-- | Stops the fold at an infixed separator element, dropping the separator.
1085+-- | Consume the input until it encounters an infixed separator element (i.e.
1086+-- when the supplied predicate succeeds), dropping the separator.
1088+-- Repeated applications of 'sliceSepBy' splits the stream on separator
1089+-- elements determined by the supplied predicate, separator is considered as
1090+-- infixed between two segments, if one side of the separator is missing then
1091+-- it is parsed as an empty stream. The supplied 'Fold' is applied on the
1092+-- split segments. With '-' representing non-separator elements and '.' as
1093+-- separator, repeated 'sliceSepBy' splits the stream as follows:
1078-- "--.--" => "--" "--"
1096-- "--.--" => "--" "--"
@@ -1080,12 +1098,41 @@ splitAt n fld1 = splitWith (,) (ltake n fld1)
1080-- ".--" => "" "--"
1098-- ".--" => "" "--"
1101+-- Repeated applications of @Fold.sliceSepBy (== x)@ on the input stream gives us
1102+-- an inverse of @Stream.intercalate (Stream.yield x)@
1104+-- > Stream.splitOn pred f = Stream.foldMany (Fold.sliceSepBy pred f)
1106+-- Let's use the following definition for illustration:
1108+-- > splitOn p = Stream.foldMany (Fold.sliceSepBy pred Fold.toList)
1109+-- > splitOn' p = Stream.toList . splitOn p . Stream.fromList
1111+-- >>> splitOn' (== '.') ""
1114+-- >>> splitOn' (== '.') "."
1117+-- >>> splitOn' (== '.') ".a"
1120+-- >>> splitOn' (== '.') "a."
1123+-- >>> splitOn' (== '.') "a.b"
1126+-- >>> splitOn' (== '.') "a..b"
1083−-- * Stops - when the predicate succeeds.
1129+-- Stops - when the predicate succeeds.
1085-- /Internal/
1131-- /Internal/
1086{-# INLINE sliceSepBy #-}
1132{-# INLINE sliceSepBy #-}
1087sliceSepBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1133sliceSepBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1088−sliceSepBy predicate (Fold fstep finitial fextract) = Fold step initial fextract
1134+sliceSepBy predicate (Fold fstep finitial fextract) =
1135+ Fold step initial fextract
@@ -1096,20 +1143,56 @@ sliceSepBy predicate (Fold fstep finitial fextract) = Fold step initial fextract
1096 then fstep s a
1143 then fstep s a
1097 else Done <$> fextract s
1144 else Done <$> fextract s
1099−-- | Like 'sliceSepBy' but does not drop the seperator element.
1146+-- | Like 'sliceSepBy' but terminates a parse even before the separator
1147+-- is encountered if its size exceeds the specified maximum limit.
1101−-- @
1149+-- > take n = PR.sliceSepByMax (const True) n
1102−-- "--.--" => "--." "--"
1150+-- > sliceSepBy p = PR.sliceSepByMax p maxBound
1103−-- "--." => "--." ""
1151+--
1104−-- ".--" => "." "--"
1152+-- Let's use the following definitions for illustration:
1154+-- > splitOn p n = PR.many FL.toList $ PR.sliceSepByMax p n (FL.toList)
1155+-- > splitOn' p n = S.parse (splitOn p n) . S.fromList
1157+-- >>> splitOn' (== '.') 0 ""
1160+-- >>> splitOn' (== '.') 0 "a"
1161+-- infinite list of empty strings
1163+-- >>> splitOn' (== '.') 3 "hello.world"
1164+-- ["hel","lo","wor","ld"]
1166+-- If the separator is found and the limit is reached at the same time then it
1167+-- behaves just like 'sliceSepBy' i.e. the separator is dropped.
1169+-- >>> splitOn' (== '.') 0 "."
1172+-- >>> splitOn' (== '.') 0 ".."
1175+-- Stops - when the predicate succeeds or the limit is reached.
1178+{-# INLINABLE sliceSepByMax #-}
1179+sliceSepByMax :: Monad m
1180+ => (a -> Bool) -> Int -> Fold m a b -> Fold m a b
1181+sliceSepByMax p n = sliceSepBy p . ltake n
1183+-- | Collect stream elements until an element succeeds the predicate. Also take
1184+-- the element on which the predicate succeeded. The succeeding element is
1185+-- treated as a suffix separator which is kept in the output segement.
1107-- * Stops - when the predicate succeeds.
1187-- * Stops - when the predicate succeeds.
1189+-- > Stream.splitWithSuffix pred f = Stream.foldMany (Fold.sliceEndWith pred f)
1109-- /Internal/
1191-- /Internal/
1110−{-# INLINE sliceSepWith #-}
1192+--
1193+{-# INLINE sliceEndWith #-}
1111−sliceSepWith :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1194+sliceEndWith :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1112−sliceSepWith predicate (Fold fstep finitial fextract) =
1195+sliceEndWith predicate (Fold fstep finitial fextract) =
1113 Fold step initial fextract
1196 Fold step initial fextract
@@ -1375,7 +1458,6 @@ foldNil = Fold step begin done where
1375 step _ _ = return $ Partial []
1458 step _ _ = return $ Partial []
1376 done = return
1459 done = return
1378−-- XXX How is the performance?
1379{-# INLINE foldCons #-}
1461{-# INLINE foldCons #-}
1380foldCons :: Monad m => Fold m a b -> Fold m a [b] -> Fold m a [b]
1462foldCons :: Monad m => Fold m a b -> Fold m a [b] -> Fold m a [b]
1381foldCons = teeWith (:)
1463foldCons = teeWith (:)
@@ -1401,58 +1483,19 @@ foldCons = teeWith (:)
1402-- This is the consumer side dual of the producer side 'sequence' operation.
1484-- This is the consumer side dual of the producer side 'sequence' operation.
1486+-- Stops when all the folds stop.
1404-- @since 0.7.0
1488-- @since 0.7.0
1405{-# INLINE distribute #-}
1489{-# INLINE distribute #-}
1406distribute :: Monad m => [Fold m a b] -> Fold m a [b]
1490distribute :: Monad m => [Fold m a b] -> Fold m a [b]
1407distribute = foldr foldCons foldNil
1491distribute = foldr foldCons foldNil
1409−-- XXX This is 2x times faster wiithout the terminating condition.
1410−-- | Like 'distribute' but for folds that return (), this can be more efficient
1411−-- than 'distribute' as it does not need to maintain state. This fold terminates
1412−-- when all the folds terminate.
1414−{-# INLINE distribute_ #-}
1415−distribute_ :: Monad m => [Fold m a ()] -> Fold m a ()
1416−distribute_ fs = Fold step initial extract
1420− initial = Prelude.mapM initialize fs
1422− -- XXX This itself can be a recursive function but we might face inlining
1424− step [] _ = return $ Done ()
1428− $ if Prelude.null ss1
1432− go [] _ = return []
1433− go ((Fold s i d):ss) a = do
1439− let fld = Fold s (return i2) d
1443− extract ss = go1 ss
1446− go1 ((Fold _ i d):ss) = (i >>= d) >> go1 ss
1448------------------------------------------------------------------------------
1493------------------------------------------------------------------------------
1449-- Partitioning
1494-- Partitioning
1450------------------------------------------------------------------------------
1495------------------------------------------------------------------------------
1452-- | Partition the input over two folds using an 'Either' partitioning
1497-- | Partition the input over two folds using an 'Either' partitioning
1453−-- predicate. This fold terminates when both the folds terminate.
1498+-- predicate.
1455−-- See also: 'partitionByFstM' and 'partitionByMinM'.
@@ -1490,6 +1533,13 @@ distribute_ fs = Fold step initial extract
1491-- This is the consumer side dual of the producer side 'mergeBy' operation.
1534-- This is the consumer side dual of the producer side 'mergeBy' operation.
1536+-- When one fold is done, any input meant for it is ignored until the other
1537+-- fold is also done.
1539+-- Stops when both the folds stop.
1541+-- /See also: 'partitionByFstM' and 'partitionByMinM'./
1493-- @since 0.7.0
1543-- @since 0.7.0
1494{-# INLINE partitionByM #-}
1544{-# INLINE partitionByM #-}
1495partitionByM :: Monad m
1545partitionByM :: Monad m
@@ -1499,10 +1549,7 @@ partitionByM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1502− begin = do
1552+ begin = RunBoth <$> beginL <*> beginR
1505− return $ RunBoth sL sR
1507 step (RunBoth sL sR) a = do
1554 step (RunBoth sL sR) a = do
1508 r <- f a
1555 r <- f a
@@ -1542,16 +1589,9 @@ partitionByM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1542 Partial sres -> Partial $ RunRight bL sres
1589 Partial sres -> Partial $ RunRight bL sres
1543 Done bres -> Done (bL, bres)
1590 Done bres -> Done (bL, bres)
1545− done (RunBoth sL sR) = do
1592+ done (RunBoth sL sR) = (,) <$> doneL sL <*> doneR sR
1549− done (RunLeft sL bR) = do
1593+ done (RunLeft sL bR) = (,bR) <$> doneL sL
1552− done (RunRight bL sR) = do
1594+ done (RunRight bL sR) = (bL,) <$> doneR sR
1556-- | Similar to 'partitionByM' but terminates when the first fold terminates.
1596-- | Similar to 'partitionByM' but terminates when the first fold terminates.
@@ -1639,44 +1679,16 @@ partition = partitionBy id
1642−-- @since 0.7.0
1682+-- Any input that does not map to a fold in the input Map is silently ignored.
1684+-- > demuxWith f kv = fmap fst $ demuxDefaultWith f kv drain
1643{-# INLINE demuxWith #-}
1688{-# INLINE demuxWith #-}
1644demuxWith :: (Monad m, Ord k)
1689demuxWith :: (Monad m, Ord k)
1645 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a (Map k b)
1690 => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a (Map k b)
1646−demuxWith f kv = Fold step initial extract
1691+demuxWith f kv = fmap fst $ demuxDefaultWith f kv drain
1650− initial = Tuple' Map.empty <$> Prelude.mapM initialize kv
1652− step (Tuple' bmp mp) a =
1656− case Map.lookup k mp of
1657− Nothing -> return $ Partial $ Tuple' bmp mp
1658− Just (Fold stp ini dn) -> do
1664− let fld = Fold stp (return sres) dn
1665− mp1 = Map.insert k fld mp
1666− in Partial $ Tuple' bmp mp1
1668− let mp1 = Map.delete k mp
1669− bmp1 = Map.insert k bres bmp
1670− in if Map.size mp1 == 0
1672− else Partial $ Tuple' bmp1 mp1
1673− -- XXX This state is reached even for an empty Map. That will change
1674− -- once we have Step in the initial value
1675− else error "Illegal state"
1677− extract (Tuple' bmp mp) = do
1678− mpe <- Prelude.mapM (\(Fold _ i d) -> i >>= d) mp
1679− return $ bmp `Map.union` mpe
1681-- | Fold a stream of key value pairs using a map of specific folds for each
1693-- | Fold a stream of key value pairs using a map of specific folds for each
1682-- key into a map from keys to the results of fold outputs of the corresponding
1694-- key into a map from keys to the results of fold outputs of the corresponding
@@ -1695,164 +1707,119 @@ demux :: (Monad m, Ord k)
1695 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
1707 => Map k (Fold m a b) -> Fold m (k, a) (Map k b)
1696demux = demuxWith id
1708demux = demuxWith id
1698−-- data DemuxState m s = DemuxP !m !s | DemuxingOnlyMap !m
1710+data DemuxState s b rMap kvMap =
1699−data DemuxState s m1 m2 = DemuxingWithDefault !s !m1 !m2 | DemuxingOnlyMap !m2
1711+ DemuxMapWithDefault !s !rMap !kvMap
1712+ | DemuxMap b !rMap !kvMap
1713+ | DemuxDefault s !rMap
1701−{-# INLINE demuxWithDefault_ #-}
1715+-- | Like 'demuxWith' but uses a default catchall fold to handle inputs which
1702−demuxWithDefault_ :: (Monad m, Ord k)
1716+-- do not have a specific fold in the map to handle them.
1718+-- If any fold in the map stops, inputs meant for that fold are sent to the
1719+-- catchall fold. If the catchall fold stops then inputs that do not match any
1720+-- fold are ignored.
1722+-- Stops when all the folds, including the catchall fold, stop.
1726+{-# INLINE demuxDefaultWith #-}
1727+demuxDefaultWith :: (Monad m, Ord k)
1703− => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m (k, a') b -> Fold m a ()
1729+ -> Map k (Fold m a' b)
1730+ -> Fold m (k, a') c
1731+ -> Fold m a (Map k b, c)
1704−demuxWithDefault_ f kv (Fold dstep dinitial dextract) =
1732+demuxDefaultWith f kv (Fold dstep dinitial dextract) =
1705 Fold step initial extract
1733 Fold step initial extract
1709− initial = do
1737+ initial =
1738+ DemuxMapWithDefault
1710− ini <- dinitial
1739+ <$> dinitial
1740+ <*> return Map.empty
1711− mp <- Prelude.mapM initialize kv
1741+ <*> Prelude.mapM initialize kv
1712− return $ DemuxingWithDefault ini Set.empty mp
1714− -- XXX Some code can probably be abstracted
1743+ step (DemuxMapWithDefault dacc results kvMap) a =
1715− step (DemuxingWithDefault dacc bst mp) a =
1716− if Map.size mp > 0
1744+ if Map.size kvMap > 0
1718 let (k, a1) = f a
1746 let (k, a1) = f a
1719− case Map.lookup k mp of
1747+ case Map.lookup k kvMap of
1720− Nothing ->
1748+ Nothing -> do
1721− if k `Set.member` bst
1722− then return $ Partial $ DemuxingWithDefault dacc bst mp
1724− res <- dstep dacc (k, a1)
1749+ res <- dstep dacc (k, a1)
1729− DemuxingWithDefault sres bst mp
1730− Done _ -> DemuxingOnlyMap mp
1731− Just (Fold stp ini dn) -> do
1735 $ case res of
1752 $ case res of
1736− Partial sres ->
1753+ Partial s -> DemuxMapWithDefault s results kvMap
1737− let fld = Fold stp (return sres) dn
1754+ Done b -> DemuxMap b results kvMap
1738− mp1 = Map.insert k fld mp
1739− in Partial $ DemuxingWithDefault dacc bst mp1
1741− -- XXX We can skip the check here
1742− if Map.size mp == 1
1745− $ DemuxingWithDefault
1749− -- XXX This state is reached even for an empty Map. That will change
1750− -- once we have Step in the initial value
1751− else error "Illegal state"
1752− -- XXX Reduce code duplication?
1753− step (DemuxingOnlyMap mp) a =
1757− case Map.lookup k mp of
1758− Nothing -> return $ Partial $ DemuxingOnlyMap mp
1759− Just (Fold stp ini dn) -> do
1755+ Just (Fold step1 initial1 extract1) -> do
1760− !st <- ini
1756+ !st <- initial1
1761− !res <- stp st a1
1757+ !res <- step1 st a1
1763 $ case res of
1759 $ case res of
1764− Partial sres ->
1760+ Partial s ->
1765− Partial
1761+ let fld = Fold step1 (return s) extract1
1767− $ Map.insert
1762+ kvMap1 = Map.insert k fld kvMap
1769− (Fold stp (return sres) dn)
1764+ $ DemuxMapWithDefault
1770− mp
1765+ dacc results kvMap1
1771− Done _ ->
1766+ Done b ->
1767+ let kvMap1 = Map.delete k kvMap
1768+ results1 = Map.insert k b results
1772− if Map.size mp == 1
1770+ $ if Map.size kvMap1 == 0
1773− then Done ()
1771+ then DemuxDefault dacc results1
1774− else Partial
1772+ else DemuxMapWithDefault
1775− $ DemuxingOnlyMap $ Map.delete k mp
1773+ dacc results1 kvMap1
1776− -- XXX This state is reached even for an empty Map. That will change
1777− -- once we have Step in the initial value
1774+ -- XXX Remove this when we have Step in the initial value
1778− else error "Illegal state"
1775+ else error "demuxDefaultWith: empty key-value Map"
1779−
1776+ step (DemuxMap dval results kvMap) a =
1780− extract (DemuxingWithDefault dacc _ mp) = do
1777+ if Map.size kvMap > 0
1781− void $ dextract dacc
1778+ then do
1782− Prelude.mapM_ (\(Fold _ i d) -> i >>= d) mp
1783− extract (DemuxingOnlyMap mp) = do
1784− Prelude.mapM_ (\(Fold _ i d) -> i >>= d) mp
1786−-- | Split the input stream based on a key field and fold each split using a
1787−-- specific fold without collecting the results. Useful for cases like protocol
1788−-- handlers to handle different type of packets.
1792−-- |-------Fold m a ()
1793−-- -----stream m a-----Map-----|
1794−-- |-------Fold m a ()
1802−-- demuxWith_ can be slightly faster than demuxWith because we do not need to
1803−-- update the Map in this case. This may be significant only if the map is
1805−{-# INLINE demuxWith_ #-}
1806−demuxWith_ :: (Monad m, Ord k)
1807− => (a -> (k, a')) -> Map k (Fold m a' b) -> Fold m a ()
1808−demuxWith_ f kv = Fold step initial extract
1812− initial = Tuple' (Map.size kv) <$> Prelude.mapM initialize kv
1814− step (Tuple' n mp) a
1815− | (k, a') <- f a =
1779+ let (k, a1) = f a
1816− case Map.lookup k mp of
1780+ case Map.lookup k kvMap of
1817− Nothing -> return $ Partial $ Tuple' n mp
1781+ Nothing -> return $ Partial $ DemuxMap dval results kvMap
1818− Just (Fold stp ini dn) -> do
1782+ Just (Fold step1 initial1 extract1) -> do
1819− !st <- ini
1783+ !st <- initial1
1820− !res <- stp st a'
1784+ !res <- step1 st a1
1823 $ case res of
1786 $ case res of
1824− Partial sres ->
1787+ Partial s ->
1825− let fld = Fold stp (return sres) dn
1788+ let fld = Fold step1 (return s) extract1
1826− in Partial $ Tuple' n $ Map.insert k fld mp
1789+ kvMap1 = Map.insert k fld kvMap
1827− Done _ ->
1790+ in Partial $ DemuxMap dval results kvMap1
1828− if n1 == 0
1791+ Done b ->
1792+ let kvMap1 = Map.delete k kvMap
1793+ results1 = Map.insert k b results
1794+ in if Map.size kvMap1 == 0
1829− then Done ()
1795+ then Done (results1, dval)
1830− else Partial $ Tuple' n1 $ Map.delete k mp
1796+ else Partial
1831−
1797+ $ DemuxMap dval results1 kvMap1
1832− extract (Tuple' _ mp) = do
1798+ -- XXX Remove this when we have Step in the initial value
1833− Prelude.mapM_ (\(Fold _ i d) -> i >>= d) mp
1799+ else error "demuxDefaultWith: empty key-value Map"
1834−
1800+ step (DemuxDefault dacc results) a = do
1835−-- | Given a stream of key value pairs and a map from keys to folds, fold the
1801+ let (k, a1) = f a
1836−-- values for each key using the corresponding folds, discarding the outputs.
1802+ res <- dstep dacc (k, a1)
1838−-- @
1804+ $ case res of
1839−-- > let prn = FL.drainBy print
1805+ Partial s -> Partial $ DemuxDefault s results
1840−-- > let table = Data.Map.fromList [(\"ONE", prn), (\"TWO", prn)]
1806+ Done b -> Done (results, b)
1841−-- input = S.fromList [(\"ONE",1),(\"TWO",2)]
1807+
1842−-- in S.fold (FL.demux_ table) input
1808+ extract (DemuxMapWithDefault dacc results kvMap) = do
1843−-- One 1
1809+ b <- dextract dacc
1844−-- Two 2
1810+ kvMap1 <- Prelude.mapM (\(Fold _ i d) -> i >>= d) kvMap
1845−-- @
1811+ return (results `Map.union` kvMap1, b)
1846−--
1812+ extract (DemuxMap dval results kvMap) = do
1847−-- @since 0.7.0
1813+ kvMap1 <- Prelude.mapM (\(Fold _ i d) -> i >>= d) kvMap
1848−{-# INLINE demux_ #-}
1814+ return (results `Map.union` kvMap1, dval)
1849−demux_ :: (Monad m, Ord k) => Map k (Fold m a ()) -> Fold m (k, a) ()
1815+ extract (DemuxDefault dacc results) = do
1850−demux_ = demuxWith_ id
1816+ b <- dextract dacc
1851−
1817+ return (results, b)
1852−{-# INLINE demuxDefault_ #-}
1818+
1819+{-# INLINE demuxDefault #-}
1853−demuxDefault_ :: (Monad m, Ord k)
1820+demuxDefault :: (Monad m, Ord k)
1854− => Map k (Fold m a ()) -> Fold m (k, a) () -> Fold m (k, a) ()
1821+ => Map k (Fold m a b) -> Fold m (k, a) b -> Fold m (k, a) (Map k b, b)
1855−demuxDefault_ = demuxWithDefault_ id
1822+demuxDefault = demuxDefaultWith id
1857-- TODO If the data is large we may need a map/hashmap in pinned memory instead
1824-- TODO If the data is large we may need a map/hashmap in pinned memory instead
1858-- of a regular Map. That may require a serializable constraint though. We can
1825-- of a regular Map. That may require a serializable constraint though. We can
@@ -1868,7 +1835,13 @@ demuxDefault_ = demuxWithDefault_ id
1868-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1835-- fromList [(\"ONE",[1.1,1.0]),(\"TWO",[2.2,2.0])]
1871−-- @since 0.7.0
1838+-- If the classifier fold stops for a particular key any further inputs in that
1839+-- bucket are ignored.
1872{-# INLINE classifyWith #-}
1845{-# INLINE classifyWith #-}
1873classifyWith :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1846classifyWith :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1874classifyWith f (Fold step initial extract) = Fold step' initial' extract'
1847classifyWith f (Fold step initial extract) = Fold step' initial' extract'
@@ -1936,7 +1909,7 @@ classify fld = classifyWith fst (lmap snd fld)
1937-- | Like 'unzipWith' but with a monadic splitter function.
1910-- | Like 'unzipWith' but with a monadic splitter function.
1939−-- -- @unzipWithM f fld1 fld2 = lmapM f (unzip fld1 fld2)@
1912+-- -- @unzipWithM k f1 f2 = lmapM k (unzip f1 f2)@
1941-- @since 0.7.0
1914-- @since 0.7.0
1942{-# INLINE unzipWithM #-}
1915{-# INLINE unzipWithM #-}
@@ -1981,8 +1954,8 @@ unzipWithM f (Fold stepL beginL doneL) (Fold stepR beginR doneR) =
1981 Done bresR -> Done (bL, bresR)
1954 Done bresR -> Done (bL, bresR)
1983 done (RunBoth sL sR) = (,) <$> doneL sL <*> doneR sR
1956 done (RunBoth sL sR) = (,) <$> doneL sL <*> doneR sR
1984− done (RunLeft sL bR) = (,) <$> doneL sL <*> return bR
1957+ done (RunLeft sL bR) = (,bR) <$> doneL sL
1985− done (RunRight bL sR) = (,) bL <$> doneR sR
1958+ done (RunRight bL sR) = (bL,) <$> doneR sR
1987-- | Similar to 'unzipWithM' but terminates when the first fold terminates.
1960-- | Similar to 'unzipWithM' but terminates when the first fold terminates.
@@ -2037,10 +2010,17 @@ unzip = unzipWith id
2037-- Nesting
2010-- Nesting
2038------------------------------------------------------------------------------
2011------------------------------------------------------------------------------
2040−
2013+-- | @concatSequence f t@ applies folds from stream @t@ sequentially and
2041−{-
2014+-- collects the results using the fold @f@.
2042−-- XXX this would be an application of "many" using a terminating fold.
2018+{-# INLINE concatSequence #-}
2021+ Fold m b c -> t (Fold m a b) -> Fold m a c
2022+concatSequence _f _p = undefined
2044-- | Group the input stream into groups of elements between @low@ and @high@.
2024-- | Group the input stream into groups of elements between @low@ and @high@.
2045-- Collection starts in chunks of @low@ and then keeps doubling until we reach
2025-- Collection starts in chunks of @low@ and then keeps doubling until we reach
2046-- @high@. Each chunk is folded using the provided fold function.
2026-- @high@. Each chunk is folded using the provided fold function.
@@ -2049,16 +2029,14 @@ unzip = unzipWith id
2049-- size to a stream of arrays and we want to minimize the number of
2029-- size to a stream of arrays and we want to minimize the number of
2050-- allocations.
2030-- allocations.
2052−-- @
2032+-- NOTE: this would be an application of "many" using a terminating fold.
2054−-- XXX we should be able to implement it with parsers/terminating folds.
2034+-- /Unimplemented/
2056−{-# INLINE lchunksInRange #-}
2036+{-# INLINE chunksBetween #-}
2057−lchunksInRange :: Monad m
2037+chunksBetween :: -- Monad m =>
2058− => Int -> Int -> Fold m a b -> Fold m b c -> Fold m a c
2038+ Int -> Int -> Fold m a b -> Fold m b c -> Fold m a c
2059−lchunksInRange low high (Fold step1 initial1 extract1)
2039+chunksBetween _low _high _f1 _f2 = undefined
2060− (Fold step2 initial2 extract2) = undefined
2063------------------------------------------------------------------------------
2041------------------------------------------------------------------------------
2064-- Fold to a Parallel SVar
2042-- Fold to a Parallel SVar