@@ -110,9 +110,12 @@ module Streamly.Internal.Data.Fold
110110 , map
111111 --, lsequence
112112 , lmapM
113+ , indexed
114+
113115 -- ** Filtering
114116 , filter
115117 , filterM
118+ , sampleFromthen
116119 -- , ldeleteBy
117120 -- , luniq
118121 , lcatMaybes
@@ -209,6 +212,8 @@ module Streamly.Internal.Data.Fold
209212 , intervalsOf
210213 , chunksOf
211214 , chunksBetween
215+ , zipWithM
216+ , zip
212217
213218 , concatSequence
214219 , concatMap
@@ -230,9 +235,11 @@ import Streamly.Internal.Data.Either.Strict
230235import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
231236import Streamly.Internal.Data.Pipe.Types (Pipe (..), PipeState(..))
232237import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
238+import Streamly.Internal.Data.Stream.Serial (SerialT)
233239
234240import qualified Data.Map.Strict as Map
235241import qualified Streamly.Internal.Data.Pipe.Types as Pipe
242+import qualified Streamly.Internal.Data.Stream.IsStream.Enumeration as Stream
236243import qualified Prelude
237244
238245import Prelude hiding
@@ -241,7 +248,7 @@ import Prelude hiding
241248 , notElem, maximum, minimum, head, last, tail, length, null
242249 , reverse, iterate, init, and, or, lookup, (!!)
243250 , scanl, scanl1, replicate, concatMap, mconcat, foldMap, unzip
244− , span, splitAt, break, mapM)
251+ , span, splitAt, break, mapM, zip)
245252import Streamly.Internal.Data.Fold.Types
246253
247254------------------------------------------------------------------------------
@@ -1727,6 +1734,61 @@ unzipWith f = unzipWithM (return . f)
17271734unzip :: Monad m => Fold m a x -> Fold m b y -> Fold m (a,b) (x,y)
17281735unzip = unzipWith id
17291736
1737+------------------------------------------------------------------------------
1738+-- Combining streams and folds - Zipping
1739+------------------------------------------------------------------------------
1740+
1741+-- | Zip a stream with the input of a fold using the supplied function.
1742+--
1743+-- /Unimplemented/
1744+--
1745+{-# INLINE zipWithM #-}
1746+zipWithM :: -- Monad m =>
1747+ (a -> b -> m c) -> t m a -> Fold m c x -> Fold m b x
1748+zipWithM = undefined
1749+
1750+-- | Zip a stream with the input of a fold.
1751+--
1752+-- /Unimplemented/
1753+--
1754+{-# INLINE zip #-}
1755+zip :: Monad m => t m a -> Fold m (a, b) x -> Fold m b x
1756+zip = zipWithM (curry return)
1757+
1758+-- | Pair each element of a fold input with its index, starting from index 0.
1759+--
1760+-- /Unimplemented/
1761+{-# INLINE indexed #-}
1762+indexed :: forall m a b. Monad m => Fold m (Int, a) b -> Fold m a b
1763+indexed = zip (Stream.enumerateFrom 0 :: SerialT m Int)
1764+
1765+-- | Change the predicate function of a Fold from @a -> b@ to accept an
1766+-- additional state input @(s, a) -> b@. Convenient to filter with an
1767+-- addiitonal index or time input.
1768+--
1769+-- @
1770+-- filterWithIndex = with indexed filter
1771+-- filterWithAbsTime = with timestamped filter
1772+-- filterWithRelTime = with timeIndexed filter
1773+-- @
1774+--
1775+-- /Internal/
1776+{-# INLINE with #-}
1777+with ::
1778+ (Fold m (s, a) b -> Fold m a b)
1779+ -> (((s, a) -> c) -> Fold m (s, a) b -> Fold m (s, a) b)
1780+ -> (((s, a) -> c) -> Fold m a b -> Fold m a b)
1781+with f comb g = f . comb g . map snd
1782+
1783+-- | @sampleFromthen offset stride@ samples the element at @offset@ index and
1784+-- then every element at strides of @stride@.
1785+--
1786+-- /Unimplemented/
1787+{-# INLINE sampleFromthen #-}
1788+sampleFromthen :: Monad m => Int -> Int -> Fold m a b -> Fold m a b
1789+sampleFromthen offset size =
1790+ with indexed filter (\(i, _) -> (i + offset) `mod` size == 0)
1791+
17301792------------------------------------------------------------------------------
17311793-- Nesting
17321794------------------------------------------------------------------------------