on master help sign in
Fix documentation in the Stream modules

Add the unfold operation in Generation module.

commit4608fad86108b4eed7357fc7abba209d32dad722 authorHarendra Kumar <harendra@composewell.com> dateThu 2 Jun 2022, 23:52 (4 years ago) parent1872958
4 files changed+83−73
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+9−4 core/src/Streamly/Internal/Data/Stream/Generate.hs+43−22 core/src/Streamly/Internal/Data/Stream/Transform.hs+14−32 core/src/Streamly/Internal/Data/Stream/Type.hs+17−15
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+9−4
@@ -18,23 +18,28 @@ import Streamly.Internal.Data.Stream.Type (Stream)
1818import qualified Streamly.Internal.Data.Stream.Type as Stream
1919import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
2020
21+-- $setup
22+-- >>> import qualified Streamly.Data.Fold as Fold
23+-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
24+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
25+
2126-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
2227-- expression strictly at each step. The behavior is similar to 'foldl''. A
2328-- 'Fold' can terminate early without consuming the full stream. See the
2429-- documentation of individual 'Fold's for termination behavior.
2530--
26−-- >>> Stream.foldWith Fold.sum (Stream.enumerateFromTo 1 100)
31+-- >>> Stream.fold Fold.sum (Stream.unfold Unfold.enumerateFromTo (1,100))
2732-- 5050
2833--
2934-- Folds never fail, therefore, they produce a default value even when no input
3035-- is provided. It means we can always fold an empty stream and get a valid
3136-- result. For example:
3237--
33−-- >>> Stream.fold Fold.sum Stream.nil
34−-- 0
38+-- >> Stream.fold Fold.sum Stream.nil
39+-- >0
3540--
3641-- However, 'foldMany' on an empty stream results in an empty stream.
37−-- Therefore, @Stream.foldWith f@ is not the same as @Stream.head . Stream.foldMany
42+-- Therefore, @Stream.fold f@ is not the same as @Stream.head . Stream.foldMany
3843-- f@.
3944--
4045-- @fold f = Stream.parse (Parser.fromFold f)@
core/src/Streamly/Internal/Data/Stream/Generate.hs+43−22
@@ -10,6 +10,7 @@ module Streamly.Internal.Data.Stream.Generate
1010 (
1111 cons
1212 , consM
13+ , unfold
1314 , append
1415 )
1516where
@@ -21,27 +22,30 @@ import Data.Semigroup (Semigroup(..))
2122import Data.Semigroup (Semigroup(..))
2223#endif
2324import Streamly.Internal.Data.Stream.Type (Stream)
25+import Streamly.Internal.Data.Unfold (Unfold)
2426
2527import qualified Streamly.Internal.Data.Stream.Type as Stream
28+import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
2629import qualified Streamly.Internal.Data.Stream.StreamK.Type as StreamK
2730
2831-- $setup
2932-- >>> :m
30−-- >>> import Control.Concurrent (threadDelay)
31−-- >>> import Data.IORef
32−-- >>> import Prelude hiding (zipWith, concatMap, concat)
33+-- >>> import qualified Streamly.Data.Fold as Fold
34+-- >>> import qualified Streamly.Data.Unfold as Unfold
3335-- >>> import qualified Streamly.Internal.Data.Stream as Stream
34−--
36+
37+infixr 5 `cons`
3538
3639-- | Construct a stream by adding a pure value at the head of an existing
37−-- stream. This is the same as @(return a) \`consM` r@ but
38−-- more efficient. For concurrent streams this is not concurrent whereas
39−-- 'consM' is concurrent. For example:
40+-- stream. Same as the following but more efficient:
41+--
42+-- For example:
4043--
41−-- @
42−-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
43−-- [1,2,3]
44−-- @
44+-- >> s = 1 `Stream.cons` 2 `Stream.cons` 3 `Stream.cons` Stream.nil
45+-- >> Stream.fold Fold.toList s
46+-- >[1,2,3]
47+--
48+-- >>> cons x xs = return x `Stream.consM` xs
4549--
4650-- /Pre-release/
4751--
@@ -49,17 +53,16 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as StreamK
4953cons :: a -> Stream m a -> Stream m a
5054cons x = Stream.fromStreamK . StreamK.cons x . Stream.toStreamK
5155
56+infixr 5 `consM`
57+
5258-- | Constructs a stream by adding a monadic action at the head of an
5359-- existing stream. For example:
5460--
55−-- @
56−-- > toList $ getLine \`consM` getLine \`consM` nil
57−-- hello
58−-- world
59−-- ["hello","world"]
60−-- @
61+-- >> s = putChar 'h' `Stream.consM` putChar 'i' `Stream.consM` Stream.nil
62+-- >> Stream.fold Fold.toList s
63+-- >hi
6164--
62−-- > consM x xs = fromEffect x `append` xs
65+-- >> consM x xs = Stream.fromEffect x `Stream.append` xs
6366--
6467-- /Pre-release/
6568--
@@ -68,17 +71,35 @@ cons x = Stream.fromStreamK . StreamK.cons x . Stream.toStreamK
6871consM :: Monad m => m a -> Stream m a -> Stream m a
6972consM m = Stream.fromStreamK . StreamK.consM m . Stream.toStreamK
7073
74+------------------------------------------------------------------------------
75+-- From Unfold
76+------------------------------------------------------------------------------
77+
78+-- | Convert an 'Unfold' into a stream by supplying it an input seed.
79+--
80+-- >>> s = Stream.unfold (Unfold.replicateM 3) (putStrLn "hello")
81+-- >>> Stream.fold Fold.drain s
82+-- hello
83+-- hello
84+-- hello
85+--
86+-- /Pre-release/
87+{-# INLINE unfold #-}
88+unfold :: Monad m => Unfold m a b -> a -> Stream m b
89+unfold unf = Stream.fromStreamD . StreamD.unfold unf
90+
7191------------------------------------------------------------------------------
7292-- Combining
7393------------------------------------------------------------------------------
7494
95+infixr 6 `append`
96+
7597-- | Appends two streams sequentially, yielding all elements from the first
7698-- stream, and then all elements from the second stream.
7799--
78−-- >>> import Streamly.Internal.Data.Stream (append)
79−-- >>> stream1 = Stream.fromList [1,2]
80−-- >>> stream2 = Stream.fromList [3,4]
81−-- >>> Stream.toList $ stream1 `append` stream2
100+-- >>> s1 = Stream.unfold Unfold.fromList [1,2]
101+-- >>> s2 = Stream.unfold Unfold.fromList [3,4]
102+-- >>> Stream.fold Fold.toList $ s1 `Stream.append` s2
82103-- [1,2,3,4]
83104--
84105-- This operation can be used to fold an infinite lazy container of streams.
core/src/Streamly/Internal/Data/Stream/Transform.hs+14−32
@@ -26,43 +26,24 @@ import Prelude hiding (map, mapM, filter)
2626--
2727-- $setup
2828-- >>> :m
29−-- >>> import Streamly.Internal.Data.Stream as Stream
30−-- >>> import qualified Streamly.Data.Fold as Fold
3129-- >>> import qualified Streamly.Internal.Data.Fold as Fold
32−-- >>> import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
33−--
34−-- >>> hSetBuffering stdout LineBuffering
30+-- >>> import qualified Streamly.Data.Unfold as Unfold
31+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
3532
3633------------------------------------------------------------------------------
3734-- Transformation by Mapping
3835------------------------------------------------------------------------------
3936
4037-- |
41−-- @
42−-- mapM f = sequence . map f
43−-- @
38+-- >> mapM f = Stream.sequence . Stream.map f
4439--
4540-- Apply a monadic function to each element of the stream and replace it with
4641-- the output of the resulting action.
4742--
48−-- @
49−-- > drain $ Stream.mapM putStr $ Stream.fromList ["a", "b", "c"]
43+-- >>> s = Stream.unfold Unfold.fromList ["a", "b", "c"]
44+-- >>> Stream.fold Fold.drain $ Stream.mapM putStr s
5045-- abc
5146--
52−-- > :{
53−-- drain $ Stream.replicateM 10 (return 1)
54−-- & (fromSerial . Stream.mapM (\x -> threadDelay 1000000 >> print x))
55−-- :}
56−-- 1
57−-- ...
58−-- 1
59−--
60−-- > drain $ Stream.replicateM 10 (return 1)
61−-- & (fromAsync . Stream.mapM (\x -> threadDelay 1000000 >> print x))
62−-- @
63−--
64−-- /Concurrent (do not use with 'fromParallel' on infinite streams)/
65−--
6647-- /Pre-release/
6748--
6849{-# INLINE mapM #-}
@@ -70,16 +51,13 @@ mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
7051mapM f = Stream.fromStreamD . StreamD.mapM f . Stream.toStreamD
7152
7253-- |
73−-- @
74−-- map = fmap
75−-- @
54+-- >>> map = fmap
7655--
7756-- Same as 'fmap'.
7857--
79−-- @
80−-- > S.toList $ S.map (+1) $ S.fromList [1,2,3]
58+-- >>> s = Stream.unfold Unfold.fromList [1,2,3]
59+-- >>> Stream.fold Fold.toList $ Stream.map (+1) s
8160-- [2,3,4]
82−-- @
8361--
8462-- /Pre-release/
8563--
@@ -95,8 +73,12 @@ filter p = Stream.fromStreamD . StreamD.filter p . Stream.toStreamD
9573
9674-- | Use a filtering fold on a stream.
9775--
98−-- > Stream.sum $ Stream.foldFilter (Fold.satisfy (> 5)) $ Stream.fromList [1..10]
99−-- 40
76+-- >>> :{
77+-- Stream.fold Fold.sum
78+-- $ Stream.foldFilter (Fold.maybe (\x -> if x > 5 then Just x else Nothing))
79+-- $ Stream.unfold Unfold.fromList [1..10]
80+-- :}
81+--40
10082--
10183-- /Pre-release/
10284--
core/src/Streamly/Internal/Data/Stream/Type.hs+17−15
@@ -48,24 +48,28 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
4848#include "inline.hs"
4949
5050-- $setup
51−-- >>> import qualified Streamly.Prelude as Stream
51+-- >>> import qualified Streamly.Data.Fold as Fold
52+-- >>> import qualified Streamly.Data.Unfold as Unfold
53+-- >>> import qualified Streamly.Internal.Data.Stream as Stream
5254
5355------------------------------------------------------------------------------
5456-- Stream
5557------------------------------------------------------------------------------
5658
57−-- | For 'Stream' streams:
59+-- | Semigroup instance appends two streams:
5860--
59−-- @
60−-- (<>) = 'Streamly.Prelude.serial' -- 'Semigroup'
61−-- (>>=) = flip . 'Streamly.Prelude.concatMapWith' 'Streamly.Prelude.serial' -- 'Monad'
62−-- @
61+-- > (<>) = Stream.append
6362--
64−-- A single 'Monad' bind behaves like a @for@ loop:
63+-- Monad bind maps a stream generator function on the stream and flattens the
64+-- resulting stream:
65+--
66+-- > (>>=) = flip . Stream.concatMapWith Stream.append
67+--
68+-- A 'Monad' bind behaves like a @for@ loop:
6569--
6670-- >>> :{
67−-- Stream.toList $ do
68−-- x <- Stream.fromList [1,2] -- foreach x in stream
71+-- Stream.fold Fold.toList $ do
72+-- x <- Stream.unfold Unfold.fromList [1,2] -- foreach x in stream
6973-- return x
7074-- :}
7175-- [1,2]
@@ -73,16 +77,14 @@ import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
7377-- Nested monad binds behave like nested @for@ loops:
7478--
7579-- >>> :{
76−-- Stream.toList $ do
77−-- x <- Stream.fromList [1,2] -- foreach x in stream
78−-- y <- Stream.fromList [3,4] -- foreach y in stream
80+-- Stream.fold Fold.toList $ do
81+-- x <- Stream.unfold Unfold.fromList [1,2] -- foreach x in stream
82+-- y <- Stream.unfold Unfold.fromList [3,4] -- foreach y in stream
7983-- return (x, y)
8084-- :}
8185-- [(1,3),(1,4),(2,3),(2,4)]
8286--
83−-- /Since: 0.2.0 ("Streamly")/
84−--
85−-- @since 0.8.0
87+-- @since 0.9.0
8688newtype Stream m a = Stream (K.Stream m a)
8789 -- XXX when deriving do we inherit an INLINE?
8890 deriving (Semigroup, Monoid, MonadTrans)