on master help sign in
Merge pull request #151 from composewell/unstream-safe

Make unStream use rstState, making it safer.

commit0133e7424fa11ab4bc04e6d364373995c0b833f9 authorHarendra Kumar <harendra.kumar@gmail.com> dateSat 29 Dec 2018, 16:20 (8 years ago) parentffab417d01942d
23 files changed+1246−921
benchmark/BaseStreams.hs+1 benchmark/Linear.hs+1 benchmark/LinearAsync.hs+26−13 benchmark/LinearOps.hs+26−4 benchmark/NanoBenchmarks.hs+18−4 benchmark/Nested.hs+12−6 benchmark/NestedOps.hs+7 benchmark/StreamDOps.hs+1−1 benchmark/StreamKOps.hs+9−5 src/Streamly/Prelude.hs+92−91 src/Streamly/SVar.hs+11−3 src/Streamly/Streams/Ahead.hs+60−61 src/Streamly/Streams/Async.hs+86−63 src/Streamly/Streams/Combinators.hs+12−12 src/Streamly/Streams/Parallel.hs+36−29 src/Streamly/Streams/SVar.hs+10−9 src/Streamly/Streams/Serial.hs+22−51 src/Streamly/Streams/StreamD.hs+43−83 src/Streamly/Streams/StreamD/Type.hs+100 src/Streamly/Streams/StreamK.hs+224−471 src/Streamly/Streams/StreamK/Type.hs+418 src/Streamly/Streams/Zip.hs+24−15 streamly.cabal+7
benchmark/BaseStreams.hs+1
@@ -165,6 +165,7 @@ main =
165165 ]
166166 , bgroup "elimination"
167167 [ benchIO "toNull" K.toNull K.sourceUnfoldrM
168+ , benchIO "mapM_" K.mapM_ K.sourceUnfoldrM
168169 , benchIO "uncons" K.uncons K.sourceUnfoldrM
169170 , benchFold "init" K.init K.sourceUnfoldrM
170171 , benchFold "tail" K.tail K.sourceUnfoldrM
benchmark/Linear.hs+1
@@ -97,6 +97,7 @@ main =
9797 -- These are essentially appends
9898 , benchIOSrc serially "foldMapWith" Ops.sourceFoldMapWith
9999 , benchIOSrc serially "foldMapWithM" Ops.sourceFoldMapWithM
100+ , benchIOSrc serially "foldMapM" Ops.sourceFoldMapM
100101 ]
101102 , bgroup "elimination"
102103 [ benchIOSink "toNull" $ Ops.toNull serially
benchmark/LinearAsync.hs+26−13
@@ -40,12 +40,15 @@ main :: IO ()
4040main =
4141 defaultMain
4242 [ bgroup "asyncly"
43− [ -- benchIO "unfoldr" $ Ops.toNull asyncly
44− benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
45− -- , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
43+ [ benchSrcIO asyncly "unfoldr" Ops.sourceUnfoldr
44+ , benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
45+ , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
4646 , benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
47− -- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
47+ , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
4848 , benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
49+ , benchSrcIO asyncly "foldMapM" Ops.sourceFoldMapM
50+ , benchIO "map" $ Ops.map' asyncly 1
51+ , benchIO "fmap" $ Ops.fmap' asyncly 1
4952 , benchIO "mapM" $ Ops.mapM asyncly 1
5053 , benchSrcIO asyncly "unfoldrM maxThreads 1"
5154 (maxThreads 1 . Ops.sourceUnfoldrM)
@@ -53,23 +56,29 @@ main =
5356 (maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
5457 ]
5558 , bgroup "wAsyncly"
56− [ -- benchIO "unfoldr" $ Ops.toNull wAsyncly
57− benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
58− -- , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
59+ [ benchSrcIO wAsyncly "unfoldr" Ops.sourceUnfoldr
60+ , benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
61+ , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
5962 , benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
60− -- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
63+ , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
6164 , benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
65+ , benchSrcIO wAsyncly "foldMapM" Ops.sourceFoldMapM
66+ , benchIO "map" $ Ops.map' wAsyncly 1
67+ , benchIO "fmap" $ Ops.fmap' wAsyncly 1
6268 , benchIO "mapM" $ Ops.mapM wAsyncly 1
6369 ]
6470 -- unfoldr and fromFoldable are always serial and thereofore the same for
6571 -- all stream types.
6672 , bgroup "aheadly"
67− [ -- benchIO "unfoldr" $ Ops.toNull aheadly
68− benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
73+ [ benchSrcIO aheadly "unfoldr" Ops.sourceUnfoldr
74+ , benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
6975 , benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
7076 -- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
7177 , benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
72− , benchIO "mapM" $ Ops.mapM aheadly 1
78+ , benchSrcIO aheadly "foldMapM" Ops.sourceFoldMapM
79+ , benchIO "map" $ Ops.map' aheadly 1
80+ , benchIO "fmap" $ Ops.fmap' aheadly 1
81+ , benchIO "mapM" $ Ops.mapM aheadly 1
7382 , benchSrcIO aheadly "unfoldrM maxThreads 1"
7483 (maxThreads 1 . Ops.sourceUnfoldrM)
7584 , benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
@@ -78,15 +87,19 @@ main =
7887 ]
7988 -- XXX need to use smaller streams to finish in reasonable time
8089 , bgroup "parallely"
81− [ --benchIO "unfoldr" $ Ops.toNull parallely
82− benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
90+ [ benchSrcIO parallely "unfoldr" Ops.sourceUnfoldr
91+ , benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
8392 --, benchSrcIO parallely "fromFoldable" Ops.sourceFromFoldable
8493 , benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
8594 -- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
8695 , benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
96+ , benchSrcIO parallely "foldMapM" Ops.sourceFoldMapM
97+ , benchIO "map" $ Ops.map' parallely 1
98+ , benchIO "fmap" $ Ops.fmap' parallely 1
8799 , benchIO "mapM" $ Ops.mapM parallely 1
88100 -- Zip has only one parallel flavor
89101 , benchIO "zip" Ops.zipAsync
90102 , benchIO "zipM" Ops.zipAsyncM
103+ , benchIO "zipAp" Ops.zipAsyncAp
91104 ]
92105 ]
benchmark/LinearOps.hs+26−4
@@ -19,7 +19,7 @@ import Data.Maybe (fromJust)
1919import Prelude
2020 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (>=),
2121 subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
22− maxBound, div, IO, compare, Double, fromIntegral, Integer)
22+ maxBound, div, IO, compare, Double, fromIntegral, Integer, (<$>), (<*>))
2323import qualified Prelude as P
2424import qualified Data.Foldable as F
2525import qualified GHC.Exts as GHC
@@ -49,7 +49,7 @@ type Stream m a = S.SerialT m a
4949
5050{-# INLINE source #-}
5151source :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
52−source n = S.serially $ sourceUnfoldrM n
52+source n = sourceUnfoldrM n
5353
5454{-# INLINE sourceIntFromTo #-}
5555sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> t m Int
@@ -98,6 +98,11 @@ sourceFoldMapWithM :: (S.IsStream t, Monad m, S.Semigroup (t m Int))
9898 => Int -> t m Int
9999sourceFoldMapWithM n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
100100
101+{-# INLINE sourceFoldMapM #-}
102+sourceFoldMapM :: (S.IsStream t, Monad m, P.Monoid (t m Int))
103+ => Int -> t m Int
104+sourceFoldMapM n = F.foldMap (S.yieldM . return) [n..n+value]
105+
101106{-# INLINE sourceUnfoldr #-}
102107sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> t m Int
103108sourceUnfoldr n = S.unfoldr step n
@@ -173,6 +178,8 @@ last, minimum, maximum, find, findIndex, elemIndex, foldl1', foldr1
173178minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
174179
175180{-# INLINE foldl' #-}
181+{-# INLINE foldr #-}
182+{-# INLINE foldrM #-}
176183{-# INLINE length #-}
177184{-# INLINE sum #-}
178185{-# INLINE product #-}
@@ -307,7 +314,12 @@ scan, scanl1', map, fmap, mapMaybe, filterEven, filterAllOut,
307314mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
308315
309316{-# INLINE mapM #-}
310−mapM :: (S.IsStream t, S.MonadAsync m)
317+{-# INLINE map' #-}
318+{-# INLINE fmap' #-}
319+mapM, map' :: (S.IsStream t, S.MonadAsync m)
320+ => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
321+
322+fmap' :: (S.IsStream t, S.MonadAsync m, P.Functor (t m))
311323 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
312324
313325{-# INLINE sequence #-}
@@ -317,7 +329,9 @@ sequence :: (S.IsStream t, S.MonadAsync m)
317329scan n = composeN n $ S.scanl' (+) 0
318330scanl1' n = composeN n $ S.scanl1' (+)
319331fmap n = composeN n $ Prelude.fmap (+1)
332+fmap' t n = composeN' n $ t . Prelude.fmap (+1)
320333map n = composeN n $ S.map (+1)
334+map' t n = composeN' n $ t . S.map (+1)
321335mapM t n = composeN' n $ t . S.mapM return
322336mapMaybe n = composeN n $ S.mapMaybe
323337 (\x -> if Prelude.odd x then Nothing else Just x)
@@ -421,17 +435,25 @@ stripPrefix src = do
421435
422436{-# INLINE zipAsync #-}
423437{-# INLINE zipAsyncM #-}
424−zipAsync, zipAsyncM :: S.MonadAsync m => Stream m Int -> m ()
438+{-# INLINE zipAsyncAp #-}
439+zipAsync, zipAsyncAp, zipAsyncM :: S.MonadAsync m => Stream m Int -> m ()
425440
426441zipAsync src = do
427442 r <- S.tail src
428443 let src1 = fromJust r
429444 transform (S.zipAsyncWith (,) src src1)
445+
430446zipAsyncM src = do
431447 r <- S.tail src
432448 let src1 = fromJust r
433449 transform (S.zipAsyncWithM (curry return) src src1)
434450
451+zipAsyncAp src = do
452+ r <- S.tail src
453+ let src1 = fromJust r
454+ transform (S.zipAsyncly $ (,) <$> S.serially src
455+ <*> S.serially src1)
456+
435457{-# INLINE eqBy #-}
436458eqBy :: (Monad m, P.Eq a) => Stream m a -> m P.Bool
437459eqBy src = S.eqBy (==) src src
benchmark/NanoBenchmarks.hs+18−4
@@ -3,15 +3,18 @@
33-- at GHC generated code for optimizing specific problematic cases.
44-------------------------------------------------------------------------------
55
6+{-# LANGUAGE FlexibleContexts #-}
67{-# LANGUAGE ScopedTypeVariables #-}
7−import qualified Streamly.Streams.StreamD as S
8+import Streamly.SVar (MonadAsync)
9+import qualified Streamly.Streams.StreamK as S
810import Gauge
11+import System.Random
912
1013maxValue :: Int
1114maxValue = 100000
1215
1316{-# INLINE sourceUnfoldrM #-}
14−sourceUnfoldrM :: Monad m => S.Stream m Int
17+sourceUnfoldrM :: MonadAsync m => S.Stream m Int
1518sourceUnfoldrM = S.unfoldrM step 0
1619 where
1720 step cnt =
@@ -20,7 +23,7 @@ sourceUnfoldrM = S.unfoldrM step 0
2023 else return (Just (cnt, cnt + 1))
2124
2225{-# INLINE sourceUnfoldrMN #-}
23−sourceUnfoldrMN :: Monad m => Int -> S.Stream m Int
26+sourceUnfoldrMN :: MonadAsync m => Int -> S.Stream m Int
2427sourceUnfoldrMN n = S.unfoldrM step n
2528 where
2629 step cnt =
@@ -28,6 +31,15 @@ sourceUnfoldrMN n = S.unfoldrM step n
2831 then return Nothing
2932 else return (Just (cnt, cnt + 1))
3033
34+{-# INLINE sourceUnfoldr #-}
35+sourceUnfoldr :: Monad m => Int -> S.Stream m Int
36+sourceUnfoldr n = S.unfoldr step n
37+ where
38+ step cnt =
39+ if cnt > n + maxValue
40+ then Nothing
41+ else Just (cnt, cnt + 1)
42+
3143-------------------------------------------------------------------------------
3244-- take-drop composition
3345-------------------------------------------------------------------------------
@@ -64,7 +76,7 @@ dropWhileFalseX4 = S.runStream
6476
6577{-# INLINE iterateSource #-}
6678iterateSource
67− :: Monad m
79+ :: MonadAsync m
6880 => (S.Stream m Int -> S.Stream m Int) -> Int -> Int -> S.Stream m Int
6981iterateSource g i n = f i (sourceUnfoldrMN n)
7082 where
@@ -75,6 +87,8 @@ iterateSource g i n = f i (sourceUnfoldrMN n)
7587-- We keep all of them enabled by default for testing the build.
7688main :: IO ()
7789main = do
90+ defaultMain [bench "unfoldr" $ nfIO $
91+ randomRIO (1,1) >>= \n -> S.runStream (sourceUnfoldr n)]
7892 defaultMain [bench "take-drop" $ nfIO $ takeDrop sourceUnfoldrM]
7993 defaultMain [bench "dropWhileFalseX4" $
8094 nfIO $ dropWhileFalseX4 sourceUnfoldrM]
benchmark/Nested.hs+12−6
@@ -23,7 +23,8 @@ main =
2323 -- TBD Study scaling with 10, 100, 1000 loop iterations
2424 defaultMain
2525 [ bgroup "serially"
26− [ benchIO "toNull" $ Ops.toNull serially
26+ [ benchIO "toNullAp" $ Ops.toNullAp serially
27+ , benchIO "toNull" $ Ops.toNull serially
2728 , benchIO "toList" $ Ops.toList serially
2829 -- , benchIO "toListSome" $ Ops.toListSome serially
2930 , benchIO "filterAllOut" $ Ops.filterAllOut serially
@@ -33,7 +34,8 @@ main =
3334 ]
3435
3536 , bgroup "wSerially"
36− [ benchIO "toNull" $ Ops.toNull wSerially
37+ [ benchIO "toNullAp" $ Ops.toNullAp wSerially
38+ , benchIO "toNull" $ Ops.toNull wSerially
3739 , benchIO "toList" $ Ops.toList wSerially
3840 -- , benchIO "toListSome" $ Ops.toListSome wSerially
3941 , benchIO "filterAllOut" $ Ops.filterAllOut wSerially
@@ -43,7 +45,8 @@ main =
4345 ]
4446
4547 , bgroup "aheadly"
46− [ benchIO "toNull" $ Ops.toNull aheadly
48+ [ benchIO "toNullAp" $ Ops.toNullAp aheadly
49+ , benchIO "toNull" $ Ops.toNull aheadly
4750 , benchIO "toList" $ Ops.toList aheadly
4851 -- , benchIO "toListSome" $ Ops.toListSome aheadly
4952 , benchIO "filterAllOut" $ Ops.filterAllOut aheadly
@@ -53,7 +56,8 @@ main =
5356 ]
5457
5558 , bgroup "asyncly"
56− [ benchIO "toNull" $ Ops.toNull asyncly
59+ [ benchIO "toNullAp" $ Ops.toNullAp asyncly
60+ , benchIO "toNull" $ Ops.toNull asyncly
5761 , benchIO "toList" $ Ops.toList asyncly
5862 -- , benchIO "toListSome" $ Ops.toListSome asyncly
5963 , benchIO "filterAllOut" $ Ops.filterAllOut asyncly
@@ -63,7 +67,8 @@ main =
6367 ]
6468
6569 , bgroup "wAsyncly"
66− [ benchIO "toNull" $ Ops.toNull wAsyncly
70+ [ benchIO "toNullAp" $ Ops.toNullAp wAsyncly
71+ , benchIO "toNull" $ Ops.toNull wAsyncly
6772 , benchIO "toList" $ Ops.toList wAsyncly
6873 -- , benchIO "toListSome" $ Ops.toListSome wAsyncly
6974 , benchIO "filterAllOut" $ Ops.filterAllOut wAsyncly
@@ -73,7 +78,8 @@ main =
7378 ]
7479
7580 , bgroup "parallely"
76− [ benchIO "toNull" $ Ops.toNull parallely
81+ [ benchIO "toNullAp" $ Ops.toNullAp parallely
82+ , benchIO "toNull" $ Ops.toNull parallely
7783 , benchIO "toList" $ Ops.toList parallely
7884 --, benchIO "toListSome" $ Ops.toListSome parallely
7985 , benchIO "filterAllOut" $ Ops.filterAllOut parallely
benchmark/NestedOps.hs+7
@@ -62,6 +62,13 @@ runToList = S.toList
6262-- Benchmark ops
6363-------------------------------------------------------------------------------
6464
65+{-# INLINE toNullAp #-}
66+toNullAp
67+ :: (S.IsStream t, S.MonadAsync m, Monad (t m))
68+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
69+toNullAp t start = runStream . t $
70+ (+) <$> source start prodCount <*> source start prodCount
71+
6572{-# INLINE toNull #-}
6673toNull
6774 :: (S.IsStream t, S.MonadAsync m, Monad (t m))
benchmark/StreamDOps.hs+1−1
@@ -59,7 +59,7 @@ sourceUnfoldrM n = S.unfoldrM step n
5959
6060{-# INLINE sourceFromEnum #-}
6161sourceFromEnum :: Monad m => Int -> Stream m Int
62−sourceFromEnum n = S.enumFromStepN n 1 value
62+sourceFromEnum n = S.intFromTo n (n + value)
6363
6464{-# INLINE sourceFromList #-}
6565sourceFromList :: Monad m => Int -> Stream m Int
benchmark/StreamKOps.hs+9−5
@@ -14,7 +14,7 @@ import Control.Monad (when)
1414import Data.Maybe (isJust)
1515import Prelude
1616 (Monad, Int, (+), ($), (.), return, even, (>), (<=), div,
17− subtract, undefined, Maybe(..), not, mapM_, (>>=),
17+ subtract, undefined, Maybe(..), not, (>>=),
1818 maxBound)
1919import qualified Prelude as P
2020
@@ -116,6 +116,10 @@ source = sourceUnfoldrM
116116runStream :: Monad m => Stream m a -> m ()
117117runStream = S.runStream
118118
119+{-# INLINE mapM_ #-}
120+mapM_ :: Monad m => Stream m a -> m ()
121+mapM_ = S.mapM_ (\_ -> return ())
122+
119123toNull = runStream
120124uncons s = do
121125 r <- S.uncons s
@@ -127,19 +131,19 @@ uncons s = do
127131init :: (Monad m, S.IsStream t) => t m a -> m ()
128132init s = do
129133 t <- S.init s
130− mapM_ S.runStream t
134+ P.mapM_ S.runStream t
131135
132136{-# INLINE tail #-}
133137tail :: (Monad m, S.IsStream t) => t m a -> m ()
134−tail s = S.tail s >>= mapM_ tail
138+tail s = S.tail s >>= P.mapM_ tail
135139
136140nullTail s = do
137141 r <- S.null s
138− when (not r) $ S.tail s >>= mapM_ nullTail
142+ when (not r) $ S.tail s >>= P.mapM_ nullTail
139143
140144headTail s = do
141145 h <- S.head s
142− when (isJust h) $ S.tail s >>= mapM_ headTail
146+ when (isJust h) $ S.tail s >>= P.mapM_ headTail
143147
144148toList = S.toList
145149foldl = S.foldl' (+) 0
src/Streamly/Prelude.hs+92−91
@@ -363,7 +363,7 @@ import Prelude
363363import qualified Prelude
364364import qualified System.IO as IO
365365
366−import Streamly.SVar (MonadAsync, defState, rstState)
366+import Streamly.SVar (MonadAsync, defState)
367367import Streamly.Streams.Async (mkAsync')
368368import Streamly.Streams.Combinators (maxYields)
369369import Streamly.Streams.Prelude (fromStreamS, toStreamS)
@@ -394,6 +394,7 @@ import qualified Streamly.Streams.Serial as Serial
394394-- the head of the stream and @ma@ its tail.
395395--
396396-- @since 0.1.0
397+{-# INLINE uncons #-}
397398uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
398399uncons m = K.uncons (K.adapt m)
399400
@@ -840,9 +841,9 @@ iterate step = fromStream . go
840841iterateM :: (IsStream t, MonadAsync m) => (a -> m a) -> a -> t m a
841842iterateM step = go
842843 where
843− go s = fromStream $ K.Stream $ \svr stp sng yld -> do
844+ go s = K.mkStream $ \st stp sng yld -> do
844845 next <- step s
845− K.unStream (toStream (return s |: go next)) svr stp sng yld
846+ K.foldStreamShared st stp sng yld (return s |: go next)
846847
847848------------------------------------------------------------------------------
848849-- Conversions
@@ -894,9 +895,9 @@ each = K.fromFoldable
894895--
895896-- @since 0.1.0
896897fromHandle :: (IsStream t, MonadIO m) => IO.Handle -> t m String
897−fromHandle h = fromStream go
898+fromHandle h = go
898899 where
899− go = K.Stream $ \_ stp _ yld -> do
900+ go = K.mkStream $ \_ yld _ stp -> do
900901 eof <- liftIO $ IO.hIsEOF h
901902 if eof
902903 then stp
@@ -923,60 +924,69 @@ foldrM = P.foldrM
923924
924925-- | Lazy right associative fold.
925926--
926−-- @foldr f z xs@ deconstructs @xs@ one element @x@ at a time, applying the
927−-- function @f@ to @x@ and the tail of the output. The tail recurses until the
928−-- input finishes and @z@ is used as the tail end.
927+-- For lists a @foldr@ looks like:
929928--
930929-- @
931−-- foldr f z xs == x1 \`f` tail1
932−-- tail1 == x2 \`f` tail2
933−-- tail2 == x3 \`f` tail3
934−-- ...
935−-- tailn == xn \`f` z
930+-- foldr f z [] = z
931+-- foldr f z (x:xs) = x \`f` foldr f z xs
936932-- @
937933--
938−-- Resulting in a right associated expression:
934+-- The recursive expression is the second argument of the fold step `f`.
935+-- Therefore, the evaluation of the recursive call depends on `f`. It can
936+-- terminate recursion by not inspecting the second argument based on a
937+-- condition. When expanded fully, it results in the following right associated
938+-- expression:
939939--
940940-- @
941941-- foldr f z xs == x1 \`f` (x2 \`f` ...(xn \`f` z))
942942-- @
943943--
944−-- When the outermost operation in the fold function is a constructor, foldr
945−-- generates a structure that can be consumed lazily. For example:
944+-- When `f` is a constructor, we can see that the first deconstruction of this
945+-- expression would be @x1@ on the left and the recursive expression on the
946+-- right. Therefore, we can deconstruct it to access the input elements in the
947+-- first-in-first-out (FIFO) order and consume the reconstructed structure
948+-- lazily. The recursive expression on the right gets evaluated incrementall
949+-- as demanded by the consumer. For example:
946950--
947951-- @
948952-- > S.foldr (:) [] $ S.fromList [1,2,3,4]
949953-- [1,2,3,4]
950954-- @
951955--
956+-- When `f` is a function strict in its second argument, the right side of the
957+-- expression gets evaluated as follows:
958+--
952959-- @
953−-- 1 : tail
954−-- 1 : (2 : tail)
955−-- 1 : (2 : (3 : tail))
956−-- 1 : (2 : (3 : (4 : [])))
960+-- foldr f z xs == x1 \`f` tail1
961+-- tail1 == x2 \`f` tail2
962+-- tail2 == x3 \`f` tail3
963+-- ...
964+-- tailn == xn \`f` z
957965-- @
958966--
959−-- When the outermost operation is a function @foldr@ results in a right
960−-- associated expression which cannot be reduced until the whole expression has
961−-- been built. Therefore, it ends up consuming the whole input, buffering the
962−-- whole expression in memory before reduction can start. For example:
967+-- In @foldl'@ we have both the arguments of `f` available at each step,
968+-- therefore, each step can be reduced immediately. However, in @foldr@ the
969+-- second argument to `f` is a recursive call, therefore, it ends up building
970+-- the whole expression in memory before it can be reduced, consuming the whole
971+-- input. This makes @foldr@ much less efficient for reduction compared to
972+-- @foldl'@. For example:
963973--
964974-- @
965975-- > S.foldr (+) 0 $ S.fromList [1,2,3,4]
966976-- 10
967977-- @
968978--
969−-- @
970−-- 1 + tail
971−-- 1 + (2 + tail)
972−-- 1 + (2 + (3 + tail))
973−-- 1 + (2 + (3 + (4 + 0)))
974−-- @
979+-- When the underlying monad @m@ is strict (e.g. IO), then @foldr@ ends up
980+-- evaluating all of its input because of strict evaluation of the recursive
981+-- call:
982+--
983+-- >> S.foldr (\_ _ -> []) [] $ S.fromList (1:undefined)
984+-- >*** Exception: Prelude.undefined
975985--
976−-- In @foldr@, the output tail is the source of recursion, we can stop
977−-- recursion and terminate the fold by yielding a terminal value as tail:
986+-- In a lazy monad, we can consume the input lazily, and terminate the fold
987+-- by conditionally not inspecting the recursive expression.
978988--
979−-- >> S.foldr (\x rest -> if x == 3 then [] else x : rest) [] $ S.fromList [4,1,3,undefined]
989+-- >> runIdentity $ S.foldr (\x rest -> if x == 3 then [] else x : rest) [] $ S.fromList (4:1:3:undefined)
980990-- >[4,1]
981991--
982992-- The arguments to the folding function (@a -> b -> b@) are in the head and
@@ -1014,37 +1024,38 @@ foldl = foldx
10141024
10151025-- | Strict left associative fold.
10161026--
1017−-- @foldl' f z xs@ deconstructs @xs@ one element @x@ at a time, applying the
1018−-- function @f@ to the output accumulated till now (the head of the expression)
1019−-- and @x@. The accumulator starts with the initial value @z@ and keeps
1020−-- accumulating elements until the input finishes.
1027+-- For lists a @foldl@ looks like:
10211028--
10221029-- @
1023−-- head1 == z \`f` x1
1024−-- head2 == head1 \`f` x2
1025−-- head3 == head2 \`f` x3
1026−-- ...
1027−-- foldl' f z xs == head(n-1) \`f` xn
1030+-- foldl f z [] = z
1031+-- foldl f z (x:xs) = foldl f (z \`f` x) xs
10281032-- @
10291033--
1030−-- Recursively building a left associated expression:
1034+-- The recursive call at the head of the output expression is bound to be
1035+-- evaluated until recursion terminates,
1036+-- /deconstructing the whole input container/ and building the following left
1037+-- associated expression:
10311038--
10321039-- @
1033−-- foldl' f z xs == (((z \`f` x1) \`f` x2) ...) \`f` xn
1040+-- foldl f z xs == (((z \`f` x1) \`f` x2) ...) \`f` xn
10341041-- @
10351042--
1036−-- When the outermost operation in the fold function is a (left associated)
1037−-- constructor, foldl' consumes the whole input to construct the new structure
1038−-- buffered in memory in the reverse order of the input. For example:
1043+-- When `f` is a constructor, we can see that the first deconstruction of this
1044+-- expression would be the recursive expression on the left and `xn` on the
1045+-- right. Therefore, it can access the input elements only in the reverse
1046+-- (LIFO) order. For example:
10391047--
10401048-- @
10411049-- > S.foldl' (flip (:)) [] $ S.fromList [1,2,3,4]
10421050-- [4,3,2,1]
10431051-- @
10441052--
1045−-- When the outermost operation is a function, @foldl'@ results in a left
1046−-- associated expression which is incrementally reduced at each step of the
1047−-- fold, thus never building the whole expression in memory. For example:
1053+-- The strict left fold @foldl'@ forces the reduction of its argument @z \`f`
1054+-- x@ before using it, therefore it never builds the whole expression in
1055+-- memory. Thus, @z \`f` x1@ would get reduced to @z1@ and then @z1 \`f` x2@
1056+-- would get reduced to @z2@ and so on, incrementally reducing the expression
1057+-- as it recurses. However, it evaluates the accumulator only to WHNF, it may
1058+-- further help to use a strict data structure as accumulator. For example:
10481059--
10491060-- @
10501061-- > S.foldl' (+) 0 $ S.fromList [1,2,3,4]
@@ -1057,42 +1068,32 @@ foldl = foldx
10571068-- ((0 + 1) + 2) + 3
10581069-- (((0 + 1) + 2) + 3) + 4
10591070-- @
1060−-- @
1061−-- 0 + 1 => reduce to 1
1062−-- 1 + 2 => reduce to 3
1063−-- 3 + 3 => reduce to 6
1064−-- 6 + 4 => reduce to 10
1065−-- @
10661071--
1067−-- We can stop recursion and terminate the fold by yielding an expression that
1068−-- is independent of the input element:
1072+-- @foldl@ strictly deconstructs the whole input container irrespective of
1073+-- whether it needs it or not:
10691074--
1070−-- >> S.foldl' (\acc x -> if acc >= 8 then acc else x + acc) 0 $ S.fromList [4,1,3,undefined]
1071−-- >8
1075+-- >> S.foldl' (\acc x -> if x == 3 then acc else x : acc) [] $ S.fromList (4:1:3:undefined)
1076+-- >*** Exception: Prelude.undefined
10721077--
1073−-- To stop on encountering the number 3 we will have to store the previous
1074−-- number in the accumulator so that we do not depend on the current input:
1078+-- However, evaluation of the items contained in the input container is lazy as
1079+-- demanded by the fold step function:
10751080--
1076−-- @
1077−-- > S.foldl' (\(acc, prev) x -> if prev == 3 then (acc,prev) else (x + acc,x))
1078−-- (0,0) $ S.fromList \[4,1,3,undefined]
1079−-- (8,3)
1080−-- @
1081+-- >> S.foldl' (\acc x -> if x == 3 then acc else x : acc) [] $ S.fromList [4,1,3,undefined]
1082+-- >[4,1]
10811083--
1082−-- To map the fold operation to stateful or event-driven programming, we can
1083−-- consider @z@ as the initial state and the stream being folded as a stream of
1084−-- events, thus @foldl'@ processes all the events in the stream updating the
1085−-- state on each event and then ultimately returning the final state.
1084+-- To perform a left fold without consuming all the input one can use @scanl@
1085+-- to stream the intermediate results of the fold and use them lazily.
1086+--
1087+-- In stateful or event-driven programming, we can consider @z@ as the initial
1088+-- state and the stream being folded as a stream of events, thus @foldl'@
1089+-- processes all the events in the stream updating the state on each event and
1090+-- then ultimately returning the final state.
10861091--
10871092-- The arguments to the folding function (@b -> a -> b@) are in the head and
10881093-- tail order of the output expression, @b@ is the head and @a@ is the tail.
10891094-- Remember, in a left fold the zero is on the left, at the head of the
10901095-- expression.
10911096--
1092−-- IMPORTANT: 'foldl'' evaluates the accumulator to WHNF. To avoid building
1093−-- lazy expressions inside the accumulator, and to help GHC optimize better, it
1094−-- is recommended that a strict data structure is used for accumulator.
1095−--
10961097-- @since 0.2.0
10971098{-# INLINE foldl' #-}
10981099foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
@@ -1443,13 +1444,13 @@ toList = P.toList
14431444--
14441445-- @since 0.1.0
14451446toHandle :: MonadIO m => IO.Handle -> SerialT m String -> m ()
1446−toHandle h m = go (toStream m)
1447+toHandle h m = go m
14471448 where
14481449 go m1 =
14491450 let stop = return ()
14501451 single a = liftIO (IO.hPutStrLn h a)
14511452 yieldk a r = liftIO (IO.hPutStrLn h a) >> go r
1452− in K.unStream m1 defState stop single yieldk
1453+ in K.foldStream defState yieldk single stop m1
14531454
14541455------------------------------------------------------------------------------
14551456-- Transformation by Folding (Scans)
@@ -1519,8 +1520,8 @@ scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
15191520-- @
15201521--
15211522-- IMPORTANT: 'scanl'' evaluates the accumulator to WHNF. To avoid building
1522−-- lazy expressions inside the accumulator, and to help GHC optimize better, it
1523−-- is recommended that a strict data structure is used for accumulator.
1523+-- lazy expressions inside the accumulator, it is recommended that a strict
1524+-- data structure is used for accumulator.
15241525--
15251526-- @since 0.2.0
15261527{-# INLINE scanl' #-}
@@ -1768,14 +1769,14 @@ mapMaybeMSerial f m = fromStreamD $ D.mapMaybeM f $ toStreamD m
17681769--
17691770-- @since 0.1.1
17701771reverse :: (IsStream t) => t m a -> t m a
1771−reverse m = fromStream $ go K.nil (toStream m)
1772+reverse m = go K.nil m
17721773 where
1773− go rev rest = K.Stream $ \st stp sng yld ->
1774− let runIt x = K.unStream x (rstState st) stp sng yld
1774+ go rev rest = K.mkStream $ \st yld sng stp ->
1775+ let runIt x = K.foldStream st yld sng stp x
17751776 stop = runIt rev
17761777 single a = runIt $ a `K.cons` rev
17771778 yieldk a r = runIt $ go (a `K.cons` rev) r
1778− in K.unStream rest (rstState st) stop single yieldk
1779+ in K.foldStream st yieldk single stop rest
17791780
17801781------------------------------------------------------------------------------
17811782-- Transformation by Inserting
@@ -1986,10 +1987,10 @@ merge = mergeBy compare
19861987-- @since 0.6.0
19871988mergeAsyncBy :: (IsStream t, MonadAsync m)
19881989 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
1989−mergeAsyncBy f m1 m2 = K.fromStream $ K.Stream $ \st stp sng yld -> do
1990− ma <- mkAsync' (rstState st) m1
1991− mb <- mkAsync' (rstState st) m2
1992− K.unStream (K.toStream (K.mergeBy f ma mb)) (rstState st) stp sng yld
1990+mergeAsyncBy f m1 m2 = K.mkStream $ \st stp sng yld -> do
1991+ ma <- mkAsync' st m1
1992+ mb <- mkAsync' st m2
1993+ K.foldStream st stp sng yld (K.mergeBy f ma mb)
19931994
19941995-- | Like 'mergeByM' but merges concurrently (i.e. both the elements being
19951996-- merged are generated concurrently).
@@ -1997,7 +1998,7 @@ mergeAsyncBy f m1 m2 = K.fromStream $ K.Stream $ \st stp sng yld -> do
19971998-- @since 0.6.0
19981999mergeAsyncByM :: (IsStream t, MonadAsync m)
19992000 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
2000−mergeAsyncByM f m1 m2 = K.fromStream $ K.Stream $ \st stp sng yld -> do
2001− ma <- mkAsync' (rstState st) m1
2002− mb <- mkAsync' (rstState st) m2
2003− K.unStream (K.toStream (K.mergeByM f ma mb)) (rstState st) stp sng yld
2001+mergeAsyncByM f m1 m2 = K.mkStream $ \st stp sng yld -> do
2002+ ma <- mkAsync' st m1
2003+ mb <- mkAsync' st m2
2004+ K.foldStream st stp sng yld (K.mergeByM f ma mb)
src/Streamly/SVar.hs+11−3
@@ -31,7 +31,7 @@ module Streamly.SVar
3131 , Limit (..)
3232 , State (streamVar)
3333 , defState
34− , rstState
34+ , adaptState
3535 , getMaxThreads
3636 , setMaxThreads
3737 , getMaxBuffer
@@ -433,8 +433,15 @@ defState = State
433433-- We can optimize this so that we clear it only if it is a Just value, it
434434-- results in slightly better perf for zip/zipM but the performance of scan
435435-- worsens a lot, it does not fuse.
436−rstState :: State t m a -> State t m b
437−rstState st = st
436+--
437+-- XXX This has a side effect of clearing the SVar and yieldLimit, therefore it
438+-- should not be used to convert from the same type to the same type, unless
439+-- you want to clear the SVar. For clearing the SVar you should be using the
440+-- appropriate unStream functions instead.
441+--
442+-- | Adapt the stream state from one type to another.
443+adaptState :: State t m a -> State t m b
444+adaptState st = st
438445 { streamVar = Nothing
439446 , _yieldLimit = Nothing
440447 }
@@ -2009,6 +2016,7 @@ newSVarStats = do
20092016 , svarStopTime = stpTime
20102017 }
20112018
2019+-- XXX remove polymorphism in t, inline f
20122020getAheadSVar :: MonadAsync m
20132021 => State t m a
20142022 -> ( IORef ([t m a], Int)
src/Streamly/Streams/Ahead.hs+60−61
@@ -48,8 +48,8 @@ import Streamly.Streams.SVar (fromSVar)
4848import Streamly.Streams.Serial (map)
4949import Streamly.SVar
5050import Streamly.Streams.StreamK
51− (IsStream(..), Stream(..), unstreamShared, unStreamIsolated,
52− runStreamSVar)
51+ (IsStream(..), Stream, mkStream, foldStream, foldStreamShared,
52+ foldStreamSVar)
5353import qualified Streamly.Streams.StreamK as K
5454
5555import Prelude hiding (map)
@@ -298,9 +298,11 @@ processHeap q heap st sv winfo entry sno stopping = loopHeap sno entry
298298 let stop = do
299299 liftIO (incrementYieldLimit sv)
300300 nextHeap seqNo
301− runStreamSVar sv r st stop
302− (singleStreamFromHeap seqNo)
301+ foldStreamSVar sv st
303302 (yieldStreamFromHeap seqNo)
303+ (singleStreamFromHeap seqNo)
304+ stop
305+ r
304306 else liftIO $ do
305307 let ent = Entry seqNo (AheadEntryStream r)
306308 liftIO $ requeueOnHeapTop heap ent seqNo
@@ -348,9 +350,11 @@ processWithoutToken q heap st sv winfo m seqNo = do
348350 -- we stop.
349351 toHeap AheadEntryNull
350352
351− runStreamSVar sv m st stop
352− (toHeap . AheadEntryPure)
353+ foldStreamSVar sv st
353354 (\a r -> toHeap $ AheadEntryStream $ K.cons a r)
355+ (toHeap . AheadEntryPure)
356+ stop
357+ m
354358
355359 where
356360
@@ -408,7 +412,7 @@ processWithToken q heap st sv winfo action sno = do
408412 liftIO (incrementYieldLimit sv)
409413 loopWithToken (sno + 1)
410414
411− runStreamSVar sv action st stop (singleOutput sno) (yieldOutput sno)
415+ foldStreamSVar sv st (yieldOutput sno) (singleOutput sno) stop action
412416
413417 where
414418
@@ -431,9 +435,11 @@ processWithToken q heap st sv winfo action sno = do
431435 let stop = do
432436 liftIO (incrementYieldLimit sv)
433437 loopWithToken (seqNo + 1)
434− runStreamSVar sv r st stop
435− (singleOutput seqNo)
438+ foldStreamSVar sv st
436439 (yieldOutput seqNo)
440+ (singleOutput seqNo)
441+ stop
442+ r
437443 else do
438444 let ent = Entry seqNo (AheadEntryStream r)
439445 liftIO $ requeueOnHeapTop heap ent seqNo
@@ -460,9 +466,11 @@ processWithToken q heap st sv winfo action sno = do
460466 let stop = do
461467 liftIO (incrementYieldLimit sv)
462468 loopWithToken (seqNo + 1)
463− runStreamSVar sv m st stop
464− (singleOutput seqNo)
469+ foldStreamSVar sv st
465470 (yieldOutput seqNo)
471+ (singleOutput seqNo)
472+ stop
473+ m
466474 else
467475 -- To avoid a race when another thread puts something
468476 -- on the heap and goes away, the consumer will not get
@@ -543,32 +551,38 @@ workLoopAhead q heap st sv winfo = do
543551
544552-- The only difference between forkSVarAsync and this is that we run the left
545553-- computation without a shared SVar.
546−forkSVarAhead :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
547−forkSVarAhead m1 m2 = Stream $ \st stp sng yld -> do
548− sv <- newAheadVar st (concurrently m1 m2) workLoopAhead
549− unStream (fromSVar sv) (rstState st) stp sng yld
554+forkSVarAhead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
555+forkSVarAhead m1 m2 = mkStream $ \st stp sng yld -> do
556+ sv <- newAheadVar st (concurrently (toStream m1) (toStream m2))
557+ workLoopAhead
558+ foldStream st stp sng yld (fromSVar sv)
550559 where
551− concurrently ma mb = Stream $ \st stp sng yld -> do
560+ concurrently ma mb = mkStream $ \st stp sng yld -> do
552561 liftIO $ enqueue (fromJust $ streamVar st) mb
553− unStream ma (rstState st) stp sng yld
562+ foldStream st stp sng yld ma
554563
555−{-# INLINE aheadS #-}
556−aheadS :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
557−aheadS m1 m2 = Stream $ \st stp sng yld ->
564+-- | Polymorphic version of the 'Semigroup' operation '<>' of 'AheadT'.
565+-- Merges two streams sequentially but with concurrent lookahead.
566+--
567+-- @since 0.3.0
568+{-# INLINE ahead #-}
569+ahead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
570+ahead m1 m2 = mkStream $ \st stp sng yld ->
558571 case streamVar st of
559572 Just sv | svarStyle sv == AheadVar -> do
560− liftIO $ enqueue sv m2
573+ liftIO $ enqueue sv (toStream m2)
561574 -- Always run the left side on a new SVar to avoid complexity in
562575 -- sequencing results. This means the left side cannot further
563576 -- split into more ahead computations on the same SVar.
564− unStream m1 (rstState st) stp sng yld
565− _ -> unStream (forkSVarAhead m1 m2) st stp sng yld
577+ foldStream st stp sng yld m1
578+ _ -> foldStreamShared st stp sng yld (forkSVarAhead m1 m2)
566579
567580-- | XXX we can implement it more efficienty by directly implementing instead
568581-- of combining streams using ahead.
569582{-# INLINE consMAhead #-}
570−consMAhead :: MonadAsync m => m a -> Stream m a -> Stream m a
571−consMAhead m r = K.yieldM m `aheadS` r
583+{-# SPECIALIZE consMAhead :: IO a -> AheadT IO a -> AheadT IO a #-}
584+consMAhead :: MonadAsync m => m a -> AheadT m a -> AheadT m a
585+consMAhead m r = fromStream $ K.yieldM m `ahead` (toStream r)
572586
573587------------------------------------------------------------------------------
574588-- AheadT
@@ -636,30 +650,20 @@ aheadly = K.adapt
636650instance IsStream AheadT where
637651 toStream = getAheadT
638652 fromStream = AheadT
639−
640− {-# INLINE consM #-}
641− {-# SPECIALIZE consM :: IO a -> AheadT IO a -> AheadT IO a #-}
642− consM m r = fromStream $ consMAhead m (toStream r)
643−
644− {-# INLINE (|:) #-}
645− {-# SPECIALIZE (|:) :: IO a -> AheadT IO a -> AheadT IO a #-}
646− (|:) = consM
653+ consM = consMAhead
654+ (|:) = consMAhead
647655
648656------------------------------------------------------------------------------
649657-- Semigroup
650658------------------------------------------------------------------------------
651659
652−-- | Polymorphic version of the 'Semigroup' operation '<>' of 'AheadT'.
653−-- Merges two streams sequentially but with concurrent lookahead.
654−--
655−-- @since 0.3.0
656−{-# INLINE ahead #-}
657−ahead :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
658−ahead m1 m2 = fromStream $ Stream $ \st stp sng yld ->
659− unStream (aheadS (toStream m1) (toStream m2)) st stp sng yld
660+{-# INLINE mappendAhead #-}
661+{-# SPECIALIZE mappendAhead :: AheadT IO a -> AheadT IO a -> AheadT IO a #-}
662+mappendAhead :: MonadAsync m => AheadT m a -> AheadT m a -> AheadT m a
663+mappendAhead m1 m2 = fromStream $ ahead (toStream m1) (toStream m2)
660664
661665instance MonadAsync m => Semigroup (AheadT m a) where
662− (<>) = ahead
666+ (<>) = mappendAhead
663667
664668------------------------------------------------------------------------------
665669-- Monoid
@@ -673,31 +677,26 @@ instance MonadAsync m => Monoid (AheadT m a) where
673677-- Monad
674678------------------------------------------------------------------------------
675679
676−{-# INLINE aheadbind #-}
677−aheadbind
678− :: MonadAsync m
679− => Stream m a
680− -> (a -> Stream m b)
681− -> Stream m b
682−aheadbind m f = go m
683− where
684− go (Stream g) =
685− Stream $ \st stp sng yld ->
686− let runShared x = unstreamShared x st stp sng yld
687− runIsolated x = unStreamIsolated x st stp sng yld
688−
689− single a = runIsolated $ f a
690− yieldk a r = runShared $
691− K.isolateStream (f a) `aheadS` go r
692− in g (rstState st) stp single yieldk
680+{-# INLINE bindAhead #-}
681+{-# SPECIALIZE bindAhead :: AheadT IO a -> (a -> AheadT IO b) -> AheadT IO b #-}
682+bindAhead :: MonadAsync m => AheadT m a -> (a -> AheadT m b) -> AheadT m b
683+bindAhead m f = fromStream $ K.bindWith ahead (K.adapt m) (\a -> K.adapt $ f a)
693684
694685instance MonadAsync m => Monad (AheadT m) where
695686 return = pure
696− (AheadT m) >>= f = AheadT $ aheadbind m (getAheadT . f)
687+ (>>=) = bindAhead
688+
689+{-# INLINE apAhead #-}
690+{-# SPECIALIZE apAhead :: AheadT IO (a -> b) -> AheadT IO a -> AheadT IO b #-}
691+apAhead :: MonadAsync m => AheadT m (a -> b) -> AheadT m a -> AheadT m b
692+apAhead mf m = ap (K.adapt mf) (K.adapt m)
693+
694+instance (Monad m, MonadAsync m) => Applicative (AheadT m) where
695+ pure = AheadT . K.yield
696+ (<*>) = apAhead
697697
698698------------------------------------------------------------------------------
699699-- Other instances
700700------------------------------------------------------------------------------
701701
702−MONAD_APPLICATIVE_INSTANCE(AheadT,MONADPARALLEL)
703702MONAD_COMMON_INSTANCES(AheadT, MONADPARALLEL)
src/Streamly/Streams/Async.hs+86−63
@@ -57,7 +57,9 @@ import qualified Data.Set as S
5757import Streamly.Streams.SVar (fromSVar)
5858import Streamly.Streams.Serial (map)
5959import Streamly.SVar
60−import Streamly.Streams.StreamK (IsStream(..), Stream(..), adapt, runStreamSVar)
60+import Streamly.Streams.StreamK
61+ (IsStream(..), Stream, mkStream, foldStream, adapt, foldStreamShared,
62+ foldStreamSVar)
6163import qualified Streamly.Streams.StreamK as K
6264
6365#include "Instances.hs"
@@ -82,7 +84,7 @@ workLoopLIFO q st sv winfo = run
8284 work <- dequeue
8385 case work of
8486 Nothing -> liftIO $ sendStop sv winfo
85− Just m -> runStreamSVar sv m st run single yieldk
87+ Just m -> foldStreamSVar sv st yieldk single run m
8688
8789 single a = do
8890 res <- liftIO $ sendYield sv winfo (ChildYield a)
@@ -91,7 +93,7 @@ workLoopLIFO q st sv winfo = run
9193 yieldk a r = do
9294 res <- liftIO $ sendYield sv winfo (ChildYield a)
9395 if res
94− then runStreamSVar sv r st run single yieldk
96+ then foldStreamSVar sv st yieldk single run r
9597 else liftIO $ do
9698 enqueueLIFO sv q r
9799 sendStop sv winfo
@@ -132,7 +134,7 @@ workLoopLIFOLimited q st sv winfo = run
132134 if yieldLimitOk
133135 then do
134136 let stop = liftIO (incrementYieldLimit sv) >> run
135− runStreamSVar sv m st stop single yieldk
137+ foldStreamSVar sv st yieldk single stop m
136138 -- Avoid any side effects, undo the yield limit decrement if we
137139 -- never yielded anything.
138140 else liftIO $ do
@@ -151,7 +153,7 @@ workLoopLIFOLimited q st sv winfo = run
151153 yieldLimitOk <- liftIO $ decrementYieldLimit sv
152154 let stop = liftIO (incrementYieldLimit sv) >> run
153155 if res && yieldLimitOk
154− then runStreamSVar sv r st stop single yieldk
156+ then foldStreamSVar sv st yieldk single stop r
155157 else liftIO $ do
156158 incrementYieldLimit sv
157159 enqueueLIFO sv q r
@@ -183,7 +185,7 @@ workLoopFIFO q st sv winfo = run
183185 work <- liftIO $ tryPopR q
184186 case work of
185187 Nothing -> liftIO $ sendStop sv winfo
186− Just m -> runStreamSVar sv m st run single yieldk
188+ Just m -> foldStreamSVar sv st yieldk single run m
187189
188190 single a = do
189191 res <- liftIO $ sendYield sv winfo (ChildYield a)
@@ -192,7 +194,7 @@ workLoopFIFO q st sv winfo = run
192194 yieldk a r = do
193195 res <- liftIO $ sendYield sv winfo (ChildYield a)
194196 if res
195− then runStreamSVar sv r st run single yieldk
197+ then foldStreamSVar sv st yieldk single run r
196198 else liftIO $ do
197199 enqueueFIFO sv q r
198200 sendStop sv winfo
@@ -218,7 +220,7 @@ workLoopFIFOLimited q st sv winfo = run
218220 if yieldLimitOk
219221 then do
220222 let stop = liftIO (incrementYieldLimit sv) >> run
221− runStreamSVar sv m st stop single yieldk
223+ foldStreamSVar sv st yieldk single stop m
222224 else liftIO $ do
223225 enqueueFIFO sv q m
224226 incrementYieldLimit sv
@@ -233,7 +235,7 @@ workLoopFIFOLimited q st sv winfo = run
233235 yieldLimitOk <- liftIO $ decrementYieldLimit sv
234236 let stop = liftIO (incrementYieldLimit sv) >> run
235237 if res && yieldLimitOk
236− then runStreamSVar sv r st stop single yieldk
238+ then foldStreamSVar sv st yieldk single stop r
237239 else liftIO $ do
238240 incrementYieldLimit sv
239241 enqueueFIFO sv q r
@@ -526,36 +528,33 @@ newWAsyncVar st m = do
526528-- composition and vice-versa we create a new SVar to isolate the scheduling
527529-- of the two.
528530
529−forkSVarAsync :: MonadAsync m
530− => SVarStyle -> Stream m a -> Stream m a -> Stream m a
531−forkSVarAsync style m1 m2 = Stream $ \st stp sng yld -> do
531+forkSVarAsync :: (IsStream t, MonadAsync m)
532+ => SVarStyle -> t m a -> t m a -> t m a
533+forkSVarAsync style m1 m2 = mkStream $ \st stp sng yld -> do
532534 sv <- case style of
533− AsyncVar -> newAsyncVar st (concurrently m1 m2)
534− WAsyncVar -> newWAsyncVar st (concurrently m1 m2)
535+ AsyncVar -> newAsyncVar st (concurrently (toStream m1) (toStream m2))
536+ WAsyncVar -> newWAsyncVar st (concurrently (toStream m1) (toStream m2))
535537 _ -> error "illegal svar type"
536− unStream (fromSVar sv) (rstState st) stp sng yld
538+ foldStream st stp sng yld $ fromSVar sv
537539 where
538− concurrently ma mb = Stream $ \st stp sng yld -> do
540+ concurrently ma mb = mkStream $ \st stp sng yld -> do
539541 liftIO $ enqueue (fromJust $ streamVar st) mb
540− unStream ma st stp sng yld
542+ foldStreamShared st stp sng yld ma
541543
542544{-# INLINE joinStreamVarAsync #-}
543−joinStreamVarAsync :: MonadAsync m
544− => SVarStyle -> Stream m a -> Stream m a -> Stream m a
545−joinStreamVarAsync style m1 m2 = Stream $ \st stp sng yld ->
545+joinStreamVarAsync :: (IsStream t, MonadAsync m)
546+ => SVarStyle -> t m a -> t m a -> t m a
547+joinStreamVarAsync style m1 m2 = mkStream $ \st stp sng yld ->
546548 case streamVar st of
547− Just sv | svarStyle sv == style ->
548− liftIO (enqueue sv m2) >> unStream m1 st stp sng yld
549− _ -> unStream (forkSVarAsync style m1 m2) st stp sng yld
549+ Just sv | svarStyle sv == style -> do
550+ liftIO $ enqueue sv (toStream m2)
551+ foldStreamShared st stp sng yld m1
552+ _ -> foldStreamShared st stp sng yld (forkSVarAsync style m1 m2)
550553
551554------------------------------------------------------------------------------
552555-- Semigroup and Monoid style compositions for parallel actions
553556------------------------------------------------------------------------------
554557
555−{-# INLINE asyncS #-}
556−asyncS :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
557−asyncS = joinStreamVarAsync AsyncVar
558−
559558-- | Polymorphic version of the 'Semigroup' operation '<>' of 'AsyncT'.
560559-- Merges two streams possibly concurrently, preferring the
561560-- elements from the left one when available.
@@ -563,9 +562,7 @@ asyncS = joinStreamVarAsync AsyncVar
563562-- @since 0.2.0
564563{-# INLINE async #-}
565564async :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
566−async m1 m2 = fromStream $ Stream $ \st stp sng yld ->
567− unStream (joinStreamVarAsync AsyncVar (toStream m1) (toStream m2))
568− st stp sng yld
565+async = joinStreamVarAsync AsyncVar
569566
570567-- | Same as 'async'.
571568--
@@ -575,11 +572,16 @@ async m1 m2 = fromStream $ Stream $ \st stp sng yld ->
575572(<|) :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
576573(<|) = async
577574
575+-- IMPORTANT: using a monomorphically typed and SPECIALIZED consMAsync makes a
576+-- huge difference in the performance of consM in IsStream instance even we
577+-- have a SPECIALIZE in the instance.
578+--
578579-- | XXX we can implement it more efficienty by directly implementing instead
579580-- of combining streams using async.
580581{-# INLINE consMAsync #-}
581−consMAsync :: MonadAsync m => m a -> Stream m a -> Stream m a
582−consMAsync m r = K.yieldM m `asyncS` r
582+{-# SPECIALIZE consMAsync :: IO a -> AsyncT IO a -> AsyncT IO a #-}
583+consMAsync :: MonadAsync m => m a -> AsyncT m a -> AsyncT m a
584+consMAsync m r = fromStream $ K.yieldM m `async` (toStream r)
583585
584586------------------------------------------------------------------------------
585587-- AsyncT
@@ -652,21 +654,22 @@ asyncly = adapt
652654instance IsStream AsyncT where
653655 toStream = getAsyncT
654656 fromStream = AsyncT
655−
656− {-# INLINE consM #-}
657− {-# SPECIALIZE consM :: IO a -> AsyncT IO a -> AsyncT IO a #-}
658− consM m r = fromStream $ consMAsync m (toStream r)
659−
660− {-# INLINE (|:) #-}
661− {-# SPECIALIZE (|:) :: IO a -> AsyncT IO a -> AsyncT IO a #-}
662− (|:) = consM
657+ consM = consMAsync
658+ (|:) = consMAsync
663659
664660------------------------------------------------------------------------------
665661-- Semigroup
666662------------------------------------------------------------------------------
667663
664+-- Monomorphically typed version of "async" for better performance of Semigroup
665+-- instance.
666+{-# INLINE mappendAsync #-}
667+{-# SPECIALIZE mappendAsync :: AsyncT IO a -> AsyncT IO a -> AsyncT IO a #-}
668+mappendAsync :: MonadAsync m => AsyncT m a -> AsyncT m a -> AsyncT m a
669+mappendAsync m1 m2 = fromStream $ async (toStream m1) (toStream m2)
670+
668671instance MonadAsync m => Semigroup (AsyncT m a) where
669− (<>) = async
672+ (<>) = mappendAsync
670673
671674------------------------------------------------------------------------------
672675-- Monoid
@@ -680,30 +683,40 @@ instance MonadAsync m => Monoid (AsyncT m a) where
680683-- Monad
681684------------------------------------------------------------------------------
682685
686+{-# INLINE bindAsync #-}
687+{-# SPECIALIZE bindAsync :: AsyncT IO a -> (a -> AsyncT IO b) -> AsyncT IO b #-}
688+bindAsync :: MonadAsync m => AsyncT m a -> (a -> AsyncT m b) -> AsyncT m b
689+bindAsync m f = fromStream $ K.bindWith async (adapt m) (\a -> adapt $ f a)
690+
683691instance MonadAsync m => Monad (AsyncT m) where
684692 return = pure
685− (AsyncT m) >>= f = AsyncT $ K.bindWith asyncS m (getAsyncT . f)
693+ (>>=) = bindAsync
694+
695+{-# INLINE apAsync #-}
696+{-# SPECIALIZE apAsync :: AsyncT IO (a -> b) -> AsyncT IO a -> AsyncT IO b #-}
697+apAsync :: MonadAsync m => AsyncT m (a -> b) -> AsyncT m a -> AsyncT m b
698+apAsync mf m = ap (adapt mf) (adapt m)
699+
700+instance (Monad m, MonadAsync m) => Applicative (AsyncT m) where
701+ pure = AsyncT . K.yield
702+ (<*>) = apAsync
686703
687704------------------------------------------------------------------------------
688705-- Other instances
689706------------------------------------------------------------------------------
690707
691−MONAD_APPLICATIVE_INSTANCE(AsyncT,MONADPARALLEL)
692708MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
693709
694710------------------------------------------------------------------------------
695711-- WAsyncT
696712------------------------------------------------------------------------------
697713
698−{-# INLINE wAsyncS #-}
699−wAsyncS :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
700−wAsyncS = joinStreamVarAsync WAsyncVar
701−
702714-- | XXX we can implement it more efficienty by directly implementing instead
703715-- of combining streams using wAsync.
704716{-# INLINE consMWAsync #-}
705−consMWAsync :: MonadAsync m => m a -> Stream m a -> Stream m a
706−consMWAsync m r = K.yieldM m `wAsyncS` r
717+{-# SPECIALIZE consMWAsync :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
718+consMWAsync :: MonadAsync m => m a -> WAsyncT m a -> WAsyncT m a
719+consMWAsync m r = fromStream $ K.yieldM m `wAsync` (toStream r)
707720
708721-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WAsyncT'.
709722-- Merges two streams concurrently choosing elements from both fairly.
@@ -711,8 +724,7 @@ consMWAsync m r = K.yieldM m `wAsyncS` r
711724-- @since 0.2.0
712725{-# INLINE wAsync #-}
713726wAsync :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
714−wAsync m1 m2 = fromStream $ Stream $ \st stp sng yld ->
715− unStream (wAsyncS (toStream m1) (toStream m2)) st stp sng yld
727+wAsync = joinStreamVarAsync WAsyncVar
716728
717729-- | Wide async composition or async composition with breadth first traversal.
718730-- The Semigroup instance of 'WAsyncT' concurrently /traverses/ the composed
@@ -779,21 +791,20 @@ wAsyncly = adapt
779791instance IsStream WAsyncT where
780792 toStream = getWAsyncT
781793 fromStream = WAsyncT
782−
783− {-# INLINE consM #-}
784− {-# SPECIALIZE consM :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
785− consM m r = fromStream $ consMWAsync m (toStream r)
786−
787− {-# INLINE (|:) #-}
788− {-# SPECIALIZE (|:) :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
789− (|:) = consM
794+ consM = consMWAsync
795+ (|:) = consMWAsync
790796
791797------------------------------------------------------------------------------
792798-- Semigroup
793799------------------------------------------------------------------------------
794800
801+{-# INLINE mappendWAsync #-}
802+{-# SPECIALIZE mappendWAsync :: WAsyncT IO a -> WAsyncT IO a -> WAsyncT IO a #-}
803+mappendWAsync :: MonadAsync m => WAsyncT m a -> WAsyncT m a -> WAsyncT m a
804+mappendWAsync m1 m2 = fromStream $ wAsync (toStream m1) (toStream m2)
805+
795806instance MonadAsync m => Semigroup (WAsyncT m a) where
796− (<>) = wAsync
807+ (<>) = mappendWAsync
797808
798809------------------------------------------------------------------------------
799810-- Monoid
@@ -807,14 +818,26 @@ instance MonadAsync m => Monoid (WAsyncT m a) where
807818-- Monad
808819------------------------------------------------------------------------------
809820
821+{-# INLINE bindWAsync #-}
822+{-# SPECIALIZE bindWAsync :: WAsyncT IO a -> (a -> WAsyncT IO b) -> WAsyncT IO b #-}
823+bindWAsync :: MonadAsync m => WAsyncT m a -> (a -> WAsyncT m b) -> WAsyncT m b
824+bindWAsync m f = fromStream $ K.bindWith wAsync (adapt m) (\a -> adapt $ f a)
825+
810826instance MonadAsync m => Monad (WAsyncT m) where
811827 return = pure
812− (WAsyncT m) >>= f =
813− WAsyncT $ K.bindWith wAsyncS m (getWAsyncT . f)
828+ (>>=) = bindWAsync
829+
830+{-# INLINE apWAsync #-}
831+{-# SPECIALIZE apWAsync :: WAsyncT IO (a -> b) -> WAsyncT IO a -> WAsyncT IO b #-}
832+apWAsync :: MonadAsync m => WAsyncT m (a -> b) -> WAsyncT m a -> WAsyncT m b
833+apWAsync mf m = ap (adapt mf) (adapt m)
834+
835+instance (Monad m, MonadAsync m) => Applicative (WAsyncT m) where
836+ pure = WAsyncT . K.yield
837+ (<*>) = apWAsync
814838
815839------------------------------------------------------------------------------
816840-- Other instances
817841------------------------------------------------------------------------------
818842
819−MONAD_APPLICATIVE_INSTANCE(WAsyncT,MONADPARALLEL)
820843MONAD_COMMON_INSTANCES(WAsyncT, MONADPARALLEL)
src/Streamly/Streams/Combinators.hs+12−12
@@ -52,8 +52,8 @@ import Streamly.Streams.Serial (SerialT)
5252-- @since 0.4.0
5353{-# INLINE_NORMAL maxThreads #-}
5454maxThreads :: IsStream t => Int -> t m a -> t m a
55−maxThreads n m = fromStream $ Stream $ \st stp sng yld ->
56− unStream (toStream m) (setMaxThreads n st) stp sng yld
55+maxThreads n m = mkStream $ \st stp sng yld ->
56+ foldStreamShared (setMaxThreads n st) stp sng yld m
5757
5858{-
5959{-# RULES "maxThreadsSerial serial" maxThreads = maxThreadsSerial #-}
@@ -77,8 +77,8 @@ maxThreadsSerial _ = id
7777-- @since 0.4.0
7878{-# INLINE_NORMAL maxBuffer #-}
7979maxBuffer :: IsStream t => Int -> t m a -> t m a
80−maxBuffer n m = fromStream $ Stream $ \st stp sng yld ->
81− unStream (toStream m) (setMaxBuffer n st) stp sng yld
80+maxBuffer n m = mkStream $ \st stp sng yld ->
81+ foldStreamShared (setMaxBuffer n st) stp sng yld m
8282
8383{-
8484{-# RULES "maxBuffer serial" maxBuffer = maxBufferSerial #-}
@@ -101,7 +101,7 @@ maxBufferSerial _ = id
101101-- @since 0.5.0
102102{-# INLINE_NORMAL rate #-}
103103rate :: IsStream t => Maybe Rate -> t m a -> t m a
104−rate r m = fromStream $ Stream $ \st stp sng yld ->
104+rate r m = mkStream $ \st stp sng yld ->
105105 case r of
106106 Just (Rate low goal _ _) | goal < low ->
107107 error "rate: Target rate cannot be lower than minimum rate."
@@ -109,7 +109,7 @@ rate r m = fromStream $ Stream $ \st stp sng yld ->
109109 error "rate: Target rate cannot be greater than maximum rate."
110110 Just (Rate low _ high _) | low > high ->
111111 error "rate: Minimum rate cannot be greater than maximum rate."
112− _ -> unStream (toStream m) (setStreamRate r st) stp sng yld
112+ _ -> foldStreamShared (setStreamRate r st) stp sng yld m
113113
114114-- XXX implement for serial streams as well, as a simple delay
115115
@@ -181,8 +181,8 @@ constRate r = rate (Just $ Rate r r r 0)
181181--
182182{-# INLINE_NORMAL _serialLatency #-}
183183_serialLatency :: IsStream t => Int -> t m a -> t m a
184−_serialLatency n m = fromStream $ Stream $ \st stp sng yld ->
185− unStream (toStream m) (setStreamLatency n st) stp sng yld
184+_serialLatency n m = mkStream $ \st stp sng yld ->
185+ foldStreamShared (setStreamLatency n st) stp sng yld m
186186
187187{-
188188{-# RULES "serialLatency serial" _serialLatency = serialLatencySerial #-}
@@ -196,8 +196,8 @@ serialLatencySerial _ = id
196196-- inherited by everything in enclosed scope.
197197{-# INLINE_NORMAL maxYields #-}
198198maxYields :: IsStream t => Maybe Int64 -> t m a -> t m a
199−maxYields n m = fromStream $ Stream $ \st stp sng yld ->
200− unStream (toStream m) (setYieldLimit n st) stp sng yld
199+maxYields n m = mkStream $ \st stp sng yld ->
200+ foldStreamShared (setYieldLimit n st) stp sng yld m
201201
202202{-# RULES "maxYields serial" maxYields = maxYieldsSerial #-}
203203maxYieldsSerial :: Maybe Int64 -> SerialT m a -> SerialT m a
@@ -212,5 +212,5 @@ printState st = liftIO $ do
212212
213213-- | Print debug information about an SVar when the stream ends
214214inspectMode :: IsStream t => t m a -> t m a
215−inspectMode m = fromStream $ Stream $ \st stp sng yld ->
216− unStream (toStream m) (setInspectMode st) stp sng yld
215+inspectMode m = mkStream $ \st stp sng yld ->
216+ foldStreamShared (setInspectMode st) stp sng yld m
src/Streamly/Streams/Parallel.hs+36−29
@@ -49,7 +49,8 @@ import Prelude hiding (map)
4949import Streamly.Streams.SVar (fromSVar)
5050import Streamly.Streams.Serial (map)
5151import Streamly.SVar
52−import Streamly.Streams.StreamK (IsStream(..), Stream(..), adapt)
52+import Streamly.Streams.StreamK (IsStream(..), Stream, mkStream, foldStream,
53+ foldStreamShared, adapt)
5354import qualified Streamly.Streams.StreamK as K
5455
5556#include "Instances.hs"
@@ -62,7 +63,7 @@ import qualified Streamly.Streams.StreamK as K
6263runOne
6364 :: MonadIO m
6465 => State Stream m a -> Stream m a -> Maybe WorkerInfo -> m ()
65−runOne st m winfo = unStream m st stop single yieldk
66+runOne st m winfo = foldStreamShared st yieldk single stop m
6667
6768 where
6869
@@ -87,32 +88,29 @@ runOne st m winfo = unStream m st stop single yieldk
8788 >> withLimitCheck (void $ liftIO $ mrun $ runOne st r winfo)
8889
8990{-# NOINLINE forkSVarPar #-}
90−forkSVarPar :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
91−forkSVarPar m r = Stream $ \st stp sng yld -> do
91+forkSVarPar :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
92+forkSVarPar m r = mkStream $ \st yld sng stp -> do
9293 sv <- newParallelVar st
93− pushWorkerPar sv (runOne st{streamVar = Just sv} m)
94− pushWorkerPar sv (runOne st{streamVar = Just sv} r)
95− unStream (fromSVar sv) (rstState st) stp sng yld
94+ pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream m)
95+ pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream r)
96+ foldStream st yld sng stp (fromSVar sv)
9697
9798{-# INLINE joinStreamVarPar #-}
98−joinStreamVarPar :: MonadAsync m
99− => SVarStyle -> Stream m a -> Stream m a -> Stream m a
100−joinStreamVarPar style m1 m2 = Stream $ \st stp sng yld ->
99+joinStreamVarPar :: (IsStream t, MonadAsync m)
100+ => SVarStyle -> t m a -> t m a -> t m a
101+joinStreamVarPar style m1 m2 = mkStream $ \st yld sng stp ->
101102 case streamVar st of
102103 Just sv | svarStyle sv == style -> do
103− pushWorkerPar sv (runOne st m1)
104− unStream m2 st stp sng yld
105− _ -> unStream (forkSVarPar m1 m2) st stp sng yld
106−
107−{-# INLINE parallelStream #-}
108−parallelStream :: MonadAsync m => Stream m a -> Stream m a -> Stream m a
109−parallelStream = joinStreamVarPar ParallelVar
104+ pushWorkerPar sv (runOne st $ toStream m1)
105+ foldStreamShared st yld sng stp m2
106+ _ -> foldStreamShared st yld sng stp (forkSVarPar m1 m2)
110107
111108-- | XXX we can implement it more efficienty by directly implementing instead
112109-- of combining streams using parallel.
113110{-# INLINE consMParallel #-}
114−consMParallel :: MonadAsync m => m a -> Stream m a -> Stream m a
115−consMParallel m r = K.yieldM m `parallelStream` r
111+{-# SPECIALIZE consMParallel :: IO a -> ParallelT IO a -> ParallelT IO a #-}
112+consMParallel :: MonadAsync m => m a -> ParallelT m a -> ParallelT m a
113+consMParallel m r = fromStream $ K.yieldM m `parallel` (toStream r)
116114
117115-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'
118116-- Merges two streams concurrently.
@@ -120,9 +118,7 @@ consMParallel m r = K.yieldM m `parallelStream` r
120118-- @since 0.2.0
121119{-# INLINE parallel #-}
122120parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
123−parallel m1 m2 = fromStream $ Stream $ \st stp sng yld ->
124− unStream (parallelStream (toStream m1) (toStream m2))
125− st stp sng yld
121+parallel = joinStreamVarPar ParallelVar
126122
127123------------------------------------------------------------------------------
128124-- Convert a stream to parallel
@@ -140,10 +136,10 @@ mkParallel m = do
140136
141137{-# INLINE applyWith #-}
142138applyWith :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
143−applyWith f m = fromStream $ Stream $ \st stp sng yld -> do
144− sv <- newParallelVar (rstState st)
139+applyWith f m = mkStream $ \st yld sng stp -> do
140+ sv <- newParallelVar (adaptState st)
145141 pushWorkerPar sv (runOne st{streamVar = Just sv} (toStream m))
146− unStream (toStream $ f $ fromSVar sv) (rstState st) stp sng yld
142+ foldStream st yld sng stp $ f $ fromSVar sv
147143
148144------------------------------------------------------------------------------
149145-- Stream runner concurrent function application
@@ -345,7 +341,7 @@ instance IsStream ParallelT where
345341
346342 {-# INLINE consM #-}
347343 {-# SPECIALIZE consM :: IO a -> ParallelT IO a -> ParallelT IO a #-}
348− consM m r = fromStream $ consMParallel m (toStream r)
344+ consM = consMParallel
349345
350346 {-# INLINE (|:) #-}
351347 {-# SPECIALIZE (|:) :: IO a -> ParallelT IO a -> ParallelT IO a #-}
@@ -355,8 +351,13 @@ instance IsStream ParallelT where
355351-- Semigroup
356352------------------------------------------------------------------------------
357353
354+{-# INLINE mappendParallel #-}
355+{-# SPECIALIZE mappendParallel :: ParallelT IO a -> ParallelT IO a -> ParallelT IO a #-}
356+mappendParallel :: MonadAsync m => ParallelT m a -> ParallelT m a -> ParallelT m a
357+mappendParallel m1 m2 = fromStream $ parallel (toStream m1) (toStream m2)
358+
358359instance MonadAsync m => Semigroup (ParallelT m a) where
359− (<>) = parallel
360+ (<>) = mappendParallel
360361
361362------------------------------------------------------------------------------
362363-- Monoid
@@ -370,10 +371,16 @@ instance MonadAsync m => Monoid (ParallelT m a) where
370371-- Monad
371372------------------------------------------------------------------------------
372373
374+{-# INLINE bindParallel #-}
375+{-# SPECIALIZE bindParallel :: ParallelT IO a -> (a -> ParallelT IO b) -> ParallelT IO b #-}
376+bindParallel :: MonadAsync m => ParallelT m a -> (a -> ParallelT m b) -> ParallelT m b
377+bindParallel m f = fromStream $ K.bindWith parallel (K.adapt m) (\a -> K.adapt $ f a)
378+
373379instance MonadAsync m => Monad (ParallelT m) where
374380 return = pure
375− (ParallelT m) >>= f
376− = ParallelT $ K.bindWith parallelStream m (getParallelT . f)
381+ (>>=) = bindParallel
382+
383+-- XXX Specialize the applicative instance
377384
378385------------------------------------------------------------------------------
379386-- Other instances
src/Streamly/Streams/SVar.hs+10−9
@@ -38,12 +38,12 @@ printSVar sv how = do
3838-- | Pull a stream from an SVar.
3939{-# NOINLINE fromStreamVar #-}
4040fromStreamVar :: MonadAsync m => SVar Stream m a -> Stream m a
41−fromStreamVar sv = Stream $ \st stp sng yld -> do
41+fromStreamVar sv = mkStream $ \st yld sng stp -> do
4242 list <- readOutputQ sv
4343 -- Reversing the output is important to guarantee that we process the
4444 -- outputs in the same order as they were generated by the constituent
4545 -- streams.
46− unStream (processEvents $ reverse list) (rstState st) stp sng yld
46+ foldStream st yld sng stp $ processEvents $ reverse list
4747
4848 where
4949
@@ -55,36 +55,37 @@ fromStreamVar sv = Stream $ \st stp sng yld -> do
5555 stp
5656
5757 {-# INLINE processEvents #-}
58− processEvents [] = Stream $ \st stp sng yld -> do
58+ processEvents [] = mkStream $ \st yld sng stp -> do
5959 done <- postProcess sv
6060 if done
6161 then allDone stp
62− else unStream (fromStreamVar sv) (rstState st) stp sng yld
62+ else foldStream st yld sng stp $ fromStreamVar sv
6363
64− processEvents (ev : es) = Stream $ \st stp sng yld -> do
64+ processEvents (ev : es) = mkStream $ \st yld sng stp -> do
6565 let rest = processEvents es
6666 case ev of
6767 ChildYield a -> yld a rest
6868 ChildStop tid e -> do
6969 accountThread sv tid
7070 case e of
71− Nothing -> unStream rest (rstState st) stp sng yld
71+ Nothing -> foldStream st yld sng stp rest
7272 Just ex ->
7373 case fromException ex of
7474 Just ThreadAbort ->
75− unStream rest (rstState st) stp sng yld
75+ foldStream st yld sng stp rest
7676 Nothing -> liftIO (cleanupSVar sv) >> throwM ex
7777
7878{-# INLINE fromSVar #-}
7979fromSVar :: (MonadAsync m, IsStream t) => SVar Stream m a -> t m a
8080fromSVar sv =
81− fromStream $ Stream $ \st stp sng yld -> do
81+ mkStream $ \st yld sng stp -> do
8282 ref <- liftIO $ newIORef ()
8383 _ <- liftIO $ mkWeakIORef ref hook
8484 -- We pass a copy of sv to fromStreamVar, so that we know that it has
8585 -- no other references, when that copy gets garbage collected "ref"
8686 -- will get garbage collected and our hook will be called.
87− unStream (fromStreamVar sv{svarRef = Just ref}) st stp sng yld
87+ foldStreamShared st yld sng stp $
88+ fromStream $ fromStreamVar sv{svarRef = Just ref}
8889 where
8990
9091 hook = do
src/Streamly/Streams/Serial.hs+22−51
@@ -24,7 +24,7 @@ module Streamly.Streams.Serial
2424 SerialT
2525 , StreamT -- deprecated
2626 , Serial
27− , serial
27+ , K.serial
2828 , serially
2929
3030 -- * Serial interleaving stream
@@ -60,8 +60,8 @@ import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
6060 readListPrecDefault)
6161import Prelude hiding (map, mapM)
6262
63−import Streamly.SVar (rstState)
64−import Streamly.Streams.StreamK (IsStream(..), adapt, Stream(..))
63+import Streamly.Streams.StreamK (IsStream(..), adapt, Stream, mkStream,
64+ foldStream)
6565import qualified Streamly.Streams.Prelude as P
6666import qualified Streamly.Streams.StreamK as K
6767import qualified Streamly.Streams.StreamD as D
@@ -149,34 +149,16 @@ type StreamT = SerialT
149149serially :: IsStream t => SerialT m a -> t m a
150150serially = adapt
151151
152+{-# INLINE consMSerial #-}
153+{-# SPECIALIZE consMSerial :: IO a -> SerialT IO a -> SerialT IO a #-}
154+consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
155+consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
156+
152157instance IsStream SerialT where
153158 toStream = getSerialT
154159 fromStream = SerialT
155−
156− {-# INLINE consM #-}
157− {-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
158− consM :: Monad m => m a -> SerialT m a -> SerialT m a
159− consM m r = fromStream $ K.consMSerial m (toStream r)
160−
161− {-# INLINE (|:) #-}
162− {-# SPECIALIZE (|:) :: IO a -> SerialT IO a -> SerialT IO a #-}
163− (|:) :: Monad m => m a -> SerialT m a -> SerialT m a
164− m |: r = fromStream $ K.consMSerial m (toStream r)
165−
166−------------------------------------------------------------------------------
167−-- Semigroup
168−------------------------------------------------------------------------------
169−
170−-- | Polymorphic version of the 'Semigroup' operation '<>' of 'SerialT'.
171−-- Appends two streams sequentially, yielding all elements from the first
172−-- stream, and then all elements from the second stream.
173−--
174−-- @since 0.2.0
175−{-# INLINE serial #-}
176−serial :: IsStream t => t m a -> t m a -> t m a
177−serial m1 m2 = fromStream $ Stream $ \st stp sng yld ->
178− unStream (K.serial (toStream m1) (toStream m2))
179− (rstState st) stp sng yld
160+ consM = consMSerial
161+ (|:) = consMSerial
180162
181163------------------------------------------------------------------------------
182164-- Monad
@@ -184,11 +166,7 @@ serial m1 m2 = fromStream $ Stream $ \st stp sng yld ->
184166
185167instance Monad m => Monad (SerialT m) where
186168 return = pure
187− (SerialT (Stream m)) >>= f = SerialT $ Stream $ \st stp sng yld ->
188− let run x = unStream x (rstState st) stp sng yld
189− single a = run $ toStream (f a)
190− yieldk a r = run $ toStream $ f a <> (fromStream r >>= f)
191− in m (rstState st) stp single yieldk
169+ (>>=) = K.bindWith K.serial
192170
193171------------------------------------------------------------------------------
194172-- Other instances
@@ -286,6 +264,9 @@ wSerially = adapt
286264interleaving :: IsStream t => WSerialT m a -> t m a
287265interleaving = wSerially
288266
267+consMWSerial :: Monad m => m a -> WSerialT m a -> WSerialT m a
268+consMWSerial m ms = fromStream $ K.consMStream m (toStream ms)
269+
289270instance IsStream WSerialT where
290271 toStream = getWSerialT
291272 fromStream = WSerialT
@@ -293,34 +274,28 @@ instance IsStream WSerialT where
293274 {-# INLINE consM #-}
294275 {-# SPECIALIZE consM :: IO a -> WSerialT IO a -> WSerialT IO a #-}
295276 consM :: Monad m => m a -> WSerialT m a -> WSerialT m a
296− consM m r = fromStream $ K.consMSerial m (toStream r)
277+ consM = consMWSerial
297278
298279 {-# INLINE (|:) #-}
299280 {-# SPECIALIZE (|:) :: IO a -> WSerialT IO a -> WSerialT IO a #-}
300281 (|:) :: Monad m => m a -> WSerialT m a -> WSerialT m a
301− m |: r = fromStream $ K.consMSerial m (toStream r)
282+ (|:) = consMWSerial
302283
303284------------------------------------------------------------------------------
304285-- Semigroup
305286------------------------------------------------------------------------------
306287
307−{-# INLINE interleave #-}
308−interleave :: Stream m a -> Stream m a -> Stream m a
309−interleave m1 m2 = Stream $ \st stp sng yld -> do
310− let stop = unStream m2 (rstState st) stp sng yld
311− single a = yld a m2
312− yieldk a r = yld a (interleave m2 r)
313− unStream m1 (rstState st) stop single yieldk
314−
315288-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WSerialT'.
316289-- Interleaves two streams, yielding one element from each stream alternately.
317290--
318291-- @since 0.2.0
319292{-# INLINE wSerial #-}
320293wSerial :: IsStream t => t m a -> t m a -> t m a
321−wSerial m1 m2 = fromStream $ Stream $ \st stp sng yld ->
322− unStream (interleave (toStream m1) (toStream m2))
323− (rstState st) stp sng yld
294+wSerial m1 m2 = mkStream $ \st yld sng stp -> do
295+ let stop = foldStream st yld sng stp m2
296+ single a = yld a m2
297+ yieldk a r = yld a (wSerial m2 r)
298+ foldStream st yieldk single stop m1
324299
325300instance Semigroup (WSerialT m a) where
326301 (<>) = wSerial
@@ -349,11 +324,7 @@ instance Monoid (WSerialT m a) where
349324
350325instance Monad m => Monad (WSerialT m) where
351326 return = pure
352− (WSerialT (Stream m)) >>= f = WSerialT $ Stream $ \st stp sng yld ->
353− let run x = unStream x (rstState st) stp sng yld
354− single a = run $ toStream (f a)
355− yieldk a r = run $ toStream $ f a <> (fromStream r >>= f)
356− in m (rstState st) stp single yieldk
327+ (>>=) = K.bindWith wSerial
357328
358329------------------------------------------------------------------------------
359330-- Other instances
src/Streamly/Streams/StreamD.hs+43−83
@@ -5,6 +5,8 @@
55{-# LANGUAGE FlexibleContexts #-}
66{-# LANGUAGE FlexibleInstances #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PatternSynonyms #-}
9+{-# LANGUAGE ViewPatterns #-}
810{-# LANGUAGE RankNTypes #-}
911
1012#include "inline.hs"
@@ -197,30 +199,11 @@ import Prelude
197199 notElem, null, head, tail, zipWith, lookup, foldr1, sequence,
198200 (!!), scanl, scanl1, concatMap, replicate, enumFromTo)
199201
200−import Streamly.SVar (MonadAsync, State(..), defState, rstState)
202+import Streamly.SVar (MonadAsync, defState, adaptState)
201203
204+import Streamly.Streams.StreamD.Type
202205import qualified Streamly.Streams.StreamK as K
203206
204−------------------------------------------------------------------------------
205−-- The direct style stream type
206−------------------------------------------------------------------------------
207−
208−-- | A stream is a succession of 'Step's. A 'Yield' produces a single value and
209−-- the next state of the stream. 'Stop' indicates there are no more values in
210−-- the stream.
211−data Step s a = Yield a s | Skip s | Stop
212−
213−instance Functor (Step s) where
214− {-# INLINE fmap #-}
215− fmap f (Yield x s) = Yield (f x) s
216− fmap _ (Skip s) = Skip s
217− fmap _ Stop = Stop
218−
219−-- gst = global state
220−-- | A stream consists of a step function that generates the next step given a
221−-- current state, and the current state.
222−data Stream m a = forall s. Stream (State K.Stream m a -> s -> m (Step s a)) s
223−
224207------------------------------------------------------------------------------
225208-- Construction
226209------------------------------------------------------------------------------
@@ -238,7 +221,7 @@ cons x (Stream step state) = Stream step1 Nothing
238221 {-# INLINE_LATE step1 #-}
239222 step1 _ Nothing = return $ Yield x (Just state)
240223 step1 gst (Just st) = do
241− r <- step (rstState gst) st
224+ r <- step gst st
242225 return $
243226 case r of
244227 Yield a s -> Yield a (Just s)
@@ -252,7 +235,7 @@ cons x (Stream step state) = Stream step1 Nothing
252235-- Does not fuse, has the same performance as the StreamK version.
253236{-# INLINE_NORMAL uncons #-}
254237uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
255−uncons (Stream step state) = go state
238+uncons (UnStream step state) = go state
256239 where
257240 go st = do
258241 r <- step defState st
@@ -492,7 +475,6 @@ fromList = Stream step
492475 step _ (x:xs) = return $ Yield x xs
493476 step _ [] = return Stop
494477
495−-- XXX pass the state to streamD
496478{-# INLINE_LATE fromStreamK #-}
497479fromStreamK :: Monad m => K.Stream m a -> Stream m a
498480fromStreamK = Stream step
@@ -501,7 +483,7 @@ fromStreamK = Stream step
501483 let stop = return Stop
502484 single a = return $ Yield a K.nil
503485 yieldk a r = return $ Yield a r
504− in K.unStream m1 gst stop single yieldk
486+ in K.foldStreamShared gst yieldk single stop m1
505487
506488{-# INLINE toStreamD #-}
507489toStreamD :: (K.IsStream t, Monad m) => t m a -> Stream m a
@@ -593,7 +575,7 @@ head (Stream step state) = go state
593575-- Does not fuse, has the same performance as the StreamK version.
594576{-# INLINE_NORMAL tail #-}
595577tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
596−tail (Stream step state) = go state
578+tail (UnStream step state) = go state
597579 where
598580 go st = do
599581 r <- step defState st
@@ -773,7 +755,7 @@ findIndices p (Stream step state) = Stream step' (state, 0)
773755 where
774756 {-# INLINE_LATE step' #-}
775757 step' gst (st, i) = do
776− r <- step (rstState gst) st
758+ r <- step (adaptState gst) st
777759 return $ case r of
778760 Yield x s -> if p x then Yield i (s, i+1) else Skip (s, i+1)
779761 Skip s -> Skip (s, i+1)
@@ -785,7 +767,7 @@ concatMapM f (Stream step state) = Stream step' (Left state)
785767 where
786768 {-# INLINE_LATE step' #-}
787769 step' gst (Left st) = do
788− r <- step (rstState gst) st
770+ r <- step (adaptState gst) st
789771 case r of
790772 Yield a s -> do
791773 b_stream <- f a
@@ -793,7 +775,10 @@ concatMapM f (Stream step state) = Stream step' (Left state)
793775 Skip s -> return $ Skip (Left s)
794776 Stop -> return Stop
795777
796− step' _ (Right (Stream inner_step inner_st, st)) = do
778+ -- XXX using the pattern synonym Stream causes a major performance issue
779+ -- here even if the synonym does not include a adaptState call. Need to
780+ -- find out why. Is that something to be fixed in GHC?
781+ step' _ (Right (UnStream inner_step inner_st, st)) = do
797782 r <- inner_step defState inner_st
798783 case r of
799784 Yield b inner_s ->
@@ -897,11 +882,11 @@ toList = foldr (:) []
897882toStreamK :: Monad m => Stream m a -> K.Stream m a
898883toStreamK (Stream step state) = go state
899884 where
900− go st = K.Stream $ \gst stp sng yld -> do
885+ go st = K.mkStream $ \gst yld sng stp -> do
901886 r <- step gst st
902887 case r of
903888 Yield x s -> yld x (go s)
904− Skip s -> K.unStream (go s) gst stp sng yld
889+ Skip s -> K.foldStreamShared gst yld sng stp $ go s
905890 Stop -> stp
906891
907892#ifndef DISABLE_FUSION
@@ -935,7 +920,7 @@ prescanlM' f mz (Stream step state) = Stream step' (state, mz)
935920 where
936921 {-# INLINE_LATE step' #-}
937922 step' gst (st, prev) = do
938− r <- step (rstState gst) st
923+ r <- step (adaptState gst) st
939924 case r of
940925 Yield x s -> do
941926 acc <- prev
@@ -963,7 +948,7 @@ postscanlM' fstep begin (Stream step state) =
963948 where
964949 {-# INLINE_LATE step' #-}
965950 step' gst (st, acc) = acc `seq` do
966− r <- step (rstState gst) st
951+ r <- step (adaptState gst) st
967952 case r of
968953 Yield x s -> do
969954 y <- fstep acc x
@@ -981,7 +966,7 @@ postscanlM fstep begin (Stream step state) = Stream step' (state, begin)
981966 where
982967 {-# INLINE_LATE step' #-}
983968 step' gst (st, acc) = do
984− r <- step (rstState gst) st
969+ r <- step (adaptState gst) st
985970 case r of
986971 Yield x s -> do
987972 y <- fstep acc x
@@ -1015,14 +1000,14 @@ scanl1M fstep (Stream step state) = Stream step' (state, Nothing)
10151000 where
10161001 {-# INLINE_LATE step' #-}
10171002 step' gst (st, Nothing) = do
1018− r <- step (rstState gst) st
1003+ r <- step gst st
10191004 case r of
10201005 Yield x s -> return $ Yield x (s, Just x)
10211006 Skip s -> return $ Skip (s, Nothing)
10221007 Stop -> return Stop
10231008
10241009 step' gst (st, Just acc) = do
1025− r <- step (rstState gst) st
1010+ r <- step gst st
10261011 case r of
10271012 Yield y s -> do
10281013 z <- fstep acc y
@@ -1040,14 +1025,14 @@ scanl1M' fstep (Stream step state) = Stream step' (state, Nothing)
10401025 where
10411026 {-# INLINE_LATE step' #-}
10421027 step' gst (st, Nothing) = do
1043− r <- step (rstState gst) st
1028+ r <- step gst st
10441029 case r of
10451030 Yield x s -> x `seq` return $ Yield x (s, Just x)
10461031 Skip s -> return $ Skip (s, Nothing)
10471032 Stop -> return Stop
10481033
10491034 step' gst (st, Just acc) = acc `seq` do
1050− r <- step (rstState gst) st
1035+ r <- step gst st
10511036 case r of
10521037 Yield y s -> do
10531038 z <- fstep acc y
@@ -1069,7 +1054,7 @@ take n (Stream step state) = n `seq` Stream step' (state, 0)
10691054 where
10701055 {-# INLINE_LATE step' #-}
10711056 step' gst (st, i) | i < n = do
1072− r <- step (rstState gst) st
1057+ r <- step gst st
10731058 return $ case r of
10741059 Yield x s -> Yield x (s, i + 1)
10751060 Skip s -> Skip (s, i)
@@ -1082,7 +1067,7 @@ takeWhileM f (Stream step state) = Stream step' state
10821067 where
10831068 {-# INLINE_LATE step' #-}
10841069 step' gst st = do
1085− r <- step (rstState gst) st
1070+ r <- step gst st
10861071 case r of
10871072 Yield x s -> do
10881073 b <- f x
@@ -1101,7 +1086,7 @@ drop n (Stream step state) = Stream step' (state, Just n)
11011086 {-# INLINE_LATE step' #-}
11021087 step' gst (st, Just i)
11031088 | i > 0 = do
1104− r <- step (rstState gst) st
1089+ r <- step gst st
11051090 return $
11061091 case r of
11071092 Yield _ s -> Skip (s, Just (i - 1))
@@ -1110,7 +1095,7 @@ drop n (Stream step state) = Stream step' (state, Just n)
11101095 | otherwise = return $ Skip (st, Nothing)
11111096
11121097 step' gst (st, Nothing) = do
1113− r <- step (rstState gst) st
1098+ r <- step gst st
11141099 return $
11151100 case r of
11161101 Yield x s -> Yield x (s, Nothing)
@@ -1128,7 +1113,7 @@ dropWhileM f (Stream step state) = Stream step' (DropWhileDrop state)
11281113 where
11291114 {-# INLINE_LATE step' #-}
11301115 step' gst (DropWhileDrop st) = do
1131− r <- step (rstState gst) st
1116+ r <- step gst st
11321117 case r of
11331118 Yield x s -> do
11341119 b <- f x
@@ -1139,7 +1124,7 @@ dropWhileM f (Stream step state) = Stream step' (DropWhileDrop state)
11391124 Stop -> return Stop
11401125
11411126 step' gst (DropWhileNext st) = do
1142− r <- step (rstState gst) st
1127+ r <- step gst st
11431128 case r of
11441129 Yield x s -> return $ Skip (DropWhileYield x s)
11451130 Skip s -> return $ Skip (DropWhileNext s)
@@ -1157,7 +1142,7 @@ filterM f (Stream step state) = Stream step' state
11571142 where
11581143 {-# INLINE_LATE step' #-}
11591144 step' gst st = do
1160− r <- step (rstState gst) st
1145+ r <- step gst st
11611146 case r of
11621147 Yield x s -> do
11631148 b <- f x
@@ -1177,13 +1162,13 @@ uniq (Stream step state) = Stream step' (Nothing, state)
11771162 where
11781163 {-# INLINE_LATE step' #-}
11791164 step' gst (Nothing, st) = do
1180− r <- step (rstState gst) st
1165+ r <- step gst st
11811166 case r of
11821167 Yield x s -> return $ Yield x (Just x, s)
11831168 Skip s -> return $ Skip (Nothing, s)
11841169 Stop -> return Stop
11851170 step' gst (Just x, st) = do
1186− r <- step (rstState gst) st
1171+ r <- step gst st
11871172 case r of
11881173 Yield y s | x == y -> return $ Skip (Just x, s)
11891174 | otherwise -> return $ Yield x (Just y, s)
@@ -1194,30 +1179,13 @@ uniq (Stream step state) = Stream step' (Nothing, state)
11941179-- Transformation by Mapping
11951180------------------------------------------------------------------------------
11961181
1197−-- | Map a monadic function over a 'Stream'
1198−{-# INLINE_NORMAL mapM #-}
1199−mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
1200−mapM f (Stream step state) = Stream step' state
1201− where
1202− {-# INLINE_LATE step' #-}
1203− step' gst st = do
1204− r <- step (rstState gst) st
1205− case r of
1206− Yield x s -> f x >>= \a -> return $ Yield a s
1207− Skip s -> return $ Skip s
1208− Stop -> return Stop
1209−
1210−{-# INLINE map #-}
1211−map :: Monad m => (a -> b) -> Stream m a -> Stream m b
1212−map f = mapM (return . f)
1213−
12141182{-# INLINE_NORMAL sequence #-}
12151183sequence :: Monad m => Stream m (m a) -> Stream m a
12161184sequence (Stream step state) = Stream step' state
12171185 where
12181186 {-# INLINE_LATE step' #-}
12191187 step' gst st = do
1220− r <- step (rstState gst) st
1188+ r <- step (adaptState gst) st
12211189 case r of
12221190 Yield x s -> x >>= \a -> return (Yield a s)
12231191 Skip s -> return $ Skip s
@@ -1233,7 +1201,7 @@ insertBy cmp a (Stream step state) = Stream step' (state, False, Nothing)
12331201 where
12341202 {-# INLINE_LATE step' #-}
12351203 step' gst (st, False, _) = do
1236− r <- step (rstState gst) st
1204+ r <- step gst st
12371205 case r of
12381206 Yield x s -> case cmp a x of
12391207 GT -> return $ Yield x (s, False, Nothing)
@@ -1244,7 +1212,7 @@ insertBy cmp a (Stream step state) = Stream step' (state, False, Nothing)
12441212 step' _ (_, True, Nothing) = return Stop
12451213
12461214 step' gst (st, True, Just prev) = do
1247− r <- step (rstState gst) st
1215+ r <- step gst st
12481216 case r of
12491217 Yield x s -> return $ Yield prev (s, True, Just x)
12501218 Skip s -> return $ Skip (s, True, Just prev)
@@ -1260,7 +1228,7 @@ deleteBy eq x (Stream step state) = Stream step' (state, False)
12601228 where
12611229 {-# INLINE_LATE step' #-}
12621230 step' gst (st, False) = do
1263− r <- step (rstState gst) st
1231+ r <- step gst st
12641232 case r of
12651233 Yield y s -> return $
12661234 if eq x y then Skip (s, True) else Yield y (s, False)
@@ -1268,7 +1236,7 @@ deleteBy eq x (Stream step state) = Stream step' (state, False)
12681236 Stop -> return Stop
12691237
12701238 step' gst (st, True) = do
1271− r <- step (rstState gst) st
1239+ r <- step gst st
12721240 case r of
12731241 Yield y s -> return $ Yield y (s, True)
12741242 Skip s -> return $ Skip (s, True)
@@ -1297,7 +1265,7 @@ indexed (Stream step state) = Stream step' (state, 0)
12971265 where
12981266 {-# INLINE_LATE step' #-}
12991267 step' gst (st, i) = i `seq` do
1300− r <- step (rstState gst) st
1268+ r <- step (adaptState gst) st
13011269 case r of
13021270 Yield x s -> return $ Yield (i, x) (s, i+1)
13031271 Skip s -> return $ Skip (s, i)
@@ -1309,7 +1277,7 @@ indexedR m (Stream step state) = Stream step' (state, m)
13091277 where
13101278 {-# INLINE_LATE step' #-}
13111279 step' gst (st, i) = i `seq` do
1312− r <- step (rstState gst) st
1280+ r <- step (adaptState gst) st
13131281 case r of
13141282 Yield x s -> let i' = i - 1
13151283 in
@@ -1324,7 +1292,7 @@ zipWithM f (Stream stepa ta) (Stream stepb tb) = Stream step (ta, tb, Nothing)
13241292 where
13251293 {-# INLINE_LATE step #-}
13261294 step gst (sa, sb, Nothing) = do
1327− r <- stepa (rstState gst) sa
1295+ r <- stepa (adaptState gst) sa
13281296 return $
13291297 case r of
13301298 Yield x sa' -> Skip (sa', sb, Just x)
@@ -1332,7 +1300,7 @@ zipWithM f (Stream stepa ta) (Stream stepb tb) = Stream step (ta, tb, Nothing)
13321300 Stop -> Stop
13331301
13341302 step gst (sa, sb, Just x) = do
1335− r <- stepb (rstState gst) sb
1303+ r <- stepb (adaptState gst) sb
13361304 case r of
13371305 Yield y sb' -> do
13381306 z <- f x y
@@ -1423,14 +1391,14 @@ mergeByM cmp (Stream stepa ta) (Stream stepb tb) =
14231391
14241392 -- one of the values is missing, and the corresponding stream is running
14251393 step gst (Just sa, sb, Nothing, b) = do
1426− r <- stepa (rstState gst) sa
1394+ r <- stepa gst sa
14271395 return $ case r of
14281396 Yield a sa' -> Skip (Just sa', sb, Just a, b)
14291397 Skip sa' -> Skip (Just sa', sb, Nothing, b)
14301398 Stop -> Skip (Nothing, sb, Nothing, b)
14311399
14321400 step gst (sa, Just sb, a, Nothing) = do
1433− r <- stepb (rstState gst) sb
1401+ r <- stepb gst sb
14341402 return $ case r of
14351403 Yield b sb' -> Skip (sa, Just sb', a, Just b)
14361404 Skip sb' -> Skip (sa, Just sb', a, Nothing)
@@ -1479,11 +1447,3 @@ the (Stream step state) = go state
14791447 | otherwise -> return Nothing
14801448 Skip s -> go' n s
14811449 Stop -> return (Just n)
1482−
1483−------------------------------------------------------------------------------
1484−-- Instances
1485−------------------------------------------------------------------------------
1486−
1487−instance Monad m => Functor (Stream m) where
1488− {-# INLINE fmap #-}
1489− fmap = map
src/Streamly/Streams/StreamD/Type.hsnew file+100
@@ -0,0 +1,100 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE ConstraintKinds #-}
4+{-# LANGUAGE ExistentialQuantification #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PatternSynonyms #-}
9+{-# LANGUAGE ViewPatterns #-}
10+{-# LANGUAGE RankNTypes #-}
11+
12+#include "../inline.hs"
13+
14+-- |
15+-- Module : Streamly.Streams.StreamD.Type
16+-- Copyright : (c) 2018 Harendra Kumar
17+--
18+-- License : BSD3
19+-- Maintainer : harendra.kumar@gmail.com
20+-- Stability : experimental
21+-- Portability : GHC
22+
23+module Streamly.Streams.StreamD.Type
24+ (
25+ -- * The stream type
26+ Step (..)
27+ -- XXX UnStream is exported to avoid a performance issue in concatMap if we
28+ -- use the pattern synonym "Stream".
29+#if __GLASGOW_HASKELL__ >= 800
30+ , Stream (Stream, UnStream)
31+#else
32+ , Stream (UnStream)
33+ , pattern Stream
34+#endif
35+ , map
36+ , mapM
37+ )
38+where
39+
40+import Streamly.SVar (State(..), adaptState)
41+import qualified Streamly.Streams.StreamK as K
42+import Prelude hiding (map, mapM)
43+
44+------------------------------------------------------------------------------
45+-- The direct style stream type
46+------------------------------------------------------------------------------
47+
48+-- | A stream is a succession of 'Step's. A 'Yield' produces a single value and
49+-- the next state of the stream. 'Stop' indicates there are no more values in
50+-- the stream.
51+data Step s a = Yield a s | Skip s | Stop
52+
53+instance Functor (Step s) where
54+ {-# INLINE fmap #-}
55+ fmap f (Yield x s) = Yield (f x) s
56+ fmap _ (Skip s) = Skip s
57+ fmap _ Stop = Stop
58+
59+-- gst = global state
60+-- | A stream consists of a step function that generates the next step given a
61+-- current state, and the current state.
62+data Stream m a =
63+ forall s. UnStream (State K.Stream m a -> s -> m (Step s a)) s
64+
65+unShare :: Stream m a -> Stream m a
66+unShare (UnStream step state) = UnStream step' state
67+ where step' gst = step (adaptState gst)
68+
69+pattern Stream :: (State K.Stream m a -> s -> m (Step s a)) -> s -> Stream m a
70+pattern Stream step state <- (unShare -> UnStream step state)
71+ where Stream = UnStream
72+
73+#if __GLASGOW_HASKELL__ >= 802
74+{-# COMPLETE Stream #-}
75+#endif
76+
77+------------------------------------------------------------------------------
78+-- Instances
79+------------------------------------------------------------------------------
80+
81+-- | Map a monadic function over a 'Stream'
82+{-# INLINE_NORMAL mapM #-}
83+mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
84+mapM f (Stream step state) = Stream step' state
85+ where
86+ {-# INLINE_LATE step' #-}
87+ step' gst st = do
88+ r <- step (adaptState gst) st
89+ case r of
90+ Yield x s -> f x >>= \a -> return $ Yield a s
91+ Skip s -> return $ Skip s
92+ Stop -> return Stop
93+
94+{-# INLINE map #-}
95+map :: Monad m => (a -> b) -> Stream m a -> Stream m b
96+map f = mapM (return . f)
97+
98+instance Monad m => Functor (Stream m) where
99+ {-# INLINE fmap #-}
100+ fmap = map
src/Streamly/Streams/StreamK.hs+224−471
@@ -6,8 +6,11 @@
66{-# LANGUAGE InstanceSigs #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
88{-# LANGUAGE RankNTypes #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
910{-# LANGUAGE UndecidableInstances #-} -- XXX
1011
12+#include "inline.hs"
13+
1114-- |
1215-- Module : Streamly.Streams.StreamK
1316-- Copyright : (c) 2017 Harendra Kumar
@@ -32,22 +35,21 @@ module Streamly.Streams.StreamK
3235 , adapt
3336
3437 -- * The stream type
35− , Stream (..)
36− , unStreamIsolated
37− , isolateStream
38− , unstreamShared
39− , runStreamSVar
38+ , Stream
4039
41− -- * Construction
40+ -- * Construction Primitives
4241 , mkStream
4342 , nil
4443 , cons
4544 , (.:)
4645
47− -- * Asynchronous construction
48− , nilK
49− , yieldK
50− , consK
46+ -- * Elimination Primitives
47+ , foldStream
48+ , foldStreamShared
49+ , foldStreamSVar
50+
51+ -- * Transformation Primitives
52+ , unShare
5153
5254 -- * Deconstruction
5355 , uncons
@@ -71,7 +73,6 @@ module Streamly.Streams.StreamK
7173
7274 -- * Elimination
7375 -- ** General Folds
74− , foldStream
7576 , foldr
7677 , foldrM
7778 , foldr1
@@ -150,7 +151,7 @@ module Streamly.Streams.StreamK
150151 , serial
151152
152153 -- * Utilities
153− , consMSerial
154+ , consMStream
154155 , bindWith
155156 , withLocal
156157
@@ -161,10 +162,7 @@ module Streamly.Streams.StreamK
161162where
162163
163164import Control.Monad (void)
164−import Control.Monad.IO.Class (MonadIO(liftIO))
165165import Control.Monad.Reader.Class (MonadReader(..))
166−import Control.Monad.Trans.Class (MonadTrans(lift))
167−import Data.Semigroup (Semigroup(..))
168166import Prelude
169167 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
170168 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
@@ -173,182 +171,18 @@ import Prelude
173171import qualified Prelude
174172
175173import Streamly.SVar
174+import Streamly.Streams.StreamK.Type
176175
177−------------------------------------------------------------------------------
178−-- The basic stream type
179−------------------------------------------------------------------------------
180−
181−-- | The type @Stream m a@ represents a monadic stream of values of type 'a'
182−-- constructed using actions in monad 'm'. It uses stop, singleton and yield
183−-- continuations equivalent to the following direct style type:
184−--
185−-- @
186−-- data Stream m a = Stop | Singleton a | Yield a (Stream m a)
187−-- @
188−--
189−-- To facilitate parallel composition we maintain a local state in an 'SVar'
190−-- that is shared across and is used for synchronization of the streams being
191−-- composed.
192−--
193−-- The singleton case can be expressed in terms of stop and yield but we have
194−-- it as a separate case to optimize composition operations for streams with
195−-- single element. We build singleton streams in the implementation of 'pure'
196−-- for Applicative and Monad, and in 'lift' for MonadTrans.
197−--
198−newtype Stream m a =
199− Stream {
200− unStream :: forall r.
201− State Stream m a -- state
202− -> m r -- stop
203− -> (a -> m r) -- singleton
204− -> (a -> Stream m a -> m r) -- yield
205− -> m r
206− }
207−
208−-- XXX make this the default "unStream"
209−-- | unwraps the Stream type producing the stream function that can be run with
210−-- continuations.
211−{-# INLINE unStreamIsolated #-}
212−unStreamIsolated ::
213− Stream m a
214− -> State Stream m a -- state
215− -> m r -- stop
216− -> (a -> m r) -- singleton
217− -> (a -> Stream m a -> m r) -- yield
218− -> m r
219−unStreamIsolated x st = unStream x (rstState st)
220−
221−{-# INLINE isolateStream #-}
222−isolateStream :: Stream m a -> Stream m a
223−isolateStream x = Stream $ \st stp sng yld ->
224− unStreamIsolated x st stp sng yld
225−
226−-- | Like unstream, but passes a shared SVar across continuations.
227−{-# INLINE unstreamShared #-}
228−unstreamShared ::
229− Stream m a
230− -> State Stream m a -- state
231− -> m r -- stop
232− -> (a -> m r) -- singleton
233− -> (a -> Stream m a -> m r) -- yield
234− -> m r
235−unstreamShared = unStream
236−
237−-- Run the stream using a run function associated with the SVar that runs the
238−-- streams with a captured snapshot of the monadic state.
239−{-# INLINE runStreamSVar #-}
240−runStreamSVar
241− :: MonadIO m
242− => SVar Stream m a
243− -> Stream m a
244− -> State Stream m a -- state
245− -> m r -- stop
246− -> (a -> m r) -- singleton
247− -> (a -> Stream m a -> m r) -- yield
248− -> m ()
249−runStreamSVar sv m st stp sng yld =
250− let mrun = runInIO $ svarMrun sv
251− in void $ liftIO $ mrun $ unStream m st stp sng yld
252−
253−------------------------------------------------------------------------------
254−-- Types that can behave as a Stream
255−------------------------------------------------------------------------------
256−
257−infixr 5 `consM`
258−infixr 5 |:
259−
260−-- | Class of types that can represent a stream of elements of some type 'a' in
261−-- some monad 'm'.
262−--
263−-- @since 0.2.0
264−class IsStream t where
265− toStream :: t m a -> Stream m a
266− fromStream :: Stream m a -> t m a
267− -- | Constructs a stream by adding a monadic action at the head of an
268− -- existing stream. For example:
269− --
270− -- @
271− -- > toList $ getLine \`consM` getLine \`consM` nil
272− -- hello
273− -- world
274− -- ["hello","world"]
275− -- @
276− --
277− -- /Concurrent (do not use 'parallely' to construct infinite streams)/
278− --
279− -- @since 0.2.0
280− consM :: MonadAsync m => m a -> t m a -> t m a
281− -- | Operator equivalent of 'consM'. We can read it as "@parallel colon@"
282− -- to remember that @|@ comes before ':'.
283− --
284− -- @
285− -- > toList $ getLine |: getLine |: nil
286− -- hello
287− -- world
288− -- ["hello","world"]
289− -- @
290− --
291− -- @
292− -- let delay = threadDelay 1000000 >> print 1
293− -- runStream $ serially $ delay |: delay |: delay |: nil
294− -- runStream $ parallely $ delay |: delay |: delay |: nil
295− -- @
296− --
297− -- /Concurrent (do not use 'parallely' to construct infinite streams)/
298− --
299− -- @since 0.2.0
300− (|:) :: MonadAsync m => m a -> t m a -> t m a
301− -- We can define (|:) just as 'consM' but it is defined explicitly for each
302− -- type because we want to use SPECIALIZE pragma on the definition.
303−
304−-- | Same as 'IsStream'.
305−--
306−-- @since 0.1.0
307−{-# DEPRECATED Streaming "Please use IsStream instead." #-}
308−type Streaming = IsStream
309−
310−-------------------------------------------------------------------------------
311−-- Type adapting combinators
312−-------------------------------------------------------------------------------
313−
314−-- | Adapt any specific stream type to any other specific stream type.
315−--
316−-- @since 0.1.0
317−adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a
318−adapt = fromStream . toStream
319−
320−------------------------------------------------------------------------------
321−-- Building a stream
322−------------------------------------------------------------------------------
323−
324−-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
325−-- continuation and a yield continuation.
326−mkStream:: IsStream t
327− => (forall r. State Stream m a
328− -> m r
329− -> (a -> m r)
330− -> (a -> t m a -> m r)
331− -> m r)
332− -> t m a
333−mkStream k = fromStream $ Stream $ \st stp sng yld ->
334− let yieldk a r = yld a (toStream r)
335− in k (rstState st) stp sng yieldk
176+-- | Detach a stream from an SVar
177+{-# INLINE unShare #-}
178+unShare :: IsStream t => t m a -> t m a
179+unShare x = mkStream $ \st yld sng stp ->
180+ foldStream st yld sng stp x
336181
337182------------------------------------------------------------------------------
338183-- Construction
339184------------------------------------------------------------------------------
340185
341−-- | An empty stream.
342−--
343−-- @
344−-- > toList nil
345−-- []
346−-- @
347−--
348−-- @since 0.1.0
349−nil :: IsStream t => t m a
350−nil = fromStream $ Stream $ \_ stp _ _ -> stp
351−
352186infixr 5 `cons`
353187
354188-- faster than consM because there is no bind.
@@ -363,8 +197,9 @@ infixr 5 `cons`
363197-- @
364198--
365199-- @since 0.1.0
200+{-# INLINE cons #-}
366201cons :: IsStream t => a -> t m a -> t m a
367−cons a r = fromStream $ Stream $ \_ _ _ yld -> yld a (toStream r)
202+cons a r = mkStream $ \_ yld _ _ -> yld a r
368203
369204infixr 5 .:
370205
@@ -376,50 +211,10 @@ infixr 5 .:
376211-- @
377212--
378213-- @since 0.1.1
214+{-# INLINE (.:) #-}
379215(.:) :: IsStream t => a -> t m a -> t m a
380216(.:) = cons
381217
382−{-# INLINE consMSerial #-}
383−consMSerial :: (Monad m) => m a -> Stream m a -> Stream m a
384−consMSerial m r = Stream $ \_ _ _ yld -> m >>= \a -> yld a r
385−
386−------------------------------------------------------------------------------
387−-- Asynchronous construction
388−------------------------------------------------------------------------------
389−
390−-- | Make an empty stream from a callback function.
391−nilK :: IsStream t => (forall r. m r -> m r) -> t m a
392−nilK k = fromStream $ Stream $ \_ stp _ _ -> k stp
393−
394−-- | Make a singleton stream from a one shot callback function.
395−yieldK :: IsStream t => (forall r. (a -> m r) -> m r) -> t m a
396−yieldK k = fromStream $ Stream $ \_ _ sng _ -> k sng
397−
398−-- | Construct a stream from a callback function.
399−consK :: IsStream t => (forall r. (a -> m r) -> m r) -> t m a -> t m a
400−consK k r = fromStream $ Stream $ \_ _ _ yld -> k (\x -> yld x (toStream r))
401−
402−-- XXX consK with concurrent callbacks
403−-- XXX Build a stream from a repeating callback function.
404−
405−-------------------------------------------------------------------------------
406−-- IsStream Stream
407−-------------------------------------------------------------------------------
408−
409−instance IsStream Stream where
410− toStream = id
411− fromStream = id
412−
413− {-# INLINE consM #-}
414− {-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
415− consM :: Monad m => m a -> Stream m a -> Stream m a
416− consM = consMSerial
417−
418− {-# INLINE (|:) #-}
419− {-# SPECIALIZE (|:) :: IO a -> Stream IO a -> Stream IO a #-}
420− (|:) :: Monad m => m a -> Stream m a -> Stream m a
421− (|:) = consMSerial
422−
423218-------------------------------------------------------------------------------
424219-- Deconstruction
425220-------------------------------------------------------------------------------
@@ -429,43 +224,56 @@ uncons :: (IsStream t, Monad m) => t m a -> m (Maybe (a, t m a))
429224uncons m =
430225 let stop = return Nothing
431226 single a = return (Just (a, nil))
432− yieldk a r = return (Just (a, fromStream r))
433− in unStream (toStream m) defState stop single yieldk
227+ yieldk a r = return (Just (a, r))
228+ in foldStream defState yieldk single stop m
434229
435230-------------------------------------------------------------------------------
436231-- Generation
437232-------------------------------------------------------------------------------
438233
234+{-# INLINE_NORMAL build #-}
235+build :: IsStream t => forall a. (forall b. (a -> b -> b) -> b -> b) -> t m a
236+build g = g cons nil
237+
238+{-# INLINE_NORMAL _augment #-}
239+_augment
240+ :: IsStream t
241+ => forall a. (forall b. (a -> b -> b) -> b -> b) -> t m a -> t m a
242+_augment g xs = g cons xs
243+
244+{-# INLINE_NORMAL _buildM #-}
245+_buildM
246+ :: (IsStream t, MonadAsync m)
247+ => forall a. ((m a -> t m a -> t m a) -> t m a -> t m a) -> t m a
248+_buildM g = g consM nil
249+
439250{-# INLINE unfoldr #-}
440251unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a
441−unfoldr step = fromStream . go
442− where
443− go s = Stream $ \_ stp _ yld ->
444− case step s of
445− Nothing -> stp
446− Just (a, b) -> yld a (go b)
252+unfoldr step b0 = build $ \cns nl ->
253+ let go s =
254+ case step s of
255+ Just (a, b) -> a `cns` go b
256+ Nothing -> nl
257+ in go b0
447258
448259{-# INLINE unfoldrM #-}
449260unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
450261unfoldrM step = go
451262 where
452− go s = fromStream $ Stream $ \svr stp sng yld -> do
263+ go s = mkStream $ \st yld sng stp -> do
453264 mayb <- step s
454265 case mayb of
455266 Nothing -> stp
456267 Just (a, b) ->
457− unStream (toStream (return a |: go b)) svr stp sng yld
268+ foldStreamShared st yld sng stp $ return a |: go b
458269
459270-------------------------------------------------------------------------------
460271-- Special generation
461272-------------------------------------------------------------------------------
462273
274+{-# INLINE yield #-}
463275yield :: IsStream t => a -> t m a
464−yield a = fromStream $ Stream $ \_ _ single _ -> single a
465−
466−{-# INLINE yieldM #-}
467−yieldM :: (Monad m, IsStream t) => m a -> t m a
468−yieldM m = fromStream $ Stream $ \_ _ single _ -> m >>= single
276+yield a = mkStream $ \_ _ single _ -> single a
469277
470278-- | Same as yieldM
471279--
@@ -484,14 +292,17 @@ once = yieldM
484292-- Generate an infinite stream by repeating a pure value.
485293--
486294-- @since 0.4.0
295+{-# INLINE repeat #-}
487296repeat :: IsStream t => a -> t m a
488297repeat a = let x = cons a x in x
489298
299+{-# INLINE replicateM #-}
490300replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
491301replicateM n m = go n
492302 where
493303 go cnt = if cnt <= 0 then nil else m |: go (cnt - 1)
494304
305+{-# INLINE replicate #-}
495306replicate :: IsStream t => Int -> a -> t m a
496307replicate n a = go n
497308 where
@@ -518,47 +329,34 @@ fromList :: IsStream t => [a] -> t m a
518329fromList = fromFoldable
519330
520331{-# INLINE fromStreamK #-}
521−fromStreamK :: Stream m a -> Stream m a
522−fromStreamK = id
332+fromStreamK :: IsStream t => Stream m a -> t m a
333+fromStreamK = fromStream
523334
524335-------------------------------------------------------------------------------
525336-- Elimination by Folding
526337-------------------------------------------------------------------------------
527338
528−-- | Fold a stream by providing an SVar, a stop continuation, a singleton
529−-- continuation and a yield continuation.
530−foldStream
531− :: IsStream t
532− => State Stream m a
533− -> m r
534− -> (a -> m r)
535− -> (a -> t m a -> m r)
536− -> t m a
537− -> m r
538−foldStream st blank single step m =
539− let yieldk a x = step a (fromStream x)
540− in unStream (toStream m) st blank single yieldk
541−
542339-- | Lazy right associative fold.
340+{-# INLINE foldr #-}
543341foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
544−foldr step acc m = go (toStream m)
342+foldr step acc m = go m
545343 where
546344 go m1 =
547345 let stop = return acc
548346 single a = return (step a acc)
549347 yieldk a r = go r >>= \b -> return (step a b)
550− in unStream m1 defState stop single yieldk
348+ in foldStream defState yieldk single stop m1
551349
552350-- | Lazy right fold with a monadic step function.
553351{-# INLINE foldrM #-}
554352foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
555−foldrM step acc m = go (toStream m)
353+foldrM step acc m = go m
556354 where
557355 go m1 =
558356 let stop = return acc
559357 single a = step a acc
560358 yieldk a r = go r >>= step a
561− in unStream m1 defState stop single yieldk
359+ in foldStream defState yieldk single stop m1
562360
563361{-# INLINE foldr1 #-}
564362foldr1 :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> m (Maybe a)
@@ -566,13 +364,13 @@ foldr1 step m = do
566364 r <- uncons m
567365 case r of
568366 Nothing -> return Nothing
569− Just (h, t) -> fmap Just (go h (toStream t))
367+ Just (h, t) -> fmap Just (go h t)
570368 where
571369 go p m1 =
572370 let stp = return p
573371 single a = return $ step a p
574372 yieldk a r = fmap (step p) (go a r)
575− in unStream m1 defState stp single yieldk
373+ in foldStream defState yieldk single stp m1
576374
577375-- | Strict left fold with an extraction function. Like the standard strict
578376-- left fold, but applies a user supplied extraction function (the third
@@ -581,28 +379,31 @@ foldr1 step m = do
581379--
582380-- Note that the accumulator is always evaluated including the initial value.
583381{-# INLINE foldx #-}
584−foldx :: (IsStream t, Monad m)
382+foldx :: forall t m a b x. (IsStream t, Monad m)
585383 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
586−foldx step begin done m = get $ go (toStream m) begin
384+foldx step begin done m = get $ go m begin
587385 where
588386 {-# NOINLINE get #-}
387+ get :: t m x -> m b
589388 get m1 =
590389 -- XXX we are not strictly evaluating the accumulator here. Is this
591390 -- okay?
592391 let single = return . done
593− in unStream m1 undefined undefined single undefined
392+ -- XXX this is foldSingleton. why foldStreamShared?
393+ in foldStreamShared undefined undefined single undefined m1
594394
595395 -- Note, this can be implemented by making a recursive call to "go",
596396 -- however that is more expensive because of unnecessary recursion
597397 -- that cannot be tail call optimized. Unfolding recursion explicitly via
598398 -- continuations is much more efficient.
599− go m1 !acc = Stream $ \_ _ sng yld ->
399+ go :: t m a -> x -> t m x
400+ go m1 !acc = mkStream $ \_ yld sng _ ->
600401 let stop = sng acc
601402 single a = sng $ step acc a
602− yieldk a r =
603− let stream = go r (step acc a)
604− in unStream stream defState undefined sng yld
605− in unStream m1 defState stop single yieldk
403+ -- XXX this is foldNonEmptyStream
404+ yieldk a r = foldStream defState yld sng undefined $
405+ go r (step acc a)
406+ in foldStream defState yieldk single stop m1
606407
607408-- | Strict left associative fold.
608409{-# INLINE foldl' #-}
@@ -611,17 +412,19 @@ foldl' step begin = foldx step begin id
611412
612413-- XXX replace the recursive "go" with explicit continuations.
613414-- | Like 'foldx', but with a monadic step function.
415+{-# INLINABLE foldxM #-}
614416foldxM :: (IsStream t, Monad m)
615417 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
616−foldxM step begin done m = go begin (toStream m)
418+foldxM step begin done m = go begin m
617419 where
618420 go !acc m1 =
619421 let stop = acc >>= done
620422 single a = acc >>= \b -> step b a >>= done
621423 yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
622− in unStream m1 defState stop single yieldk
424+ in foldStream defState yieldk single stop m1
623425
624426-- | Like 'foldl'' but with a monadic step function.
427+{-# INLINE foldlM' #-}
625428foldlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> m b
626429foldlM' step begin = foldxM step (return begin) return
627430
@@ -629,15 +432,18 @@ foldlM' step begin = foldxM step (return begin) return
629432-- Specialized folds
630433------------------------------------------------------------------------------
631434
435+-- |
436+-- > runStream = foldl' (\_ _ -> ()) ()
437+-- > runStream = mapM_ (\_ -> return ())
632438{-# INLINE runStream #-}
633439runStream :: (Monad m, IsStream t) => t m a -> m ()
634−runStream m = go (toStream m)
440+runStream = go
635441 where
636442 go m1 =
637443 let stop = return ()
638444 single _ = return ()
639− yieldk _ r = go (toStream r)
640− in unStream m1 defState stop single yieldk
445+ yieldk _ r = go r
446+ in foldStream defState yieldk single stop m1
641447
642448{-# INLINE null #-}
643449null :: (IsStream t, Monad m) => t m a -> m Bool
@@ -645,7 +451,7 @@ null m =
645451 let stop = return True
646452 single _ = return False
647453 yieldk _ _ = return False
648− in unStream (toStream m) defState stop single yieldk
454+ in foldStream defState yieldk single stop m
649455
650456{-# INLINE head #-}
651457head :: (IsStream t, Monad m) => t m a -> m (Maybe a)
@@ -653,69 +459,71 @@ head m =
653459 let stop = return Nothing
654460 single a = return (Just a)
655461 yieldk a _ = return (Just a)
656− in unStream (toStream m) defState stop single yieldk
462+ in foldStream defState yieldk single stop m
657463
658464{-# INLINE tail #-}
659465tail :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
660466tail m =
661467 let stop = return Nothing
662468 single _ = return $ Just nil
663− yieldk _ r = return $ Just $ fromStream r
664− in unStream (toStream m) defState stop single yieldk
469+ yieldk _ r = return $ Just r
470+ in foldStream defState yieldk single stop m
665471
666472{-# INLINE init #-}
667473init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
668−init m = go1 (toStream m)
474+init m = go1 m
669475 where
670476 go1 m1 = do
671477 r <- uncons m1
672478 case r of
673479 Nothing -> return Nothing
674− Just (h, t) -> return . Just . fromStream $ go h t
675− go p m1 = Stream $ \_ stp sng yld ->
480+ Just (h, t) -> return . Just $ go h t
481+ go p m1 = mkStream $ \_ yld sng stp ->
676482 let single _ = sng p
677483 yieldk a x = yld p $ go a x
678− in unStream m1 defState stp single yieldk
484+ in foldStream defState yieldk single stp m1
679485
680486{-# INLINE elem #-}
681487elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
682−elem e m = go (toStream m)
488+elem e m = go m
683489 where
684490 go m1 =
685491 let stop = return False
686492 single a = return (a == e)
687493 yieldk a r = if a == e then return True else go r
688− in unStream m1 defState stop single yieldk
494+ in foldStream defState yieldk single stop m1
689495
690496{-# INLINE notElem #-}
691497notElem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
692−notElem e m = go (toStream m)
498+notElem e m = go m
693499 where
694500 go m1 =
695501 let stop = return True
696502 single a = return (a /= e)
697503 yieldk a r = if a == e then return False else go r
698− in unStream m1 defState stop single yieldk
504+ in foldStream defState yieldk single stop m1
699505
506+{-# INLINABLE all #-}
700507all :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
701−all p m = go (toStream m)
508+all p m = go m
702509 where
703510 go m1 =
704511 let single a | p a = return True
705512 | otherwise = return False
706513 yieldk a r | p a = go r
707514 | otherwise = return False
708− in unStream m1 defState (return True) single yieldk
515+ in foldStream defState yieldk single (return True) m1
709516
517+{-# INLINABLE any #-}
710518any :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
711−any p m = go (toStream m)
519+any p m = go m
712520 where
713521 go m1 =
714522 let single a | p a = return True
715523 | otherwise = return False
716524 yieldk a r | p a = return True
717525 | otherwise = go r
718− in unStream m1 defState (return False) single yieldk
526+ in foldStream defState yieldk single (return False) m1
719527
720528-- | Extract the last element of the stream, if any.
721529{-# INLINE last #-}
@@ -724,13 +532,13 @@ last = foldx (\_ y -> Just y) Nothing id
724532
725533{-# INLINE minimum #-}
726534minimum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
727−minimum m = go Nothing (toStream m)
535+minimum m = go Nothing m
728536 where
729537 go Nothing m1 =
730538 let stop = return Nothing
731539 single a = return (Just a)
732540 yieldk a r = go (Just a) r
733− in unStream m1 defState stop single yieldk
541+ in foldStream defState yieldk single stop m1
734542
735543 go (Just res) m1 =
736544 let stop = return (Just res)
@@ -742,19 +550,19 @@ minimum m = go Nothing (toStream m)
742550 if res <= a
743551 then go (Just res) r
744552 else go (Just a) r
745− in unStream m1 defState stop single yieldk
553+ in foldStream defState yieldk single stop m1
746554
747555{-# INLINE minimumBy #-}
748556minimumBy
749557 :: (IsStream t, Monad m)
750558 => (a -> a -> Ordering) -> t m a -> m (Maybe a)
751−minimumBy cmp m = go Nothing (toStream m)
559+minimumBy cmp m = go Nothing m
752560 where
753561 go Nothing m1 =
754562 let stop = return Nothing
755563 single a = return (Just a)
756564 yieldk a r = go (Just a) r
757− in unStream m1 defState stop single yieldk
565+ in foldStream defState yieldk single stop m1
758566
759567 go (Just res) m1 =
760568 let stop = return (Just res)
@@ -764,17 +572,17 @@ minimumBy cmp m = go Nothing (toStream m)
764572 yieldk a r = case cmp res a of
765573 GT -> go (Just a) r
766574 _ -> go (Just res) r
767− in unStream m1 defState stop single yieldk
575+ in foldStream defState yieldk single stop m1
768576
769577{-# INLINE maximum #-}
770578maximum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
771−maximum m = go Nothing (toStream m)
579+maximum m = go Nothing m
772580 where
773581 go Nothing m1 =
774582 let stop = return Nothing
775583 single a = return (Just a)
776584 yieldk a r = go (Just a) r
777− in unStream m1 defState stop single yieldk
585+ in foldStream defState yieldk single stop m1
778586
779587 go (Just res) m1 =
780588 let stop = return (Just res)
@@ -786,17 +594,17 @@ maximum m = go Nothing (toStream m)
786594 if res <= a
787595 then go (Just a) r
788596 else go (Just res) r
789− in unStream m1 defState stop single yieldk
597+ in foldStream defState yieldk single stop m1
790598
791599{-# INLINE maximumBy #-}
792600maximumBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> m (Maybe a)
793−maximumBy cmp m = go Nothing (toStream m)
601+maximumBy cmp m = go Nothing m
794602 where
795603 go Nothing m1 =
796604 let stop = return Nothing
797605 single a = return (Just a)
798606 yieldk a r = go (Just a) r
799− in unStream m1 defState stop single yieldk
607+ in foldStream defState yieldk single stop m1
800608
801609 go (Just res) m1 =
802610 let stop = return (Just res)
@@ -806,11 +614,11 @@ maximumBy cmp m = go Nothing (toStream m)
806614 yieldk a r = case cmp res a of
807615 GT -> go (Just res) r
808616 _ -> go (Just a) r
809− in unStream m1 defState stop single yieldk
617+ in foldStream defState yieldk single stop m1
810618
811619{-# INLINE (!!) #-}
812620(!!) :: (IsStream t, Monad m) => t m a -> Int -> m (Maybe a)
813−m !! i = go i (toStream m)
621+m !! i = go i m
814622 where
815623 go n m1 =
816624 let single a | n == 0 = return $ Just a
@@ -818,22 +626,22 @@ m !! i = go i (toStream m)
818626 yieldk a x | n < 0 = return Nothing
819627 | n == 0 = return $ Just a
820628 | otherwise = go (n - 1) x
821− in unStream m1 defState (return Nothing) single yieldk
629+ in foldStream defState yieldk single (return Nothing) m1
822630
823631{-# INLINE lookup #-}
824632lookup :: (IsStream t, Monad m, Eq a) => a -> t m (a, b) -> m (Maybe b)
825−lookup e m = go (toStream m)
633+lookup e m = go m
826634 where
827635 go m1 =
828636 let single (a, b) | a == e = return $ Just b
829637 | otherwise = return Nothing
830638 yieldk (a, b) x | a == e = return $ Just b
831639 | otherwise = go x
832− in unStream m1 defState (return Nothing) single yieldk
640+ in foldStream defState yieldk single (return Nothing) m1
833641
834642{-# INLINE findM #-}
835643findM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> m (Maybe a)
836−findM p m = go (toStream m)
644+findM p m = go m
837645 where
838646 go m1 =
839647 let single a = do
@@ -842,7 +650,7 @@ findM p m = go (toStream m)
842650 yieldk a x = do
843651 b <- p a
844652 if b then return $ Just a else go x
845− in unStream m1 defState (return Nothing) single yieldk
653+ in foldStream defState yieldk single (return Nothing) m1
846654
847655{-# INLINE find #-}
848656find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
@@ -850,14 +658,15 @@ find p = findM (return . p)
850658
851659{-# INLINE findIndices #-}
852660findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
853−findIndices p = fromStream . go 0 . toStream
661+findIndices p = go 0
854662 where
855− go offset m1 = Stream $ \st stp sng yld ->
663+ go offset m1 = mkStream $ \st yld sng stp ->
856664 let single a | p a = sng offset
857665 | otherwise = stp
858666 yieldk a x | p a = yld offset $ go (offset + 1) x
859− | otherwise = unStream (go (offset + 1) x) st stp sng yld
860− in unStream m1 (rstState st) stp single yieldk
667+ | otherwise = foldStream (adaptState st) yld sng stp $
668+ go (offset + 1) x
669+ in foldStream (adaptState st) yieldk single stp m1
861670
862671------------------------------------------------------------------------------
863672-- Map and Fold
@@ -865,14 +674,15 @@ findIndices p = fromStream . go 0 . toStream
865674
866675-- | Apply a monadic action to each element of the stream and discard the
867676-- output of the action.
677+{-# INLINE mapM_ #-}
868678mapM_ :: (IsStream t, Monad m) => (a -> m b) -> t m a -> m ()
869−mapM_ f m = go (toStream m)
679+mapM_ f m = go m
870680 where
871681 go m1 =
872682 let stop = return ()
873683 single a = void (f a)
874684 yieldk a r = f a >> go r
875− in unStream m1 defState stop single yieldk
685+ in foldStream defState yieldk single stop m1
876686
877687------------------------------------------------------------------------------
878688-- Converting folds
@@ -893,14 +703,14 @@ toStreamK = id
893703{-# INLINE scanx #-}
894704scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
895705scanx step begin done m =
896− cons (done begin) $ fromStream $ go (toStream m) begin
706+ cons (done begin) $ go m begin
897707 where
898− go m1 !acc = Stream $ \st stp sng yld ->
708+ go m1 !acc = mkStream $ \st yld sng stp ->
899709 let single a = sng (done $ step acc a)
900710 yieldk a r =
901711 let s = step acc a
902712 in yld (done s) (go r s)
903− in unStream m1 (rstState st) stp single yieldk
713+ in foldStream (adaptState st) yieldk single stp m1
904714
905715{-# INLINE scanl' #-}
906716scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
@@ -912,91 +722,84 @@ scanl' step begin = scanx step begin id
912722
913723{-# INLINE filter #-}
914724filter :: IsStream t => (a -> Bool) -> t m a -> t m a
915−filter p m = fromStream $ go (toStream m)
725+filter p m = go m
916726 where
917− go m1 = Stream $ \st stp sng yld ->
727+ go m1 = mkStream $ \st yld sng stp ->
918728 let single a | p a = sng a
919729 | otherwise = stp
920730 yieldk a r | p a = yld a (go r)
921− | otherwise = unStream r (rstState st) stp single yieldk
922− in unStream m1 (rstState st) stp single yieldk
731+ | otherwise = foldStream st yieldk single stp r
732+ in foldStream st yieldk single stp m1
923733
924734{-# INLINE take #-}
925735take :: IsStream t => Int -> t m a -> t m a
926−take n m = fromStream $ go n (toStream m)
736+take n m = go n m
927737 where
928− go n1 m1 = Stream $ \st stp sng yld ->
738+ go n1 m1 = mkStream $ \st yld sng stp ->
929739 let yieldk a r = yld a (go (n1 - 1) r)
930740 in if n1 <= 0
931741 then stp
932− else unStream m1 (rstState st) stp sng yieldk
742+ else foldStream st yieldk sng stp m1
933743
934744{-# INLINE takeWhile #-}
935745takeWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
936−takeWhile p m = fromStream $ go (toStream m)
746+takeWhile p m = go m
937747 where
938− go m1 = Stream $ \st stp sng yld ->
748+ go m1 = mkStream $ \st yld sng stp ->
939749 let single a | p a = sng a
940750 | otherwise = stp
941751 yieldk a r | p a = yld a (go r)
942752 | otherwise = stp
943− in unStream m1 (rstState st) stp single yieldk
753+ in foldStream st yieldk single stp m1
944754
755+{-# INLINE drop #-}
945756drop :: IsStream t => Int -> t m a -> t m a
946−drop n m = fromStream $ Stream $ \st stp sng yld ->
947− unStream (go n (toStream m)) (rstState st) stp sng yld
757+drop n m = fromStream $ unShare (go n (toStream m))
948758 where
949− go n1 m1 = Stream $ \st stp sng yld ->
759+ go n1 m1 = mkStream $ \st yld sng stp ->
950760 let single _ = stp
951− yieldk _ r = (unStream $ go (n1 - 1) r) st stp sng yld
761+ yieldk _ r = foldStreamShared st yld sng stp $ go (n1 - 1) r
952762 -- Somehow "<=" check performs better than a ">"
953763 in if n1 <= 0
954− then unStream m1 st stp sng yld
955− else unStream m1 st stp single yieldk
764+ then foldStreamShared st yld sng stp m1
765+ else foldStreamShared st yieldk single stp m1
956766
957767{-# INLINE dropWhile #-}
958768dropWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
959−dropWhile p m = fromStream $ go (toStream m)
769+dropWhile p m = go m
960770 where
961− go m1 = Stream $ \st stp sng yld ->
771+ go m1 = mkStream $ \st yld sng stp ->
962772 let single a | p a = stp
963773 | otherwise = sng a
964− yieldk a r | p a = unStream r (rstState st) stp single yieldk
774+ yieldk a r | p a = foldStream st yieldk single stp r
965775 | otherwise = yld a r
966− in unStream m1 (rstState st) stp single yieldk
776+ in foldStream st yieldk single stp m1
967777
968778-------------------------------------------------------------------------------
969779-- Mapping
970780-------------------------------------------------------------------------------
971781
972−{-# INLINE map #-}
973−map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
974−map f m = fromStream $ Stream $ \st stp sng yld ->
975− let single = sng . f
976− yieldk a r = yld (f a) (fmap f r)
977− in unStream (toStream m) (rstState st) stp single yieldk
978−
979782-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
980783-- other stream types to overload it.
981784{-# INLINE mapM #-}
982785mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
983−mapM f m = go (toStream m)
786+mapM f m = go m
984787 where
985− go m1 = fromStream $ Stream $ \st stp sng yld ->
788+ go m1 = mkStream $ \st yld sng stp ->
986789 let single a = f a >>= sng
987− yieldk a r = unStream (toStream (f a |: go r)) st stp sng yld
988− in unStream m1 (rstState st) stp single yieldk
790+ yieldk a r = foldStreamShared st yld sng stp $ f a |: go r
791+ in foldStream (adaptState st) yieldk single stp m1
989792
990793-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
991794-- other stream types to overload it.
992795{-# INLINE sequence #-}
993796sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
994−sequence m = go (toStream m)
797+sequence m = go m
995798 where
996− go m1 = fromStream $ Stream $ \st stp sng yld ->
799+ go m1 = mkStream $ \st yld sng stp ->
997800 let single ma = ma >>= sng
998− yieldk ma r = unStream (toStream $ ma |: go r) st stp sng yld
999− in unStream m1 (rstState st) stp single yieldk
801+ yieldk ma r = foldStreamShared st yld sng stp $ ma |: go r
802+ in foldStream (adaptState st) yieldk single stp m1
1000803
1001804-------------------------------------------------------------------------------
1002805-- Inserting
@@ -1004,21 +807,21 @@ sequence m = go (toStream m)
1004807
1005808{-# INLINE intersperseM #-}
1006809intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
1007−intersperseM a m = fromStream $ prependingStart (toStream m)
810+intersperseM a m = prependingStart m
1008811 where
1009− prependingStart m1 = Stream $ \st stp sng yld ->
1010− let yieldk i x = unStream (return i |: go x) st stp sng yld
1011− in unStream m1 (rstState st) stp sng yieldk
1012− go m2 = fromStream $ Stream $ \st stp sng yld ->
1013− let single i = unStream (a |: yield i) st stp sng yld
1014− yieldk i x = unStream (a |: return i |: go x) st stp sng yld
1015− in unStream m2 (rstState st) stp single yieldk
812+ prependingStart m1 = mkStream $ \st yld sng stp ->
813+ let yieldk i x = foldStreamShared st yld sng stp $ return i |: go x
814+ in foldStream st yieldk sng stp m1
815+ go m2 = mkStream $ \st yld sng stp ->
816+ let single i = foldStreamShared st yld sng stp $ a |: yield i
817+ yieldk i x = foldStreamShared st yld sng stp $ a |: return i |: go x
818+ in foldStream st yieldk single stp m2
1016819
1017820{-# INLINE insertBy #-}
1018821insertBy :: IsStream t => (a -> a -> Ordering) -> a -> t m a -> t m a
1019−insertBy cmp x m = fromStream $ go (toStream m)
822+insertBy cmp x m = go m
1020823 where
1021− go m1 = Stream $ \st _ _ yld ->
824+ go m1 = mkStream $ \st yld _ _ ->
1022825 let single a = case cmp x a of
1023826 GT -> yld a (yield x)
1024827 _ -> yld x (yield a)
@@ -1026,7 +829,7 @@ insertBy cmp x m = fromStream $ go (toStream m)
1026829 yieldk a r = case cmp x a of
1027830 GT -> yld a (go r)
1028831 _ -> yld x (a `cons` r)
1029− in unStream m1 (rstState st) stop single yieldk
832+ in foldStream st yieldk single stop m1
1030833
1031834------------------------------------------------------------------------------
1032835-- Deleting
@@ -1034,14 +837,14 @@ insertBy cmp x m = fromStream $ go (toStream m)
1034837
1035838{-# INLINE deleteBy #-}
1036839deleteBy :: IsStream t => (a -> a -> Bool) -> a -> t m a -> t m a
1037−deleteBy eq x m = fromStream $ go (toStream m)
840+deleteBy eq x m = go m
1038841 where
1039− go m1 = Stream $ \st stp sng yld ->
842+ go m1 = mkStream $ \st yld sng stp ->
1040843 let single a = if eq x a then stp else sng a
1041844 yieldk a r = if eq x a
1042− then unStream r (rstState st) stp sng yld
845+ then foldStream st yld sng stp r
1043846 else yld a (go r)
1044− in unStream m1 (rstState st) stp single yieldk
847+ in foldStream st yieldk single stp m1
1045848
1046849-------------------------------------------------------------------------------
1047850-- Map and Filter
@@ -1049,70 +852,67 @@ deleteBy eq x m = fromStream $ go (toStream m)
1049852
1050853{-# INLINE mapMaybe #-}
1051854mapMaybe :: IsStream t => (a -> Maybe b) -> t m a -> t m b
1052−mapMaybe f m = go (toStream m)
855+mapMaybe f m = go m
1053856 where
1054− go m1 = fromStream $ Stream $ \st stp sng yld ->
857+ go m1 = mkStream $ \st yld sng stp ->
1055858 let single a = case f a of
1056859 Just b -> sng b
1057860 Nothing -> stp
1058861 yieldk a r = case f a of
1059− Just b -> yld b (toStream $ go r)
1060− Nothing -> unStream r (rstState st) stp single yieldk
1061− in unStream m1 (rstState st) stp single yieldk
862+ Just b -> yld b $ go r
863+ Nothing -> foldStream (adaptState st) yieldk single stp r
864+ in foldStream (adaptState st) yieldk single stp m1
1062865
1063866------------------------------------------------------------------------------
1064867-- Serial Zipping
1065868------------------------------------------------------------------------------
1066869
1067−{-# INLINE zipWithS #-}
1068−zipWithS :: (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
1069−zipWithS f = go
870+-- | Zip two streams serially using a pure zipping function.
871+--
872+-- @since 0.1.0
873+{-# INLINABLE zipWith #-}
874+zipWith :: IsStream t => (a -> b -> c) -> t m a -> t m b -> t m c
875+zipWith f = go
1070876 where
1071− go mx my = Stream $ \st stp sng yld -> do
877+ go mx my = mkStream $ \st yld sng stp -> do
1072878 let merge a ra =
1073879 let single2 b = sng (f a b)
1074880 yield2 b rb = yld (f a b) (go ra rb)
1075− in unStream my (rstState st) stp single2 yield2
881+ in foldStream (adaptState st) yield2 single2 stp my
1076882 let single1 a = merge a nil
1077883 yield1 = merge
1078− unStream mx (rstState st) stp single1 yield1
1079−
1080−-- | Zip two streams serially using a pure zipping function.
1081−--
1082−-- @since 0.1.0
1083−{-# INLINABLE zipWith #-}
1084−zipWith :: IsStream t => (a -> b -> c) -> t m a -> t m b -> t m c
1085−zipWith f m1 m2 = fromStream $ zipWithS f (toStream m1) (toStream m2)
884+ foldStream (adaptState st) yield1 single1 stp mx
1086885
1087886-- | Zip two streams serially using a monadic zipping function.
1088887--
1089888-- @since 0.1.0
889+{-# INLINABLE zipWithM #-}
1090890zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c
1091−zipWithM f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
891+zipWithM f m1 m2 = go m1 m2
1092892 where
1093− go mx my = Stream $ \st stp sng yld -> do
893+ go mx my = mkStream $ \st yld sng stp -> do
1094894 let merge a ra =
1095− let runIt x = unStream x (rstState st) stp sng yld
895+ let runIt x = foldStream st yld sng stp x
1096896 single2 b = f a b >>= sng
1097897 yield2 b rb = f a b >>= \x -> runIt (x `cons` go ra rb)
1098− in unStream my (rstState st) stp single2 yield2
898+ in foldStream (adaptState st) yield2 single2 stp my
1099899 let single1 a = merge a nil
1100900 yield1 = merge
1101− unStream mx (rstState st) stp single1 yield1
901+ foldStream (adaptState st) yield1 single1 stp mx
1102902
1103903------------------------------------------------------------------------------
1104904-- Merging
1105905------------------------------------------------------------------------------
1106906
1107−{-# INLINE mergeByS #-}
1108−mergeByS
1109− :: Monad m
1110− => (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
1111−mergeByS cmp = go
907+{-# INLINE mergeByM #-}
908+mergeByM
909+ :: (IsStream t, Monad m)
910+ => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
911+mergeByM cmp = go
1112912 where
1113− go mx my = Stream $ \st stp sng yld -> do
913+ go mx my = mkStream $ \st yld sng stp -> do
1114914 let mergeWithY a ra =
1115− let stop2 = unStream mx (rstState st) stp sng yld
915+ let stop2 = foldStream st yld sng stp mx
1116916 single2 b = do
1117917 r <- cmp a b
1118918 case r of
@@ -1123,17 +923,11 @@ mergeByS cmp = go
1123923 case r of
1124924 GT -> yld b (go (a `cons` ra) rb)
1125925 _ -> yld a (go ra (b `cons` rb))
1126− in unStream my (rstState st) stop2 single2 yield2
1127− let stopX = unStream my (rstState st) stp sng yld
926+ in foldStream st yield2 single2 stop2 my
927+ let stopX = foldStream st yld sng stp my
1128928 singleX a = mergeWithY a nil
1129929 yieldX = mergeWithY
1130− unStream mx (rstState st) stopX singleX yieldX
1131−
1132−{-# INLINABLE mergeByM #-}
1133−mergeByM
1134− :: (IsStream t, Monad m)
1135− => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
1136−mergeByM f m1 m2 = fromStream $ mergeByS f (toStream m1) (toStream m2)
930+ foldStream st yieldX singleX stopX mx
1137931
1138932{-# INLINABLE mergeBy #-}
1139933mergeBy
@@ -1151,48 +945,14 @@ the m = do
1151945 r <- uncons m
1152946 case r of
1153947 Nothing -> return Nothing
1154− Just (h, t) -> go h (toStream t)
948+ Just (h, t) -> go h t
1155949 where
1156950 go h m1 =
1157951 let single a | h == a = return $ Just h
1158952 | otherwise = return Nothing
1159953 yieldk a r | h == a = go h r
1160954 | otherwise = return Nothing
1161− in unStream m1 defState (return $ Just h) single yieldk
1162−
1163−------------------------------------------------------------------------------
1164−-- Semigroup
1165−------------------------------------------------------------------------------
1166−
1167−-- | Concatenates two streams sequentially i.e. the first stream is
1168−-- exhausted completely before yielding any element from the second stream.
1169−{-# INLINE serial #-}
1170−serial :: Stream m a -> Stream m a -> Stream m a
1171−serial m1 m2 = go m1
1172− where
1173− go (Stream m) = Stream $ \st stp sng yld ->
1174− let stop = unStream m2 (rstState st) stp sng yld
1175− single a = yld a m2
1176− yieldk a r = yld a (go r)
1177− in m (rstState st) stop single yieldk
1178−
1179−instance Semigroup (Stream m a) where
1180− (<>) = serial
1181−
1182−------------------------------------------------------------------------------
1183−-- Monoid
1184−------------------------------------------------------------------------------
1185−
1186−instance Monoid (Stream m a) where
1187− mempty = nil
1188− mappend = (<>)
1189−
1190−-------------------------------------------------------------------------------
1191−-- Functor
1192−-------------------------------------------------------------------------------
1193−
1194−instance Monad m => Functor (Stream m) where
1195− fmap = map
955+ in foldStream defState yieldk single (return $ Just h) m1
1196956
1197957-------------------------------------------------------------------------------
1198958-- Bind utility
@@ -1200,40 +960,40 @@ instance Monad m => Functor (Stream m) where
1200960
1201961{-# INLINE bindWith #-}
1202962bindWith
1203− :: (forall c. Stream m c -> Stream m c -> Stream m c)
1204− -> Stream m a
1205− -> (a -> Stream m b)
1206− -> Stream m b
1207−bindWith par m f = go m
963+ :: IsStream t
964+ => (forall c. t m c -> t m c -> t m c)
965+ -> t m a
966+ -> (a -> t m b)
967+ -> t m b
968+bindWith par m1 f = go m1
1208969 where
1209− go (Stream g) =
1210− Stream $ \st stp sng yld ->
1211− let runShared x = unstreamShared x st stp sng yld
1212− runIsolated x = unStreamIsolated x st stp sng yld
1213−
1214− single a = runIsolated $ f a
1215− yieldk a r = runShared $ isolateStream (f a) `par` go r
1216− in g (rstState st) stp single yieldk
970+ go m =
971+ mkStream $ \st yld sng stp ->
972+ let foldShared = foldStreamShared st yld sng stp
973+ single a = foldShared $ unShare (f a)
974+ yieldk a r = foldShared $ unShare (f a) `par` go r
975+ in foldStream (adaptState st) yieldk single stp m
1217976
1218977------------------------------------------------------------------------------
1219978-- Alternative & MonadPlus
1220979------------------------------------------------------------------------------
1221980
1222981_alt :: Stream m a -> Stream m a -> Stream m a
1223−_alt m1 m2 = Stream $ \st stp sng yld ->
1224− let stop = unStream m2 (rstState st) stp sng yld
1225− in unStream m1 (rstState st) stop sng yld
982+_alt m1 m2 = mkStream $ \st yld sng stp ->
983+ let stop = foldStream st yld sng stp m2
984+ in foldStream st yld sng stop m1
1226985
1227986------------------------------------------------------------------------------
1228987-- MonadReader
1229988------------------------------------------------------------------------------
1230989
990+{-# INLINABLE withLocal #-}
1231991withLocal :: MonadReader r m => (r -> r) -> Stream m a -> Stream m a
1232992withLocal f m =
1233− Stream $ \st stp sng yld ->
993+ mkStream $ \st yld sng stp ->
1234994 let single = local f . sng
1235995 yieldk a r = local f $ yld a (withLocal f r)
1236− in unStream m (rstState st) (local f stp) single yieldk
996+ in foldStream st yieldk single (local f stp) m
1237997
1238998------------------------------------------------------------------------------
1239999-- MonadError
@@ -1245,16 +1005,9 @@ withCatchError
12451005 :: MonadError e m
12461006 => Stream m a -> (e -> Stream m a) -> Stream m a
12471007withCatchError m h =
1248− Stream $ \_ stp sng yld ->
1008+ mkStream $ \_ stp sng yld ->
12491009 let run x = unStream x Nothing stp sng yieldk
12501010 handle r = r `catchError` \e -> run $ h e
12511011 yieldk a r = yld a (withCatchError r h)
12521012 in handle $ run m
12531013-}
1254−
1255−-------------------------------------------------------------------------------
1256−-- Transformers
1257−-------------------------------------------------------------------------------
1258−
1259−instance MonadTrans Stream where
1260− lift = yieldM
src/Streamly/Streams/StreamK/Type.hsnew file+418
@@ -0,0 +1,418 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE ConstraintKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE InstanceSigs #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PatternSynonyms #-}
9+{-# LANGUAGE ViewPatterns #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE UndecidableInstances #-} -- XXX
12+
13+#include "../inline.hs"
14+
15+-- |
16+-- Module : Streamly.Streams.StreamK.Type
17+-- Copyright : (c) 2017 Harendra Kumar
18+--
19+-- License : BSD3
20+-- Maintainer : harendra.kumar@gmail.com
21+-- Stability : experimental
22+-- Portability : GHC
23+--
24+--
25+-- Continuation passing style (CPS) stream implementation. The symbol 'K' below
26+-- denotes a function as well as a Kontinuation.
27+--
28+module Streamly.Streams.StreamK.Type
29+ (
30+ -- * A class for streams
31+ IsStream (..)
32+ , adapt
33+
34+ -- * The stream type
35+ , Stream ()
36+
37+ -- * Construction
38+ , mkStream
39+ , fromStopK
40+ , fromYieldK
41+ , consK
42+
43+ -- * Elimination
44+ , foldStream
45+ , foldStreamShared
46+ , foldStreamSVar
47+
48+ -- instances
49+ , consMStream
50+
51+ , nil
52+ , serial
53+ , map
54+ , yieldM
55+
56+ , Streaming -- deprecated
57+ )
58+where
59+
60+import Control.Monad (void)
61+import Control.Monad.IO.Class (MonadIO(liftIO))
62+import Control.Monad.Trans.Class (MonadTrans(lift))
63+import Data.Semigroup (Semigroup(..))
64+import Prelude hiding (map)
65+
66+import Streamly.SVar
67+
68+------------------------------------------------------------------------------
69+-- Basic stream type
70+------------------------------------------------------------------------------
71+
72+-- | The type @Stream m a@ represents a monadic stream of values of type 'a'
73+-- constructed using actions in monad 'm'. It uses stop, singleton and yield
74+-- continuations equivalent to the following direct style type:
75+--
76+-- @
77+-- data Stream m a = Stop | Singleton a | Yield a (Stream m a)
78+-- @
79+--
80+-- To facilitate parallel composition we maintain a local state in an 'SVar'
81+-- that is shared across and is used for synchronization of the streams being
82+-- composed.
83+--
84+-- The singleton case can be expressed in terms of stop and yield but we have
85+-- it as a separate case to optimize composition operations for streams with
86+-- single element. We build singleton streams in the implementation of 'pure'
87+-- for Applicative and Monad, and in 'lift' for MonadTrans.
88+--
89+-- XXX remove the Stream type parameter from State as it is always constant.
90+-- We can remove it from SVar as well
91+--
92+newtype Stream m a =
93+ MkStream (forall r.
94+ State Stream m a -- state
95+ -> (a -> Stream m a -> m r) -- yield
96+ -> (a -> m r) -- singleton
97+ -> m r -- stop
98+ -> m r
99+ )
100+
101+------------------------------------------------------------------------------
102+-- Types that can behave as a Stream
103+------------------------------------------------------------------------------
104+
105+infixr 5 `consM`
106+infixr 5 |:
107+
108+-- XXX Use a different SVar based on the stream type. But we need to make sure
109+-- that we do not lose performance due to polymorphism.
110+--
111+-- | Class of types that can represent a stream of elements of some type 'a' in
112+-- some monad 'm'.
113+--
114+-- @since 0.2.0
115+class IsStream t where
116+ toStream :: t m a -> Stream m a
117+ fromStream :: Stream m a -> t m a
118+ -- | Constructs a stream by adding a monadic action at the head of an
119+ -- existing stream. For example:
120+ --
121+ -- @
122+ -- > toList $ getLine \`consM` getLine \`consM` nil
123+ -- hello
124+ -- world
125+ -- ["hello","world"]
126+ -- @
127+ --
128+ -- /Concurrent (do not use 'parallely' to construct infinite streams)/
129+ --
130+ -- @since 0.2.0
131+ consM :: MonadAsync m => m a -> t m a -> t m a
132+ -- | Operator equivalent of 'consM'. We can read it as "@parallel colon@"
133+ -- to remember that @|@ comes before ':'.
134+ --
135+ -- @
136+ -- > toList $ getLine |: getLine |: nil
137+ -- hello
138+ -- world
139+ -- ["hello","world"]
140+ -- @
141+ --
142+ -- @
143+ -- let delay = threadDelay 1000000 >> print 1
144+ -- runStream $ serially $ delay |: delay |: delay |: nil
145+ -- runStream $ parallely $ delay |: delay |: delay |: nil
146+ -- @
147+ --
148+ -- /Concurrent (do not use 'parallely' to construct infinite streams)/
149+ --
150+ -- @since 0.2.0
151+ (|:) :: MonadAsync m => m a -> t m a -> t m a
152+ -- We can define (|:) just as 'consM' but it is defined explicitly for each
153+ -- type because we want to use SPECIALIZE pragma on the definition.
154+
155+-- | Same as 'IsStream'.
156+--
157+-- @since 0.1.0
158+{-# DEPRECATED Streaming "Please use IsStream instead." #-}
159+type Streaming = IsStream
160+
161+-------------------------------------------------------------------------------
162+-- Type adapting combinators
163+-------------------------------------------------------------------------------
164+
165+-- XXX Move/reset the State here by reconstructing the stream with cleared
166+-- state. Can we make sure we do not do that when t1 = t2? If we do this then
167+-- we do not need to do that explicitly using svarStyle. It would act as
168+-- unShare when the stream type is the same.
169+--
170+-- | Adapt any specific stream type to any other specific stream type.
171+--
172+-- @since 0.1.0
173+adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a
174+adapt = fromStream . toStream
175+
176+------------------------------------------------------------------------------
177+-- Building a stream
178+------------------------------------------------------------------------------
179+
180+-- XXX The State is always parameterized by "Stream" which means State is not
181+-- different for different stream types. So we have to manually make sure that
182+-- when converting from one stream to another we migrate the state correctly.
183+-- This can be fixed if we use a different SVar type for different streams.
184+-- Currently we always use "SVar Stream" and therefore a different State type
185+-- parameterized by that stream.
186+--
187+-- XXX Since t is coercible we should be able to coerce k
188+-- mkStream k = fromStream $ MkStream $ coerce k
189+--
190+-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
191+-- continuation and a yield continuation.
192+{-# INLINE_EARLY mkStream #-}
193+mkStream :: IsStream t
194+ => (forall r. State Stream m a
195+ -> (a -> t m a -> m r)
196+ -> (a -> m r)
197+ -> m r
198+ -> m r)
199+ -> t m a
200+mkStream k = fromStream $ MkStream $ \st yld sng stp ->
201+ let yieldk a r = yld a (toStream r)
202+ in k st yieldk sng stp
203+
204+{-# RULES "mkStream from stream" mkStream = mkStreamFromStream #-}
205+mkStreamFromStream :: IsStream t
206+ => (forall r. State Stream m a
207+ -> (a -> Stream m a -> m r)
208+ -> (a -> m r)
209+ -> m r
210+ -> m r)
211+ -> t m a
212+mkStreamFromStream k = fromStream $ MkStream k
213+
214+{-# RULES "mkStream stream" mkStream = mkStreamStream #-}
215+mkStreamStream
216+ :: (forall r. State Stream m a
217+ -> (a -> Stream m a -> m r)
218+ -> (a -> m r)
219+ -> m r
220+ -> m r)
221+ -> Stream m a
222+mkStreamStream = MkStream
223+
224+-- | A terminal function that has no continuation to follow.
225+type StopK m = forall r. m r -> m r
226+
227+-- | A monadic continuation, it is a function that yields a value of type "a"
228+-- and calls the argument (a -> m r) as a continuation with that value. We can
229+-- also think of it as a callback with a handler (a -> m r). Category
230+-- theorists call it a codensity type, a special type of right kan extension.
231+type YieldK m a = forall r. (a -> m r) -> m r
232+
233+_wrapM :: Monad m => m a -> YieldK m a
234+_wrapM m = \k -> m >>= k
235+
236+-- | Make an empty stream from a stop function.
237+fromStopK :: IsStream t => StopK m -> t m a
238+fromStopK k = mkStream $ \_ _ _ stp -> k stp
239+
240+-- | Make a singleton stream from a yield function.
241+fromYieldK :: IsStream t => YieldK m a -> t m a
242+fromYieldK k = mkStream $ \_ _ sng _ -> k sng
243+
244+-- | Add a yield function at the head of the stream.
245+consK :: IsStream t => YieldK m a -> t m a -> t m a
246+consK k r = mkStream $ \_ yld _ _ -> k (\x -> yld x r)
247+
248+-- XXX Build a stream from a repeating callback function.
249+
250+------------------------------------------------------------------------------
251+-- Folding a stream
252+------------------------------------------------------------------------------
253+
254+-- | Fold a stream by providing an SVar, a stop continuation, a singleton
255+-- continuation and a yield continuation. The stream would share the current
256+-- SVar passed via the State.
257+{-# INLINE_EARLY foldStreamShared #-}
258+foldStreamShared
259+ :: IsStream t
260+ => State Stream m a
261+ -> (a -> t m a -> m r)
262+ -> (a -> m r)
263+ -> m r
264+ -> t m a
265+ -> m r
266+foldStreamShared st yld sng stp m =
267+ let yieldk a x = yld a (fromStream x)
268+ MkStream k = toStream m
269+ in k st yieldk sng stp
270+
271+-- XXX write a similar rule for foldStream as well?
272+{-# RULES "foldStreamShared from stream"
273+ foldStreamShared = foldStreamSharedStream #-}
274+foldStreamSharedStream
275+ :: State Stream m a
276+ -> (a -> Stream m a -> m r)
277+ -> (a -> m r)
278+ -> m r
279+ -> Stream m a
280+ -> m r
281+foldStreamSharedStream st yld sng stp m =
282+ let MkStream k = toStream m
283+ in k st yld sng stp
284+
285+-- | Fold a stream by providing a State, stop continuation, a singleton
286+-- continuation and a yield continuation. The stream will not use the SVar
287+-- passed via State.
288+{-# INLINE foldStream #-}
289+foldStream
290+ :: IsStream t
291+ => State Stream m a
292+ -> (a -> t m a -> m r)
293+ -> (a -> m r)
294+ -> m r
295+ -> t m a
296+ -> m r
297+foldStream st yld sng stp m =
298+ let yieldk a x = yld a (fromStream x)
299+ MkStream k = toStream m
300+ in k (adaptState st) yieldk sng stp
301+
302+-- Run the stream using a run function associated with the SVar that runs the
303+-- streams with a captured snapshot of the monadic state.
304+{-# INLINE foldStreamSVar #-}
305+foldStreamSVar
306+ :: (IsStream t, MonadIO m)
307+ => SVar Stream m a
308+ -> State Stream m a -- state
309+ -> (a -> t m a -> m r) -- yield
310+ -> (a -> m r) -- singleton
311+ -> m r -- stop
312+ -> t m a
313+ -> m ()
314+foldStreamSVar sv st yld sng stp m =
315+ let mrun = runInIO $ svarMrun sv
316+ in void $ liftIO $ mrun $ foldStreamShared st yld sng stp m
317+
318+-------------------------------------------------------------------------------
319+-- Instances
320+-------------------------------------------------------------------------------
321+
322+-- NOTE: specializing the function outside the instance definition seems to
323+-- improve performance quite a bit at times, even if we have the same
324+-- SPECIALIZE in the instance definition.
325+{-# INLINE consMStream #-}
326+{-# SPECIALIZE consMStream :: IO a -> Stream IO a -> Stream IO a #-}
327+consMStream :: (Monad m) => m a -> Stream m a -> Stream m a
328+consMStream m r = MkStream $ \_ yld _ _ -> m >>= \a -> yld a r
329+
330+-------------------------------------------------------------------------------
331+-- IsStream Stream
332+-------------------------------------------------------------------------------
333+
334+instance IsStream Stream where
335+ toStream = id
336+ fromStream = id
337+
338+ {-# INLINE consM #-}
339+ {-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
340+ consM :: Monad m => m a -> Stream m a -> Stream m a
341+ consM = consMStream
342+
343+ {-# INLINE (|:) #-}
344+ {-# SPECIALIZE (|:) :: IO a -> Stream IO a -> Stream IO a #-}
345+ (|:) :: Monad m => m a -> Stream m a -> Stream m a
346+ (|:) = consMStream
347+
348+------------------------------------------------------------------------------
349+-- Semigroup
350+------------------------------------------------------------------------------
351+
352+-- | Polymorphic version of the 'Semigroup' operation '<>' of 'SerialT'.
353+-- Appends two streams sequentially, yielding all elements from the first
354+-- stream, and then all elements from the second stream.
355+--
356+-- @since 0.2.0
357+{-# INLINE serial #-}
358+serial :: IsStream t => t m a -> t m a -> t m a
359+serial m1 m2 = go m1
360+ where
361+ go m = mkStream $ \st yld sng stp ->
362+ let stop = foldStream st yld sng stp m2
363+ single a = yld a m2
364+ yieldk a r = yld a (go r)
365+ in foldStream st yieldk single stop m
366+
367+instance Semigroup (Stream m a) where
368+ (<>) = serial
369+
370+------------------------------------------------------------------------------
371+-- Monoid
372+------------------------------------------------------------------------------
373+
374+-- | An empty stream.
375+--
376+-- @
377+-- > toList nil
378+-- []
379+-- @
380+--
381+-- @since 0.1.0
382+{-# INLINE nil #-}
383+nil :: IsStream t => t m a
384+nil = mkStream $ \_ _ _ stp -> stp
385+
386+instance Monoid (Stream m a) where
387+ mempty = nil
388+ mappend = (<>)
389+
390+-------------------------------------------------------------------------------
391+-- Functor
392+-------------------------------------------------------------------------------
393+
394+{-# INLINE map #-}
395+map :: IsStream t => (a -> b) -> t m a -> t m b
396+map f m = go m
397+ where
398+ go m1 =
399+ mkStream $ \st yld sng stp ->
400+ let single = sng . f
401+ yieldk a r = yld (f a) (go r)
402+ in foldStream (adaptState st) yieldk single stp m1
403+
404+-- in fact use the Stream type everywhere and only use polymorphism in the high
405+-- level modules/prelude.
406+instance Monad m => Functor (Stream m) where
407+ fmap = map
408+
409+-------------------------------------------------------------------------------
410+-- Transformers
411+-------------------------------------------------------------------------------
412+
413+{-# INLINE yieldM #-}
414+yieldM :: (Monad m, IsStream t) => m a -> t m a
415+yieldM m = fromStream $ mkStream $ \_ _ single _ -> m >>= single
416+
417+instance MonadTrans Stream where
418+ lift = yieldM
src/Streamly/Streams/Zip.hs+24−15
@@ -48,10 +48,10 @@ import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
4848 readListPrecDefault)
4949import Prelude hiding (map, repeat, zipWith)
5050
51−import Streamly.Streams.StreamK (IsStream(..), Stream(..))
51+import Streamly.Streams.StreamK (IsStream(..), Stream, mkStream, foldStream)
5252import Streamly.Streams.Async (mkAsync')
5353import Streamly.Streams.Serial (map)
54−import Streamly.SVar (MonadAsync, rstState)
54+import Streamly.SVar (MonadAsync, adaptState)
5555
5656import qualified Streamly.Streams.Prelude as P
5757import qualified Streamly.Streams.StreamK as K
@@ -106,6 +106,9 @@ zipSerially = K.adapt
106106zipping :: IsStream t => ZipSerialM m a -> t m a
107107zipping = zipSerially
108108
109+consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
110+consMZip m ms = fromStream $ K.consMStream m (toStream ms)
111+
109112instance IsStream ZipSerialM where
110113 toStream = getZipSerialM
111114 fromStream = ZipSerialM
@@ -113,12 +116,12 @@ instance IsStream ZipSerialM where
113116 {-# INLINE consM #-}
114117 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
115118 consM :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
116− consM m r = fromStream $ K.consMSerial m (toStream r)
119+ consM = consMZip
117120
118121 {-# INLINE (|:) #-}
119122 {-# SPECIALIZE (|:) :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
120123 (|:) :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
121− m |: r = fromStream $ K.consMSerial m (toStream r)
124+ (|:) = consMZip
122125
123126LIST_INSTANCES(ZipSerialM)
124127
@@ -127,7 +130,7 @@ instance Monad m => Functor (ZipSerialM m) where
127130
128131instance Monad m => Applicative (ZipSerialM m) where
129132 pure = ZipSerialM . K.repeat
130− m1 <*> m2 = fromStream $ K.zipWith id (toStream m1) (toStream m2)
133+ (<*>) = K.zipWith id
131134
132135FOLDABLE_INSTANCE(ZipSerialM)
133136TRAVERSABLE_INSTANCE(ZipSerialM)
@@ -140,23 +143,25 @@ TRAVERSABLE_INSTANCE(ZipSerialM)
140143-- are generated concurrently.
141144--
142145-- @since 0.1.0
146+{-# INLINABLE zipAsyncWith #-}
143147zipAsyncWith :: (IsStream t, MonadAsync m)
144148 => (a -> b -> c) -> t m a -> t m b -> t m c
145−zipAsyncWith f m1 m2 = fromStream $ Stream $ \st stp sng yld -> do
146− ma <- mkAsync' (rstState st) m1
147− mb <- mkAsync' (rstState st) m2
148− unStream (toStream (K.zipWith f ma mb)) (rstState st) stp sng yld
149+zipAsyncWith f m1 m2 = mkStream $ \st stp sng yld -> do
150+ ma <- mkAsync' (adaptState st) m1
151+ mb <- mkAsync' (adaptState st) m2
152+ foldStream st stp sng yld (K.zipWith f ma mb)
149153
150154-- | Like 'zipWithM' but zips concurrently i.e. both the streams being zipped
151155-- are generated concurrently.
152156--
153157-- @since 0.4.0
158+{-# INLINABLE zipAsyncWithM #-}
154159zipAsyncWithM :: (IsStream t, MonadAsync m)
155160 => (a -> b -> m c) -> t m a -> t m b -> t m c
156−zipAsyncWithM f m1 m2 = fromStream $ Stream $ \st stp sng yld -> do
157− ma <- mkAsync' (rstState st) m1
158− mb <- mkAsync' (rstState st) m2
159− unStream (toStream (K.zipWithM f ma mb)) (rstState st) stp sng yld
161+zipAsyncWithM f m1 m2 = mkStream $ \st stp sng yld -> do
162+ ma <- mkAsync' (adaptState st) m1
163+ mb <- mkAsync' (adaptState st) m2
164+ foldStream st stp sng yld (K.zipWithM f ma mb)
160165
161166------------------------------------------------------------------------------
162167-- Parallely Zipping Streams
@@ -199,6 +204,10 @@ zipAsyncly = K.adapt
199204{-# DEPRECATED zippingAsync "Please use zipAsyncly instead." #-}
200205zippingAsync :: IsStream t => ZipAsyncM m a -> t m a
201206zippingAsync = zipAsyncly
207+
208+consMZipAsync :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
209+consMZipAsync m ms = fromStream $ K.consMStream m (toStream ms)
210+
202211instance IsStream ZipAsyncM where
203212 toStream = getZipAsyncM
204213 fromStream = ZipAsyncM
@@ -206,12 +215,12 @@ instance IsStream ZipAsyncM where
206215 {-# INLINE consM #-}
207216 {-# SPECIALIZE consM :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
208217 consM :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
209− consM m r = fromStream $ K.consMSerial m (toStream r)
218+ consM = consMZipAsync
210219
211220 {-# INLINE (|:) #-}
212221 {-# SPECIALIZE (|:) :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
213222 (|:) :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
214− m |: r = fromStream $ K.consMSerial m (toStream r)
223+ (|:) = consMZipAsync
215224
216225instance Monad m => Functor (ZipAsyncM m) where
217226 fmap = map
streamly.cabal+7
@@ -128,7 +128,9 @@ library
128128 other-modules: Streamly.SVar
129129
130130 -- Base streams
131+ , Streamly.Streams.StreamK.Type
131132 , Streamly.Streams.StreamK
133+ , Streamly.Streams.StreamD.Type
132134 , Streamly.Streams.StreamD
133135 , Streamly.Streams.Prelude
134136
@@ -479,7 +481,9 @@ benchmark base
479481 hs-source-dirs: benchmark, src
480482 main-is: BaseStreams.hs
481483 other-modules: Streamly.SVar
484+ , Streamly.Streams.StreamK.Type
482485 , Streamly.Streams.StreamK
486+ , Streamly.Streams.StreamD.Type
483487 , Streamly.Streams.StreamD
484488 , Streamly.Streams.Prelude
485489
@@ -535,7 +539,9 @@ executable nano-bench
535539 hs-source-dirs: benchmark, src
536540 main-is: NanoBenchmarks.hs
537541 other-modules: Streamly.SVar
542+ , Streamly.Streams.StreamK.Type
538543 , Streamly.Streams.StreamK
544+ , Streamly.Streams.StreamD.Type
539545 , Streamly.Streams.StreamD
540546 default-language: Haskell2010
541547 ghc-options: -O2 -Wall
@@ -548,6 +554,7 @@ executable nano-bench
548554 , ghc-prim >= 0.2 && < 0.6
549555 , containers >= 0.5 && < 0.7
550556 , heaps >= 0.3 && < 0.4
557+ , random >= 1.0 && < 2.0
551558
552559 -- concurrency
553560 , atomic-primops >= 0.8 && < 0.9