on master help sign in
Copy combinators from IsStream, absent in the new Stream modules
326b055Adithya Kumar
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+11−1
@@ -40,6 +40,7 @@ module Streamly.Internal.Data.Stream.Eliminate
40 -- the stream one element at a time, and we have the remaining stream all
40 -- the stream one element at a time, and we have the remaining stream all
41 -- the time.
41 -- the time.
42 , uncons
42 , uncons
43+ , init
43
44
44 -- * Right Folds
45 -- * Right Folds
45 , foldrM
46 , foldrM
@@ -87,7 +88,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK as K
87import Streamly.Internal.Data.Stream.Bottom
88import Streamly.Internal.Data.Stream.Bottom
88import Streamly.Internal.Data.Stream.Type
89import Streamly.Internal.Data.Stream.Type
89
90
90−import Prelude hiding (foldr, reverse)
91+import Prelude hiding (foldr, init, reverse)
91
92
92-- $setup
93-- $setup
93-- >>> :m
94-- >>> :m
@@ -132,6 +133,15 @@ import Prelude hiding (foldr, reverse)
132uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
133uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
133uncons m = fmap (fmap (fmap fromStreamK)) $ K.uncons (toStreamK m)
134uncons m = fmap (fmap (fmap fromStreamK)) $ K.uncons (toStreamK m)
134
135
136+-- | Extract all but the last element of the stream, if any.
137+--
138+-- Note: This will end up buffering the entire stream.
139+--
140+-- /Pre-release/
141+{-# INLINE init #-}
142+init :: Monad m => Stream m a -> m (Maybe (Stream m a))
143+init m = fmap (fmap fromStreamK) $ K.init $ toStreamK m
144+
135------------------------------------------------------------------------------
145------------------------------------------------------------------------------
136-- Right Folds
146-- Right Folds
137------------------------------------------------------------------------------
147------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Expand.hs+77−3
@@ -41,6 +41,11 @@ module Streamly.Internal.Data.Stream.Expand
41 , interleave
41 , interleave
42 , interleaveFst
42 , interleaveFst
43 , interleaveMin
43 , interleaveMin
44+ , interleaveFstSuffix2
45+ , interleaveFst2
46+
47+ -- ** Round Robin
48+ , roundrobin
44
49
45 -- ** Merge
50 -- ** Merge
46 , mergeBy
51 , mergeBy
@@ -140,6 +145,7 @@ import Prelude hiding (concat, concatMap, zipWith)
140-- >>> :m
145-- >>> :m
141-- >>> import Data.Either (either)
146-- >>> import Data.Either (either)
142-- >>> import Data.IORef
147-- >>> import Data.IORef
148+-- >>> import Streamly.Internal.Data.Stream (Stream)
143-- >>> import Prelude hiding (zipWith, concatMap, concat)
149-- >>> import Prelude hiding (zipWith, concatMap, concat)
144-- >>> import qualified Streamly.Data.Array.Unboxed as Array
150-- >>> import qualified Streamly.Data.Array.Unboxed as Array
145-- >>> import qualified Streamly.Internal.Data.Fold as Fold
151-- >>> import qualified Streamly.Internal.Data.Fold as Fold
@@ -227,6 +233,74 @@ interleaveMin :: Stream m a -> Stream m a -> Stream m a
227interleaveMin s1 s2 =
233interleaveMin s1 s2 =
228 fromStreamK $ K.interleaveMin (toStreamK s1) (toStreamK s2)
234 fromStreamK $ K.interleaveMin (toStreamK s1) (toStreamK s2)
229
235
236+-- | Interleaves the outputs of two streams, yielding elements from each stream
237+-- alternately, starting from the first stream. As soon as the first stream
238+-- finishes, the output stops, discarding the remaining part of the second
239+-- stream. In this case, the last element in the resulting stream would be from
240+-- the second stream. If the second stream finishes early then the first stream
241+-- still continues to yield elements until it finishes.
242+--
243+-- >>> :set -XOverloadedStrings
244+-- >>> import Data.Functor.Identity (Identity)
245+-- >>> Stream.interleaveFstSuffix2 "abc" ",,,," :: Stream Identity Char
246+-- fromList "a,b,c,"
247+-- >>> Stream.interleaveFstSuffix2 "abc" "," :: Stream Identity Char
248+-- fromList "a,bc"
249+--
250+-- 'interleaveFstSuffix2' is a dual of 'interleaveFst2'.
251+--
252+-- Do not use at scale in concatMapWith.
253+--
254+-- /Pre-release/
255+{-# INLINE interleaveFstSuffix2 #-}
256+interleaveFstSuffix2 :: Monad m => Stream m b -> Stream m b -> Stream m b
257+interleaveFstSuffix2 m1 m2 =
258+ fromStreamD $ D.interleaveSuffix (toStreamD m1) (toStreamD m2)
259+
260+-- | Interleaves the outputs of two streams, yielding elements from each stream
261+-- alternately, starting from the first stream and ending at the first stream.
262+-- If the second stream is longer than the first, elements from the second
263+-- stream are infixed with elements from the first stream. If the first stream
264+-- is longer then it continues yielding elements even after the second stream
265+-- has finished.
266+--
267+-- >>> :set -XOverloadedStrings
268+-- >>> import Data.Functor.Identity (Identity)
269+-- >>> Stream.interleaveFst2 "abc" ",,,," :: Stream Identity Char
270+-- fromList "a,b,c"
271+-- >>> Stream.interleaveFst2 "abc" "," :: Stream Identity Char
272+-- fromList "a,bc"
273+--
274+-- 'interleaveFst2' is a dual of 'interleaveFstSuffix2'.
275+--
276+-- Do not use at scale in concatMapWith.
277+--
278+-- /Pre-release/
279+{-# INLINE interleaveFst2 #-}
280+interleaveFst2 :: Monad m => Stream m b -> Stream m b -> Stream m b
281+interleaveFst2 m1 m2 =
282+ fromStreamD $ D.interleaveInfix (toStreamD m1) (toStreamD m2)
283+
284+------------------------------------------------------------------------------
285+-- Scheduling
286+------------------------------------------------------------------------------
287+
288+-- | Schedule the execution of two streams in a fair round-robin manner,
289+-- executing each stream once, alternately. Execution of a stream may not
290+-- necessarily result in an output, a stream may chose to @Skip@ producing an
291+-- element until later giving the other stream a chance to run. Therefore, this
292+-- combinator fairly interleaves the execution of two streams rather than
293+-- fairly interleaving the output of the two streams. This can be useful in
294+-- co-operative multitasking without using explicit threads. This can be used
295+-- as an alternative to `async`.
296+--
297+-- Do not use at scale in concatMapWith.
298+--
299+-- /Pre-release/
300+{-# INLINE roundrobin #-}
301+roundrobin :: Monad m => Stream m b -> Stream m b -> Stream m b
302+roundrobin m1 m2 = fromStreamD $ D.roundRobin (toStreamD m1) (toStreamD m2)
303+
230------------------------------------------------------------------------------
304------------------------------------------------------------------------------
231-- Merging (sorted streams)
305-- Merging (sorted streams)
232------------------------------------------------------------------------------
306------------------------------------------------------------------------------
@@ -361,7 +435,7 @@ unfoldInterleave u m =
361{-# INLINE unfoldRoundRobin #-}
435{-# INLINE unfoldRoundRobin #-}
362unfoldRoundRobin ::Monad m => Unfold m a b -> Stream m a -> Stream m b
436unfoldRoundRobin ::Monad m => Unfold m a b -> Stream m a -> Stream m b
363unfoldRoundRobin u m =
437unfoldRoundRobin u m =
364− fromStreamD $ D.unfoldManyInterleave u (toStreamD m)
438+ fromStreamD $ D.unfoldManyRoundRobin u (toStreamD m)
365
439
366------------------------------------------------------------------------------
440------------------------------------------------------------------------------
367-- Combine N Streams - interpose
441-- Combine N Streams - interpose
@@ -407,7 +481,7 @@ interposeSuffix x unf str =
407-- > unfoldMany unf str =
481-- > unfoldMany unf str =
408-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
482-- > gintercalate unf str (UF.nilM (\_ -> return ())) (repeat ())
409
483
410−-- | 'interleaveInfix' followed by unfold and concat.
484+-- | 'interleaveFst' followed by unfold and concat.
411--
485--
412-- /Pre-release/
486-- /Pre-release/
413{-# INLINE gintercalate #-}
487{-# INLINE gintercalate #-}
@@ -438,7 +512,7 @@ intercalate :: Monad m
438intercalate unf seed str = fromStreamD $
512intercalate unf seed str = fromStreamD $
439 D.unfoldMany unf $ D.intersperse seed (toStreamD str)
513 D.unfoldMany unf $ D.intersperse seed (toStreamD str)
440
514
441−-- | 'interleaveSuffix' followed by unfold and concat.
515+-- | 'interleaveFstSuffix2' followed by unfold and concat.
442--
516--
443-- /Pre-release/
517-- /Pre-release/
444{-# INLINE gintercalateSuffix #-}
518{-# INLINE gintercalateSuffix #-}
core/src/Streamly/Internal/Data/Stream/Reduce.hs+113
@@ -38,6 +38,12 @@ module Streamly.Internal.Data.Stream.Reduce
38 -- | Element unaware grouping.
38 -- | Element unaware grouping.
39 , arraysOf
39 , arraysOf
40
40
41+ -- ** Splitting
42+ -- XXX Implement these as folds or parsers instead.
43+ , splitOnSuffixSeqAny
44+ , splitOnPrefix
45+ , splitOnAny
46+
41 -- * Reduce By Parsers
47 -- * Reduce By Parsers
42 -- ** Generic Parsing
48 -- ** Generic Parsing
43 -- | Apply parsers on a stream.
49 -- | Apply parsers on a stream.
@@ -204,6 +210,113 @@ refoldIterateM :: Monad m =>
204 Refold m b a b -> m b -> Stream m a -> Stream m b
210 Refold m b a b -> m b -> Stream m a -> Stream m b
205refoldIterateM c i m = fromStreamD $ D.refoldIterateM c i (toStreamD m)
211refoldIterateM c i m = fromStreamD $ D.refoldIterateM c i (toStreamD m)
206
212
213+------------------------------------------------------------------------------
214+-- Splitting
215+------------------------------------------------------------------------------
216+
217+-- Implement this as a fold or a parser instead.
218+-- This can be implemented easily using Rabin Karp
219+-- | Split post any one of the given patterns.
220+--
221+-- /Unimplemented/
222+{-# INLINE splitOnSuffixSeqAny #-}
223+splitOnSuffixSeqAny :: -- (Monad m, Unboxed a, Integral a) =>
224+ [Array a] -> Fold m a b -> Stream m a -> Stream m b
225+splitOnSuffixSeqAny _subseq _f _m = undefined
226+ -- D.fromStreamD $ D.splitPostAny f subseq (D.toStreamD m)
227+
228+-- | Split on a prefixed separator element, dropping the separator. The
229+-- supplied 'Fold' is applied on the split segments.
230+--
231+-- @
232+-- > splitOnPrefix' p xs = Stream.toList $ Stream.splitOnPrefix p (Fold.toList) (Stream.fromList xs)
233+-- > splitOnPrefix' (== '.') ".a.b"
234+-- ["a","b"]
235+-- @
236+--
237+-- An empty stream results in an empty output stream:
238+-- @
239+-- > splitOnPrefix' (== '.') ""
240+-- []
241+-- @
242+--
243+-- An empty segment consisting of only a prefix is folded to the default output
244+-- of the fold:
245+--
246+-- @
247+-- > splitOnPrefix' (== '.') "."
248+-- [""]
249+--
250+-- > splitOnPrefix' (== '.') ".a.b."
251+-- ["a","b",""]
252+--
253+-- > splitOnPrefix' (== '.') ".a..b"
254+-- ["a","","b"]
255+--
256+-- @
257+--
258+-- A prefix is optional at the beginning of the stream:
259+--
260+-- @
261+-- > splitOnPrefix' (== '.') "a"
262+-- ["a"]
263+--
264+-- > splitOnPrefix' (== '.') "a.b"
265+-- ["a","b"]
266+-- @
267+--
268+-- 'splitOnPrefix' is an inverse of 'intercalatePrefix' with a single element:
269+--
270+-- > Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList . Stream.splitOnPrefix (== '.') Fold.toList === id
271+--
272+-- Assuming the input stream does not contain the separator:
273+--
274+-- > Stream.splitOnPrefix (== '.') Fold.toList . Stream.intercalatePrefix (Stream.fromPure '.') Unfold.fromList === id
275+--
276+-- /Unimplemented/
277+{-# INLINE splitOnPrefix #-}
278+splitOnPrefix :: -- (IsStream t, MonadCatch m) =>
279+ (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
280+splitOnPrefix _predicate _f = undefined
281+ -- parseMany (Parser.sliceBeginBy predicate f)
282+
283+-- Int list examples for splitOn:
284+--
285+-- >>> splitList [] [1,2,3,3,4]
286+-- > [[1],[2],[3],[3],[4]]
287+--
288+-- >>> splitList [5] [1,2,3,3,4]
289+-- > [[1,2,3,3,4]]
290+--
291+-- >>> splitList [1] [1,2,3,3,4]
292+-- > [[],[2,3,3,4]]
293+--
294+-- >>> splitList [4] [1,2,3,3,4]
295+-- > [[1,2,3,3],[]]
296+--
297+-- >>> splitList [2] [1,2,3,3,4]
298+-- > [[1],[3,3,4]]
299+--
300+-- >>> splitList [3] [1,2,3,3,4]
301+-- > [[1,2],[],[4]]
302+--
303+-- >>> splitList [3,3] [1,2,3,3,4]
304+-- > [[1,2],[4]]
305+--
306+-- >>> splitList [1,2,3,3,4] [1,2,3,3,4]
307+-- > [[],[]]
308+
309+-- This can be implemented easily using Rabin Karp
310+-- | Split on any one of the given patterns.
311+--
312+-- /Unimplemented/
313+--
314+{-# INLINE splitOnAny #-}
315+splitOnAny :: -- (Monad m, Unboxed a, Integral a) =>
316+ [Array a] -> Fold m a b -> Stream m a -> Stream m b
317+splitOnAny _subseq _f _m =
318+ undefined -- D.fromStreamD $ D.splitOnAny f subseq (D.toStreamD m)
319+
207------------------------------------------------------------------------------
320------------------------------------------------------------------------------
208-- Parsing
321-- Parsing
209------------------------------------------------------------------------------
322------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Transform.hs+57−2
@@ -63,9 +63,14 @@ module Streamly.Internal.Data.Stream.Transform
63 , take
63 , take
64 , takeWhile
64 , takeWhile
65 , takeWhileM
65 , takeWhileM
66+ , takeWhileLast
67+ , takeWhileAround
66 , drop
68 , drop
69+ , dropLast
67 , dropWhile
70 , dropWhile
68 , dropWhileM
71 , dropWhileM
72+ , dropWhileLast
73+ , dropWhileAround
69
74
70 -- * Position Indexing
75 -- * Position Indexing
71 , indexed
76 , indexed
@@ -512,8 +517,6 @@ filterM p m = fromStreamD $ D.filterM p $ toStreamD m
512--
517--
513-- Space: @O(1)@
518-- Space: @O(1)@
514--
519--
515−-- See also: 'nubBy'.
516−--
517-- /Pre-release/
520-- /Pre-release/
518--
521--
519{-# INLINE uniqBy #-}
522{-# INLINE uniqBy #-}
@@ -598,6 +601,27 @@ takeWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
598-- takeWhileM p = scanMaybe (FL.takingEndByM_ (\x -> not <$> p x))
601-- takeWhileM p = scanMaybe (FL.takingEndByM_ (\x -> not <$> p x))
599takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
602takeWhileM p m = fromStreamD $ D.takeWhileM p $ toStreamD m
600
603
604+-- | Take all consecutive elements at the end of the stream for which the
605+-- predicate is true.
606+--
607+-- O(n) space, where n is the number elements taken.
608+--
609+-- /Unimplemented/
610+{-# INLINE takeWhileLast #-}
611+takeWhileLast :: -- Monad m =>
612+ (a -> Bool) -> Stream m a -> Stream m a
613+takeWhileLast = undefined -- fromStreamD $ D.takeWhileLast n $ toStreamD m
614+
615+-- | Like 'takeWhile' and 'takeWhileLast' combined.
616+--
617+-- O(n) space, where n is the number elements taken from the end.
618+--
619+-- /Unimplemented/
620+{-# INLINE takeWhileAround #-}
621+takeWhileAround :: -- Monad m =>
622+ (a -> Bool) -> Stream m a -> Stream m a
623+takeWhileAround = undefined -- fromStreamD $ D.takeWhileAround n $ toStreamD m
624+
601-- | Drop elements in the stream as long as the predicate succeeds and then
625-- | Drop elements in the stream as long as the predicate succeeds and then
602-- take the rest of the stream.
626-- take the rest of the stream.
603--
627--
@@ -615,6 +639,37 @@ dropWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
615-- dropWhileM p = scanMaybe (FL.droppingWhileM p)
639-- dropWhileM p = scanMaybe (FL.droppingWhileM p)
616dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
640dropWhileM p m = fromStreamD $ D.dropWhileM p $ toStreamD m
617
641
642+-- | Drop @n@ elements at the end of the stream.
643+--
644+-- O(n) space, where n is the number elements dropped.
645+--
646+-- /Unimplemented/
647+{-# INLINE dropLast #-}
648+dropLast :: -- Monad m =>
649+ Int -> Stream m a -> Stream m a
650+dropLast = undefined -- fromStreamD $ D.dropLast n $ toStreamD m
651+
652+-- | Drop all consecutive elements at the end of the stream for which the
653+-- predicate is true.
654+--
655+-- O(n) space, where n is the number elements dropped.
656+--
657+-- /Unimplemented/
658+{-# INLINE dropWhileLast #-}
659+dropWhileLast :: -- Monad m =>
660+ (a -> Bool) -> Stream m a -> Stream m a
661+dropWhileLast = undefined -- fromStreamD $ D.dropWhileLast n $ toStreamD m
662+
663+-- | Like 'dropWhile' and 'dropWhileLast' combined.
664+--
665+-- O(n) space, where n is the number elements dropped from the end.
666+--
667+-- /Unimplemented/
668+{-# INLINE dropWhileAround #-}
669+dropWhileAround :: -- Monad m =>
670+ (a -> Bool) -> Stream m a -> Stream m a
671+dropWhileAround = undefined -- fromStreamD $ D.dropWhileAround n $ toStreamD m
672+
618------------------------------------------------------------------------------
673------------------------------------------------------------------------------
619-- Inserting Elements
674-- Inserting Elements
620------------------------------------------------------------------------------
675------------------------------------------------------------------------------
src/Streamly/Internal/Data/Stream/Time.hs+90
@@ -11,8 +11,11 @@ module Streamly.Internal.Data.Stream.Time
11 (
11 (
12 -- Primitives
12 -- Primitives
13 interjectSuffix
13 interjectSuffix
14+ , ticks
14 , takeInterval
15 , takeInterval
16+ , takeLastInterval
15 , dropInterval
17 , dropInterval
18+ , dropLastInterval
16 , intervalsOf
19 , intervalsOf
17 , chunksOfTimeout
20 , chunksOfTimeout
18
21
@@ -22,6 +25,15 @@ module Streamly.Internal.Data.Stream.Time
22 , classifySessionsOf
25 , classifySessionsOf
23 , classifyKeepAliveSessions
26 , classifyKeepAliveSessions
24
27
28+ -- ** Buffering and Sampling
29+ -- | Evaluate strictly using a buffer of results. When the buffer becomes
30+ -- full we can block, drop the new elements, drop the oldest element and
31+ -- insert the new at the end or keep dropping elements uniformly to match
32+ -- the rate of the consumer.
33+ , sampleOld
34+ , sampleNew
35+ , sampleRate
36+
25 -- Sampling
37 -- Sampling
26 , sampleIntervalEnd
38 , sampleIntervalEnd
27 , sampleIntervalStart
39 , sampleIntervalStart
@@ -108,6 +120,19 @@ interjectSuffix n f xs = parallelFst [xs, repeatM timed]
108 timed = liftIO (threadDelay (round $ n * 1000000)) >> f
120 timed = liftIO (threadDelay (round $ n * 1000000)) >> f
109 repeatM = Stream.sequence . Stream.repeat
121 repeatM = Stream.sequence . Stream.repeat
110
122
123+-- | Generate ticks at the specified rate. The rate is adaptive, the tick
124+-- generation speed can be increased or decreased at different times to achieve
125+-- the specified rate. The specific behavior for different styles of 'Rate'
126+-- specifications is documented under 'Rate'. The effective maximum rate
127+-- achieved by a stream is governed by the processor speed.
128+--
129+-- /Unimplemented/
130+--
131+{-# INLINE ticks #-}
132+ticks :: -- (MonadAsync m) =>
133+ Rate -> Stream m ()
134+ticks = undefined
135+
111-- XXX Notes from D.takeByTime (which was removed)
136-- XXX Notes from D.takeByTime (which was removed)
112-- XXX using getTime in the loop can be pretty expensive especially for
137-- XXX using getTime in the loop can be pretty expensive especially for
113-- computations where iterations are lightweight. We have the following
138-- computations where iterations are lightweight. We have the following
@@ -146,6 +171,16 @@ takeInterval d =
146 . Stream.takeWhile isNothing
171 . Stream.takeWhile isNothing
147 . interjectSuffix d (return Nothing) . fmap Just
172 . interjectSuffix d (return Nothing) . fmap Just
148
173
174+-- | Take time interval @i@ seconds at the end of the stream.
175+--
176+-- O(n) space, where n is the number elements taken.
177+--
178+-- /Unimplemented/
179+{-# INLINE takeLastInterval #-}
180+takeLastInterval :: -- MonadAsync m =>
181+ Double -> Stream m a -> Stream m a
182+takeLastInterval = undefined
183+
149-- | @dropInterval duration@ drops stream elements until specified @duration@ in
184-- | @dropInterval duration@ drops stream elements until specified @duration@ in
150-- seconds has passed. The duration begins when the stream is evaluated for the
185-- seconds has passed. The duration begins when the stream is evaluated for the
151-- first time. The time duration is checked /after/ generating a stream element,
186-- first time. The time duration is checked /after/ generating a stream element,
@@ -167,6 +202,16 @@ dropInterval d =
167 . Stream.dropWhile isNothing
202 . Stream.dropWhile isNothing
168 . interjectSuffix d (return Nothing) . fmap Just
203 . interjectSuffix d (return Nothing) . fmap Just
169
204
205+-- | Drop time interval @i@ seconds at the end of the stream.
206+--
207+-- O(n) space, where n is the number elements dropped.
208+--
209+-- /Unimplemented/
210+{-# INLINE dropLastInterval #-}
211+dropLastInterval :: -- MonadAsync m =>
212+ Int -> Stream m a -> Stream m a
213+dropLastInterval = undefined
214+
170-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
215-- XXX we can implement this by repeatedly applying the 'lrunFor' fold.
171-- XXX add this example after fixing the serial stream rate control
216-- XXX add this example after fixing the serial stream rate control
172--
217--
@@ -860,3 +905,48 @@ sampleBurstEnd = sampleBurst True
860{-# INLINE sampleBurstStart #-}
905{-# INLINE sampleBurstStart #-}
861sampleBurstStart :: MonadAsync m => Double -> Stream m a -> Stream m a
906sampleBurstStart :: MonadAsync m => Double -> Stream m a -> Stream m a
862sampleBurstStart = sampleBurst False
907sampleBurstStart = sampleBurst False
908+
909+------------------------------------------------------------------------------
910+-- Lossy Buffering
911+------------------------------------------------------------------------------
912+
913+-- XXX We could use 'maxBuffer Block/Drop/Rotate/Sample' instead. However we
914+-- may want to have the evaluation rate independent of the sampling rate. To
915+-- support that we can decouple evaluation and sampling in independent stages.
916+-- The sampling stage would strictly evaluate and sample, the evaluation stage
917+-- would control the evaluation rate.
918+
919+-- | Evaluate the input stream continuously and keep only the oldest @n@
920+-- elements in the buffer, discard the new ones when the buffer is full. When
921+-- the output stream is evaluated it consumes the values from the buffer in a
922+-- FIFO manner.
923+--
924+-- /Unimplemented/
925+--
926+{-# INLINE sampleOld #-}
927+sampleOld :: -- MonadAsync m =>
928+ Int -> Stream m a -> Stream m a
929+sampleOld = undefined
930+
931+-- | Evaluate the input stream continuously and keep only the latest @n@
932+-- elements in a ring buffer, keep discarding the older ones to make space for
933+-- the new ones. When the output stream is evaluated it consumes the values
934+-- from the buffer in a FIFO manner.
935+--
936+-- /Unimplemented/
937+--
938+{-# INLINE sampleNew #-}
939+sampleNew :: -- MonadAsync m =>
940+ Int -> Stream m a -> Stream m a
941+sampleNew = undefined
942+
943+-- | Like 'sampleNew' but samples at uniform intervals to match the consumer
944+-- rate. Note that 'sampleNew' leads to non-uniform sampling depending on the
945+-- consumer pattern.
946+--
947+-- /Unimplemented/
948+--
949+{-# INLINE sampleRate #-}
950+sampleRate :: -- MonadAsync m =>
951+ Double -> Stream m a -> Stream m a
952+sampleRate = undefined