@@ -1,4 +1,5 @@
11{-# LANGUAGE UndecidableInstances #-}
2+{-# OPTIONS_GHC -Wno-orphans #-}
23
34-- |
45-- Module : Streamly.Internal.Data.Stream.Serial
@@ -35,13 +36,16 @@ module Streamly.Internal.Data.Stream.Serial
3536 , repeat
3637 , unfoldrM
3738 , fromList
39+ , list
3840
3941 -- * Elimination
4042 , toList
43+ , foldWith
4144
4245 -- * Transformation
4346 , map
4447 , mapM
48+ , filter
4549 , foldFilter
4650 )
4751where
@@ -77,7 +81,7 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Transform as D
7781import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
7882import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
7983
80−import Prelude hiding (map, mapM, repeat)
84+import Prelude hiding (map, mapM, repeat, filter)
8185
8286#include "Instances.hs"
8387#include "inline.hs"
@@ -256,6 +260,14 @@ toStreamD (SerialT m) = D.fromStreamK m
256260fromStreamD :: Monad m => D.Stream m a -> SerialT m a
257261fromStreamD m = SerialT $ D.toStreamK m
258262
263+-- XXX We should only export generation and combinators from this module.
264+--
265+-- | Include only those elements that pass a predicate.
266+--
267+{-# INLINE filter #-}
268+filter :: Monad m => (a -> Bool) -> SerialT m a -> SerialT m a
269+filter p = fromStreamD . D.filter p . toStreamD
270+
259271-- | Use a filtering fold on a stream.
260272--
261273-- > Stream.sum $ Stream.foldFilter (Fold.satisfy (> 5)) $ Stream.fromList [1..10]
@@ -265,6 +277,52 @@ fromStreamD m = SerialT $ D.toStreamK m
265277foldFilter :: Monad m => Fold m a (Maybe b) -> SerialT m a -> SerialT m b
266278foldFilter p = fromStreamD . D.foldFilter p . toStreamD
267279
280+-- XXX Renamed to foldWith because SerialT has a Foldable instance having
281+-- method fold.
282+--
283+-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
284+-- expression strictly at each step. The behavior is similar to 'foldl''. A
285+-- 'Fold' can terminate early without consuming the full stream. See the
286+-- documentation of individual 'Fold's for termination behavior.
287+--
288+-- >>> Stream.foldWith Fold.sum (Stream.enumerateFromTo 1 100)
289+-- 5050
290+--
291+-- Folds never fail, therefore, they produce a default value even when no input
292+-- is provided. It means we can always fold an empty stream and get a valid
293+-- result. For example:
294+--
295+-- >>> Stream.foldWith Fold.sum Stream.nil
296+-- 0
297+--
298+-- However, 'foldMany' on an empty stream results in an empty stream.
299+-- Therefore, @Stream.foldWith f@ is not the same as @Stream.head . Stream.foldMany
300+-- f@.
301+--
302+-- @foldWith f = Stream.parse (Parser.fromFold f)@
303+--
304+-- /Pre-release/
305+{-# INLINE foldWith #-}
306+foldWith :: Monad m => Fold m a b -> SerialT m a -> m b
307+foldWith fld m = D.fold fld $ toStreamD m
308+
309+-- XXX Renamed to "list" because fromList is present in IsList instance.
310+--
311+-- |
312+-- @
313+-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
314+-- @
315+--
316+-- Construct a stream from a list of pure values. This is more efficient than
317+-- 'K.fromFoldable' for serial streams.
318+--
319+-- @since 0.4.0
320+{-# INLINE_EARLY list #-}
321+list :: Monad m => [a] -> SerialT m a
322+list = fromStreamD . D.fromList
323+{-# RULES "list fallback to StreamK" [1]
324+ forall a. D.toStreamK (D.fromList a) = K.fromFoldable a #-}
325+
268326------------------------------------------------------------------------------
269327-- WSerialT
270328------------------------------------------------------------------------------