on master help sign in
Move fold compositions from Prelude to Data.Fold
commit27c2dd9ec113b9c6c084cc9a9ac7a28b0ce60e51 authorHarendra Kumar <harendra@composewell.com> dateTue 3 Mar 2020, 18:47 (7 years ago) parenteb71508
2 files changed+240−225
src/Streamly/Internal/Data/Fold.hs+239 src/Streamly/Internal/Prelude.hs+1−225
src/Streamly/Internal/Data/Fold.hs+239
@@ -142,6 +142,25 @@ module Streamly.Internal.Data.Fold
142142 , lsessionsOf
143143 , lchunksOf
144144
145+ -- ** Breaking
146+
147+ -- Binary
148+ , splitAt -- spanN
149+ -- , splitIn -- sessionN
150+
151+ -- By elements
152+ , span -- spanWhile
153+ , break -- breakBefore
154+ -- , breakAfter
155+ -- , breakOn
156+ -- , breakAround
157+ , spanBy
158+ , spanByRolling
159+
160+ -- By sequences
161+ -- , breakOnSeq
162+ -- , breakOnStream -- on a stream
163+
145164 -- * Distributing
146165
147166 , tee
@@ -803,6 +822,226 @@ and = Fold (\x a -> return $ x && a) (return True) return
803822or :: Monad m => Fold m Bool Bool
804823or = Fold (\x a -> return $ x || a) (return False) return
805824
825+------------------------------------------------------------------------------
826+-- Grouping/Splitting
827+------------------------------------------------------------------------------
828+
829+------------------------------------------------------------------------------
830+-- Grouping without looking at elements
831+------------------------------------------------------------------------------
832+--
833+------------------------------------------------------------------------------
834+-- Binary APIs
835+------------------------------------------------------------------------------
836+--
837+
838+-- | @splitAt n f1 f2@ composes folds @f1@ and @f2@ such that first @n@
839+-- elements of its input are consumed by fold @f1@ and the rest of the stream
840+-- is consumed by fold @f2@.
841+--
842+-- > let splitAt_ n xs = S.fold (FL.splitAt n FL.toList FL.toList) $ S.fromList xs
843+--
844+-- >>> splitAt_ 6 "Hello World!"
845+-- > ("Hello ","World!")
846+--
847+-- >>> splitAt_ (-1) [1,2,3]
848+-- > ([],[1,2,3])
849+--
850+-- >>> splitAt_ 0 [1,2,3]
851+-- > ([],[1,2,3])
852+--
853+-- >>> splitAt_ 1 [1,2,3]
854+-- > ([1],[2,3])
855+--
856+-- >>> splitAt_ 3 [1,2,3]
857+-- > ([1,2,3],[])
858+--
859+-- >>> splitAt_ 4 [1,2,3]
860+-- > ([1,2,3],[])
861+--
862+-- /Internal/
863+
864+-- This can be considered as a two-fold version of 'ltake' where we take both
865+-- the segments instead of discarding the leftover.
866+--
867+{-# INLINE splitAt #-}
868+splitAt
869+ :: Monad m
870+ => Int
871+ -> Fold m a b
872+ -> Fold m a c
873+ -> Fold m a (b, c)
874+splitAt n (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
875+ Fold step initial extract
876+ where
877+ initial = Tuple3' <$> return n <*> initialL <*> initialR
878+
879+ step (Tuple3' i xL xR) input =
880+ if i > 0
881+ then stepL xL input >>= (\a -> return (Tuple3' (i - 1) a xR))
882+ else stepR xR input >>= (\b -> return (Tuple3' i xL b))
883+
884+ extract (Tuple3' _ a b) = (,) <$> extractL a <*> extractR b
885+
886+------------------------------------------------------------------------------
887+-- Element Aware APIs
888+------------------------------------------------------------------------------
889+--
890+------------------------------------------------------------------------------
891+-- Binary APIs
892+------------------------------------------------------------------------------
893+
894+-- | Break the input stream into two groups, the first group takes the input as
895+-- long as the predicate applied to the first element of the stream and next
896+-- input element holds 'True', the second group takes the rest of the input.
897+--
898+-- /Internal/
899+--
900+spanBy
901+ :: Monad m
902+ => (a -> a -> Bool)
903+ -> Fold m a b
904+ -> Fold m a c
905+ -> Fold m a (b, c)
906+spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
907+ Fold step initial extract
908+
909+ where
910+ initial = Tuple3' <$> initialL <*> initialR <*> return (Tuple' Nothing True)
911+
912+ step (Tuple3' a b (Tuple' (Just frst) isFirstG)) input =
913+ if cmp frst input && isFirstG
914+ then stepL a input
915+ >>= (\a' -> return (Tuple3' a' b (Tuple' (Just frst) isFirstG)))
916+ else stepR b input
917+ >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
918+
919+ step (Tuple3' a b (Tuple' Nothing isFirstG)) input =
920+ if isFirstG
921+ then stepL a input
922+ >>= (\a' -> return (Tuple3' a' b (Tuple' (Just input) isFirstG)))
923+ else stepR b input
924+ >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
925+
926+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
927+
928+-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
929+-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
930+-- input.
931+--
932+-- > let span_ p xs = S.fold (S.span p FL.toList FL.toList) $ S.fromList xs
933+--
934+-- >>> span_ (< 1) [1,2,3]
935+-- > ([],[1,2,3])
936+--
937+-- >>> span_ (< 2) [1,2,3]
938+-- > ([1],[2,3])
939+--
940+-- >>> span_ (< 4) [1,2,3]
941+-- > ([1,2,3],[])
942+--
943+-- /Internal/
944+
945+-- This can be considered as a two-fold version of 'ltakeWhile' where we take
946+-- both the segments instead of discarding the leftover.
947+{-# INLINE span #-}
948+span
949+ :: Monad m
950+ => (a -> Bool)
951+ -> Fold m a b
952+ -> Fold m a c
953+ -> Fold m a (b, c)
954+span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
955+ Fold step initial extract
956+
957+ where
958+
959+ initial = Tuple3' <$> initialL <*> initialR <*> return True
960+
961+ step (Tuple3' a b isFirstG) input =
962+ if isFirstG && p input
963+ then stepL a input >>= (\a' -> return (Tuple3' a' b True))
964+ else stepR b input >>= (\a' -> return (Tuple3' a a' False))
965+
966+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
967+
968+-- |
969+-- > break p = span (not . p)
970+--
971+-- Break as soon as the predicate becomes 'True'. @break p f1 f2@ composes
972+-- folds @f1@ and @f2@ such that @f1@ stops consuming input as soon as the
973+-- predicate @p@ becomes 'True'. The rest of the input is consumed @f2@.
974+--
975+-- This is the binary version of 'splitBy'.
976+--
977+-- > let break_ p xs = S.fold (S.break p FL.toList FL.toList) $ S.fromList xs
978+--
979+-- >>> break_ (< 1) [3,2,1]
980+-- > ([3,2,1],[])
981+--
982+-- >>> break_ (< 2) [3,2,1]
983+-- > ([3,2],[1])
984+--
985+-- >>> break_ (< 4) [3,2,1]
986+-- > ([],[3,2,1])
987+--
988+-- /Internal/
989+{-# INLINE break #-}
990+break
991+ :: Monad m
992+ => (a -> Bool)
993+ -> Fold m a b
994+ -> Fold m a c
995+ -> Fold m a (b, c)
996+break p = span (not . p)
997+
998+-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
999+-- predicate is applied to the previous and the next input elements.
1000+--
1001+-- /Internal/
1002+{-# INLINE spanByRolling #-}
1003+spanByRolling
1004+ :: Monad m
1005+ => (a -> a -> Bool)
1006+ -> Fold m a b
1007+ -> Fold m a c
1008+ -> Fold m a (b, c)
1009+spanByRolling cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1010+ Fold step initial extract
1011+
1012+ where
1013+ initial = Tuple3' <$> initialL <*> initialR <*> return Nothing
1014+
1015+ step (Tuple3' a b (Just frst)) input =
1016+ if cmp input frst
1017+ then stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1018+ else stepR b input >>= (\b' -> return (Tuple3' a b' (Just input)))
1019+
1020+ step (Tuple3' a b Nothing) input =
1021+ stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
1022+
1023+ extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
1024+
1025+------------------------------------------------------------------------------
1026+-- Binary splitting on a separator
1027+------------------------------------------------------------------------------
1028+
1029+{-
1030+-- | Find the first occurrence of the specified sequence in the input stream
1031+-- and break the input stream into two parts, the first part consisting of the
1032+-- stream before the sequence and the second part consisting of the sequence
1033+-- and the rest of the stream.
1034+--
1035+-- > let breakOn_ pat xs = S.fold (S.breakOn pat FL.toList FL.toList) $ S.fromList xs
1036+--
1037+-- >>> breakOn_ "dear" "Hello dear world!"
1038+-- > ("Hello ","dear world!")
1039+--
1040+{-# INLINE breakOn #-}
1041+breakOn :: Monad m => Array a -> Fold m a b -> Fold m a c -> Fold m a (b,c)
1042+breakOn pat f m = undefined
1043+-}
1044+
8061045------------------------------------------------------------------------------
8071046-- Distributing
8081047------------------------------------------------------------------------------
src/Streamly/Internal/Prelude.hs+1−225
@@ -282,23 +282,6 @@ module Streamly.Internal.Prelude
282282
283283 -- ** Breaking
284284
285− -- Binary
286− , splitAt -- spanN
287− -- , splitIn -- sessionN
288−
289− -- By elements
290− , span -- spanWhile
291− , break -- breakBefore
292− -- , breakAfter
293− -- , breakOn
294− -- , breakAround
295− , spanBy
296− , spanByRolling
297−
298− -- By sequences
299− -- , breakOnSeq
300− -- , breakOnStream -- on a stream
301−
302285 -- Nary
303286 , chunksOf
304287 , chunksOf2
@@ -351,7 +334,7 @@ module Streamly.Internal.Prelude
351334 -- , splitOnAnyPrefixSeq
352335
353336 -- -- *** Splitting By Streams
354− -- | Splitting a stream using another stream as separator.
337+ -- -- | Splitting a stream using another stream as separator.
355338
356339 -- Nested splitting
357340 , splitInnerBy
@@ -3122,54 +3105,6 @@ concatMapTreeYieldLeavesWith combine f = concatMapLoopWith combine f yield
31223105------------------------------------------------------------------------------
31233106--
31243107
3125−-- | @splitAt n f1 f2@ composes folds @f1@ and @f2@ such that first @n@
3126−-- elements of its input are consumed by fold @f1@ and the rest of the stream
3127−-- is consumed by fold @f2@.
3128−--
3129−-- > let splitAt_ n xs = S.fold (FL.splitAt n FL.toList FL.toList) $ S.fromList xs
3130−--
3131−-- >>> splitAt_ 6 "Hello World!"
3132−-- > ("Hello ","World!")
3133−--
3134−-- >>> splitAt_ (-1) [1,2,3]
3135−-- > ([],[1,2,3])
3136−--
3137−-- >>> splitAt_ 0 [1,2,3]
3138−-- > ([],[1,2,3])
3139−--
3140−-- >>> splitAt_ 1 [1,2,3]
3141−-- > ([1],[2,3])
3142−--
3143−-- >>> splitAt_ 3 [1,2,3]
3144−-- > ([1,2,3],[])
3145−--
3146−-- >>> splitAt_ 4 [1,2,3]
3147−-- > ([1,2,3],[])
3148−--
3149−-- /Internal/
3150−
3151−-- This can be considered as a two-fold version of 'ltake' where we take both
3152−-- the segments instead of discarding the leftover.
3153−--
3154−{-# INLINE splitAt #-}
3155−splitAt
3156− :: Monad m
3157− => Int
3158− -> Fold m a b
3159− -> Fold m a c
3160− -> Fold m a (b, c)
3161−splitAt n (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
3162− Fold step initial extract
3163− where
3164− initial = Tuple3' <$> return n <*> initialL <*> initialR
3165−
3166− step (Tuple3' i xL xR) input =
3167− if i > 0
3168− then stepL xL input >>= (\a -> return (Tuple3' (i - 1) a xR))
3169− else stepR xR input >>= (\b -> return (Tuple3' i xL b))
3170−
3171− extract (Tuple3' _ a b) = (,) <$> extractL a <*> extractR b
3172−
31733108------------------------------------------------------------------------------
31743109-- N-ary APIs
31753110------------------------------------------------------------------------------
@@ -3268,145 +3203,6 @@ intervalsOf n f xs =
32683203 splitWithSuffix isNothing (FL.lcatMaybes f)
32693204 (interjectSuffix n (return Nothing) (Serial.map Just xs))
32703205
3271−------------------------------------------------------------------------------
3272−-- Element Aware APIs
3273−------------------------------------------------------------------------------
3274−--
3275−------------------------------------------------------------------------------
3276−-- Binary APIs
3277−------------------------------------------------------------------------------
3278−
3279−-- | Break the input stream into two groups, the first group takes the input as
3280−-- long as the predicate applied to the first element of the stream and next
3281−-- input element holds 'True', the second group takes the rest of the input.
3282−--
3283−-- /Internal/
3284−--
3285−spanBy
3286− :: Monad m
3287− => (a -> a -> Bool)
3288− -> Fold m a b
3289− -> Fold m a c
3290− -> Fold m a (b, c)
3291−spanBy cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
3292− Fold step initial extract
3293−
3294− where
3295− initial = Tuple3' <$> initialL <*> initialR <*> return (Tuple' Nothing True)
3296−
3297− step (Tuple3' a b (Tuple' (Just frst) isFirstG)) input =
3298− if cmp frst input && isFirstG
3299− then stepL a input
3300− >>= (\a' -> return (Tuple3' a' b (Tuple' (Just frst) isFirstG)))
3301− else stepR b input
3302− >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
3303−
3304− step (Tuple3' a b (Tuple' Nothing isFirstG)) input =
3305− if isFirstG
3306− then stepL a input
3307− >>= (\a' -> return (Tuple3' a' b (Tuple' (Just input) isFirstG)))
3308− else stepR b input
3309− >>= (\a' -> return (Tuple3' a a' (Tuple' Nothing False)))
3310−
3311− extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
3312−
3313−-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
3314−-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
3315−-- input.
3316−--
3317−-- > let span_ p xs = S.fold (S.span p FL.toList FL.toList) $ S.fromList xs
3318−--
3319−-- >>> span_ (< 1) [1,2,3]
3320−-- > ([],[1,2,3])
3321−--
3322−-- >>> span_ (< 2) [1,2,3]
3323−-- > ([1],[2,3])
3324−--
3325−-- >>> span_ (< 4) [1,2,3]
3326−-- > ([1,2,3],[])
3327−--
3328−-- /Internal/
3329−
3330−-- This can be considered as a two-fold version of 'ltakeWhile' where we take
3331−-- both the segments instead of discarding the leftover.
3332−{-# INLINE span #-}
3333−span
3334− :: Monad m
3335− => (a -> Bool)
3336− -> Fold m a b
3337− -> Fold m a c
3338− -> Fold m a (b, c)
3339−span p (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
3340− Fold step initial extract
3341−
3342− where
3343−
3344− initial = Tuple3' <$> initialL <*> initialR <*> return True
3345−
3346− step (Tuple3' a b isFirstG) input =
3347− if isFirstG && p input
3348− then stepL a input >>= (\a' -> return (Tuple3' a' b True))
3349− else stepR b input >>= (\a' -> return (Tuple3' a a' False))
3350−
3351− extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
3352−
3353−-- |
3354−-- > break p = span (not . p)
3355−--
3356−-- Break as soon as the predicate becomes 'True'. @break p f1 f2@ composes
3357−-- folds @f1@ and @f2@ such that @f1@ stops consuming input as soon as the
3358−-- predicate @p@ becomes 'True'. The rest of the input is consumed @f2@.
3359−--
3360−-- This is the binary version of 'splitBy'.
3361−--
3362−-- > let break_ p xs = S.fold (S.break p FL.toList FL.toList) $ S.fromList xs
3363−--
3364−-- >>> break_ (< 1) [3,2,1]
3365−-- > ([3,2,1],[])
3366−--
3367−-- >>> break_ (< 2) [3,2,1]
3368−-- > ([3,2],[1])
3369−--
3370−-- >>> break_ (< 4) [3,2,1]
3371−-- > ([],[3,2,1])
3372−--
3373−-- /Internal/
3374−{-# INLINE break #-}
3375−break
3376− :: Monad m
3377− => (a -> Bool)
3378− -> Fold m a b
3379− -> Fold m a c
3380− -> Fold m a (b, c)
3381−break p = span (not . p)
3382−
3383−-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
3384−-- predicate is applied to the previous and the next input elements.
3385−--
3386−-- /Internal/
3387−{-# INLINE spanByRolling #-}
3388−spanByRolling
3389− :: Monad m
3390− => (a -> a -> Bool)
3391− -> Fold m a b
3392− -> Fold m a c
3393− -> Fold m a (b, c)
3394−spanByRolling cmp (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
3395− Fold step initial extract
3396−
3397− where
3398− initial = Tuple3' <$> initialL <*> initialR <*> return Nothing
3399−
3400− step (Tuple3' a b (Just frst)) input =
3401− if cmp input frst
3402− then stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
3403− else stepR b input >>= (\b' -> return (Tuple3' a b' (Just input)))
3404−
3405− step (Tuple3' a b Nothing) input =
3406− stepL a input >>= (\a' -> return (Tuple3' a' b (Just input)))
3407−
3408− extract (Tuple3' a b _) = (,) <$> extractL a <*> extractR b
3409−
34103206------------------------------------------------------------------------------
34113207-- N-ary APIs
34123208------------------------------------------------------------------------------
@@ -3465,26 +3261,6 @@ groupsByRolling cmp f m = D.fromStreamD $ D.groupsRollingBy cmp f (D.toStreamD
34653261groups :: (IsStream t, Monad m, Eq a) => Fold m a b -> t m a -> t m b
34663262groups = groupsBy (==)
34673263
3468−------------------------------------------------------------------------------
3469−-- Binary splitting on a separator
3470−------------------------------------------------------------------------------
3471−
3472−{-
3473−-- | Find the first occurrence of the specified sequence in the input stream
3474−-- and break the input stream into two parts, the first part consisting of the
3475−-- stream before the sequence and the second part consisting of the sequence
3476−-- and the rest of the stream.
3477−--
3478−-- > let breakOn_ pat xs = S.fold (S.breakOn pat FL.toList FL.toList) $ S.fromList xs
3479−--
3480−-- >>> breakOn_ "dear" "Hello dear world!"
3481−-- > ("Hello ","dear world!")
3482−--
3483−{-# INLINE breakOn #-}
3484−breakOn :: Monad m => Array a -> Fold m a b -> Fold m a c -> Fold m a (b,c)
3485−breakOn pat f m = undefined
3486−-}
3487−
34883264------------------------------------------------------------------------------
34893265-- N-ary split on a predicate
34903266------------------------------------------------------------------------------