on master help sign in
Implementation added for grouping, spanning Fold functions (#193)
f310bedACreed
src/Streamly/Fold.hs+74−30
@@ -172,21 +172,18 @@ module Streamly.Fold
172 -}
172 -}
173
173
174 -- * Stream Splitting Operations
174 -- * Stream Splitting Operations
175− {-
176 -- ** Spanning
175 -- ** Spanning
177 -- | Spanning splits the input into two groups and applies two different
176 -- | Spanning splits the input into two groups and applies two different
178 -- folds on each group.
177 -- folds on each group.
179
178
180 -- Element unaware spanning
179 -- Element unaware spanning
181− -- , splitAt
180+ , splitAt
182
181
183 -- Element aware spanning
182 -- Element aware spanning
184 , span
183 , span
185 , break
184 , break
186− , spanBy
185+ -- , spanBy
187− , spanRollingBy
186+ -- , spanRollingBy
188− , spanned
189− -}
190
187
191 -- ** Grouping
188 -- ** Grouping
192 -- | Grouping splits the stream into groups and applies the supplied fold
189 -- | Grouping splits the stream into groups and applies the supplied fold
@@ -212,7 +209,7 @@ module Streamly.Fold
212 -- Element aware grouping
209 -- Element aware grouping
213 , groups
210 , groups
214 , groupsBy
211 , groupsBy
215− -- , groupsRollingBy
212+ , groupsRollingBy
216 , grouped -- XXX experimental
213 , grouped -- XXX experimental
217
214
218 -- ** Splitting by an Element
215 -- ** Splitting by an Element
@@ -952,14 +949,25 @@ ltakeWhile predicate (Fold step initial done) = Fold step' initial' done'
952-- prefix of length @n@ and the second group consisting of the rest of the
949-- prefix of length @n@ and the second group consisting of the rest of the
953-- stream.
950-- stream.
954--
951--
952+-}
953+{-# INLINE splitAt #-}
955splitAt
954splitAt
956 :: Monad m
955 :: Monad m
957 => Int
956 => Int
958 -> Fold m a b
957 -> Fold m a b
959 -> Fold m a c
958 -> Fold m a c
960 -> Fold m a (b, c)
959 -> Fold m a (b, c)
961−splitAt n = undefined
960+splitAt n (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
962−-}
961+ Fold step init extract
962+ where
963+ init = Tuple3' <$> return n <*> initialL <*> initialR
964+
965+ step (Tuple3' i xL xR) input =
966+ if i > 0
967+ then stepL xL input >>= (\a -> return (Tuple3' (i - 1) a xR))
968+ else stepR xR input >>= (\b -> return (Tuple3' i xL b))
969+
970+ extract (Tuple3' _ a b) = (,) <$> extractL a <*> extractR b
963
971
964------------------------------------------------------------------------------
972------------------------------------------------------------------------------
965-- N-ary APIs
973-- N-ary APIs
@@ -1010,45 +1018,64 @@ intervalsOf n f m = grouped (lcatMaybes f) s
1010-- Binary APIs
1018-- Binary APIs
1011------------------------------------------------------------------------------
1019------------------------------------------------------------------------------
1012
1020
1013−{-
1014−-- | Break the input stream of type (a,Bool) into two groups, the first group
1015−-- takes input as long as the boolean is True, the second group takes the rest
1016−-- of the input.
1017−--
1018−-- This is the most general spanning combinator, all others can be implemented
1019−-- in terms of this.
1020−--
1021−spanned
1022− :: Monad m
1023− => Fold m a b
1024− -> Fold m a c
1025− -> Fold m (a, Bool) (b, c)
1026−spanned f m = undefined
1027−
1028-- | Break the input stream into two groups, the first group takes the input as
1021-- | Break the input stream into two groups, the first group takes the input as
1029-- long as the predicate applied to the first element of the stream and next
1022-- long as the predicate applied to the first element of the stream and next
1030-- input element holds 'True', the second group takes the rest of the input.
1023-- input element holds 'True', the second group takes the rest of the input.
1024+--
1025+{-
1031spanBy
1026spanBy
1032 :: Monad m
1027 :: Monad m
1033 => (a -> a -> Bool)
1028 => (a -> a -> Bool)
1034 -> Fold m a b
1029 -> Fold m a b
1035 -> Fold m a c
1030 -> Fold m a c
1036 -> Fold m a (b, c)
1031 -> Fold m a (b, c)
1037−spanBy cmp f1 f2 = undefined
1032+spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1033+ Fold step init extract
1034+
1035+ where
1036+ init = Tuple3' <$> initialL <*> initialR <*> return (Tuple' Nothing True)
1037+
1038+ step (Tuple3' a b (Tuple' (Just frst) isFirstG)) input =
1039+ if cmp frst input && isFirstG
1040+ then stepL a input
1041+ >>= (\a' -> return (Tuple3' a' b (Tuple' (Just frst) isFirstG)))
1042+ else stepR b input
1043+ >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
1044+
1045+ step (Tuple3' a b (Tuple' Nothing isFirstG)) input =
1046+ if isFirstG
1047+ then stepL a input
1048+ >>= (\a' -> return (Tuple3' a' b (Tuple' (Just input) isFirstG)))
1049+ else stepR b input
1050+ >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
1051+
1052+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1053+-}
1038
1054
1039-- |
1055-- |
1040−-- > span p = spanBy (\_ x -> p x)
1041--
1056--
1042-- Break the input stream into two groups, the first group takes the input as
1057-- Break the input stream into two groups, the first group takes the input as
1043-- long as the predicate is 'True', the second group takes the rest of the
1058-- long as the predicate is 'True', the second group takes the rest of the
1044-- input.
1059-- input.
1060+{-# INLINE span #-}
1045span
1061span
1046 :: Monad m
1062 :: Monad m
1047 => (a -> Bool)
1063 => (a -> Bool)
1048 -> Fold m a b
1064 -> Fold m a b
1049 -> Fold m a c
1065 -> Fold m a c
1050 -> Fold m a (b, c)
1066 -> Fold m a (b, c)
1051−span p = spanBy (\_ x -> p x)
1067+span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1068+ Fold step init extract
1069+
1070+ where
1071+ init = Tuple3' <$> initialL <*> initialR <*> return True
1072+
1073+ step (Tuple3' a b isFirstG) input =
1074+ if isFirstG && p input
1075+ then stepL a input >>= (\a' -> return (Tuple3' a' b True))
1076+ else stepR b input >>= (\a' -> return (Tuple3' a a' False))
1077+
1078+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1052
1079
1053-- |
1080-- |
1054-- > break p = span (not . p)
1081-- > break p = span (not . p)
@@ -1056,6 +1083,7 @@ span p = spanBy (\_ x -> p x)
1056-- Break the input stream into two groups, the first group takes the input as
1083-- Break the input stream into two groups, the first group takes the input as
1057-- long as the predicate is 'False', the second group takes the rest of the
1084-- long as the predicate is 'False', the second group takes the rest of the
1058-- input.
1085-- input.
1086+{-# INLINE break #-}
1059break
1087break
1060 :: Monad m
1088 :: Monad m
1061 => (a -> Bool)
1089 => (a -> Bool)
@@ -1064,15 +1092,31 @@ break
1064 -> Fold m a (b, c)
1092 -> Fold m a (b, c)
1065break p = span (not . p)
1093break p = span (not . p)
1066
1094
1095+{-
1067-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1096-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1068-- predicate is applied to the previous and the next input elements.
1097-- predicate is applied to the previous and the next input elements.
1098+{-# INLINE spanRollingBy #-}
1069spanRollingBy
1099spanRollingBy
1070 :: Monad m
1100 :: Monad m
1071 => (a -> a -> Bool)
1101 => (a -> a -> Bool)
1072 -> Fold m a b
1102 -> Fold m a b
1073 -> Fold m a c
1103 -> Fold m a c
1074 -> Fold m a (b, c)
1104 -> Fold m a (b, c)
1075−spanRollingBy cmp f1 f2 = undefined
1105+spanRollingBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1106+ Fold step init extract
1107+
1108+ where
1109+ init = Tuple3' <$> initialL <*> initialR <*> return Nothing
1110+
1111+ step (Tuple3' a b (Just frst)) input =
1112+ if cmp input frst
1113+ then stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1114+ else stepR b input >>= (\b' -> return (Tuple3' a b' (Just input)))
1115+
1116+ step (Tuple3' a b Nothing) input =
1117+ stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1118+
1119+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1076-}
1120-}
1077
1121
1078------------------------------------------------------------------------------
1122------------------------------------------------------------------------------
@@ -1123,14 +1167,14 @@ groupsBy cmp f m = D.fromStreamD $ D.groupsBy cmp f (D.toStreamD m)
1123-- between two successive elements in the stream. The new element is considered
1167-- between two successive elements in the stream. The new element is considered
1124-- part of the current group if the predicate succeeds otherwise a new group
1168-- part of the current group if the predicate succeeds otherwise a new group
1125-- starts.
1169-- starts.
1170+-}
1126groupsRollingBy
1171groupsRollingBy
1127 :: (IsStream t, Monad m)
1172 :: (IsStream t, Monad m)
1128 => (a -> a -> Bool)
1173 => (a -> a -> Bool)
1129 -> Fold m a b
1174 -> Fold m a b
1130 -> t m a
1175 -> t m a
1131 -> t m b
1176 -> t m b
1132−groupsRollingBy cmp f m = undefined
1177+groupsRollingBy cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD m)
1133−-}
1134
1178
1135-- |
1179-- |
1136-- > groups = groupsBy (==)
1180-- > groups = groupsBy (==)
src/Streamly/Streams/StreamD.hs+57
@@ -133,6 +133,7 @@ module Streamly.Streams.StreamD
133 , groupsOf
133 , groupsOf
134 , grouped
134 , grouped
135 , groupsBy
135 , groupsBy
136+ , groupsRollingBy
136
137
137 -- ** Splitting
138 -- ** Splitting
138 , splitBy
139 , splitBy
@@ -1014,6 +1015,62 @@ groupsBy cmp f (Stream step state) = Stream (stepOuter f) (Just state, Nothing)
1014
1015
1015 stepOuter _ _ (Nothing,_) = return Stop
1016 stepOuter _ _ (Nothing,_) = return Stop
1016
1017
1018+{-# INLINE_NORMAL groupsRollingBy #-}
1019+groupsRollingBy :: Monad m
1020+ => (a -> a -> Bool)
1021+ -> Fold m a b
1022+ -> Stream m a
1023+ -> Stream m b
1024+groupsRollingBy cmp f (Stream step state) =
1025+ Stream (stepOuter f) (Just state, Nothing)
1026+ where
1027+
1028+ {-# INLINE_LATE stepOuter #-}
1029+ stepOuter (Fold fstep initial done) gst (Just st, Nothing) = do
1030+ res <- step (adaptState gst) st
1031+ case res of
1032+ Yield x s -> do
1033+ acc <- initial
1034+ acc' <- fstep acc x
1035+ go SPEC x s acc'
1036+
1037+ Skip s -> return $ Skip $ (Just s, Nothing)
1038+ Stop -> return Stop
1039+
1040+ where
1041+ go !_ prev stt !acc = do
1042+ res <- step (adaptState gst) stt
1043+ case res of
1044+ Yield x s -> do
1045+ if cmp x prev
1046+ then do
1047+ acc' <- fstep acc x
1048+ go SPEC x s acc'
1049+ else
1050+ done acc >>= \r -> return $ Yield r (Just s, Just x)
1051+ Skip s -> go SPEC prev s acc
1052+ Stop -> done acc >>= \r -> return $ Yield r (Nothing, Nothing)
1053+
1054+ stepOuter (Fold fstep initial done) gst (Just st, Just prev') = do
1055+ acc <- initial
1056+ acc' <- fstep acc prev'
1057+ go SPEC prev' st acc'
1058+
1059+ where
1060+ go !_ prevv stt !acc = do
1061+ res <- step (adaptState gst) stt
1062+ case res of
1063+ Yield x s -> do
1064+ if cmp x prevv
1065+ then do
1066+ acc' <- fstep acc x
1067+ go SPEC x s acc'
1068+ else done acc >>= \r -> return $ Yield r (Just s, Just x)
1069+ Skip s -> go SPEC prevv s acc
1070+ Stop -> done acc >>= \r -> return $ Yield r (Nothing, Nothing)
1071+
1072+ stepOuter _ _ (Nothing, _) = return Stop
1073+
1017{-# INLINE_EARLY splitSuffixBy' #-}
1074{-# INLINE_EARLY splitSuffixBy' #-}
1018splitSuffixBy' :: Monad m
1075splitSuffixBy' :: Monad m
1019 => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
1076 => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b