on master help sign in
use folds and map from direct style stream
commit3ae953064d16e2183094912b93102768646913b6 authorHarendra Kumar <harendra.kumar@gmail.com> dateSun 24 Jun 2018, 22:43 (8 years ago) parentbd11ec2
14 files changed+420−210
Changelog.md+1 benchmark/Linear.hs+8−2 benchmark/LinearOps.hs+15−4 src/Streamly/Prelude.hs+43−80 src/Streamly/Streams/Ahead.hs+9−6 src/Streamly/Streams/Async.hs+12−17 src/Streamly/Streams/Instances.hs+5−2 src/Streamly/Streams/Parallel.hs+8−13 src/Streamly/Streams/Prelude.hs+59−7 src/Streamly/Streams/Serial.hs+22−29 src/Streamly/Streams/StreamD.hs+87−11 src/Streamly/Streams/StreamK.hs+127−9 src/Streamly/Streams/Zip.hs+23−30 streamly.cabal+1
Changelog.md+1
@@ -10,6 +10,7 @@
1010* Add `repeat` to generate an infinite stream by repeating a pure value
1111* Add `fromList` and `fromListM` to generate streams from lists, faster than
1212 `fromFoldable` and `fromFoldableM`
13+* Add `map` as a synonym of fmap
1314* Significant performance improvements
1415
1516## 0.3.0
benchmark/Linear.hs+8−2
@@ -15,6 +15,7 @@ import Gauge
1515
1616-- We need a monadic bind here to make sure that the function f does not get
1717-- completely optimized out by the compiler in some cases.
18+{-# INLINE benchIO #-}
1819benchIO :: (IsStream t, NFData b) => String -> (t IO Int -> IO b) -> Benchmark
1920benchIO name f = bench name $ nfIO $ randomRIO (1,1000) >>= f . Ops.source
2021
@@ -50,13 +51,18 @@ main = do
5051 , benchSrcIO serially "foldMapWithM" Ops.sourceFoldMapWithM
5152 ]
5253 , bgroup "elimination"
53− [ benchIO "toList" Ops.toList
54− , benchIO "fold" Ops.foldl
54+ [ benchIO "toNull" $ Ops.toNull serially
55+ , benchIO "mapM_" Ops.mapM_
56+ , benchIO "toList" Ops.toList
57+ , benchIO "foldr" Ops.foldr
58+ , benchIO "foldrM" Ops.foldrM
59+ , benchIO "foldl'" Ops.foldl
5560 , benchIO "last" Ops.last
5661 ]
5762 , bgroup "transformation"
5863 [ benchIO "scan" Ops.scan
5964 , benchIO "map" Ops.map
65+ , benchIO "fmap" Ops.fmap
6066 , benchIO "mapM" (Ops.mapM serially)
6167 , benchIO "concat" Ops.concat
6268 ]
benchmark/LinearOps.hs+15−4
@@ -26,6 +26,7 @@ maxValue = value + 1000
2626
2727{-# INLINE scan #-}
2828{-# INLINE map #-}
29+{-# INLINE fmap #-}
2930{-# INLINE filterEven #-}
3031{-# INLINE filterAllOut #-}
3132{-# INLINE filterAllIn #-}
@@ -39,7 +40,7 @@ maxValue = value + 1000
3940{-# INLINE composeAllInFilters #-}
4041{-# INLINE composeAllOutFilters #-}
4142{-# INLINE composeMapAllInFilter #-}
42−scan, map, filterEven, filterAllOut,
43+scan, map, fmap, filterEven, filterAllOut,
4344 filterAllIn, takeOne, takeAll, takeWhileTrue, dropAll, dropWhileTrue, zip,
4445 concat, composeAllInFilters, composeAllOutFilters,
4546 composeMapAllInFilter
@@ -50,13 +51,17 @@ scan, map, filterEven, filterAllOut,
5051composeMapM :: S.MonadAsync m => Stream m Int -> m ()
5152
5253{-# INLINE toList #-}
53−toList :: Monad m => Stream m Int -> m [Int]
54+{-# INLINE foldr #-}
55+{-# INLINE foldrM #-}
56+toList, foldr, foldrM :: Monad m => Stream m Int -> m [Int]
5457{-# INLINE foldl #-}
5558foldl :: Monad m => Stream m Int -> m Int
5659{-# INLINE last #-}
5760last :: Monad m => Stream m Int -> m (Maybe Int)
5861{-# INLINE toNull #-}
5962toNull :: Monad m => (t m Int -> S.SerialT m Int) -> t m Int -> m ()
63+{-# INLINE mapM_ #-}
64+mapM_ :: Monad m => Stream m a -> m ()
6065{-# INLINE mapM #-}
6166mapM :: (S.IsStream t, S.MonadAsync m)
6267 => (t m Int -> S.SerialT m Int) -> t m Int -> m ()
@@ -72,6 +77,7 @@ type Stream m a = S.SerialT m a
7277{-# INLINE source #-}
7378source :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
7479source n = S.serially $ sourceUnfoldrM n
80+-- source n = S.serially $ sourceFromList n
7581
7682{-# INLINE sourceFromList #-}
7783sourceFromList :: (Monad m, S.IsStream t) => Int -> t m Int
@@ -126,7 +132,10 @@ runStream = S.runStream
126132-------------------------------------------------------------------------------
127133
128134toNull t = runStream . t
135+mapM_ = S.mapM_ (\_ -> return ())
129136toList = S.toList
137+foldr = S.foldr (:) []
138+foldrM = S.foldrM (\a xs -> return (a : xs)) []
130139foldl = S.foldl' (+) 0
131140last = S.last
132141
@@ -139,7 +148,8 @@ transform :: Monad m => Stream m a -> m ()
139148transform = runStream
140149
141150scan = transform . S.scanl' (+) 0
142−map = transform . fmap (+1)
151+fmap = transform . Prelude.fmap (+1)
152+map = transform . S.map (+1)
143153mapM t = transform . t . S.mapM return
144154filterEven = transform . S.filter even
145155filterAllOut = transform . S.filter (> maxValue)
@@ -169,7 +179,8 @@ compose f = transform . f . f . f . f
169179composeMapM = compose (S.mapM return)
170180composeAllInFilters = compose (S.filter (<= maxValue))
171181composeAllOutFilters = compose (S.filter (> maxValue))
172−composeMapAllInFilter = compose (S.filter (<= maxValue) . fmap (subtract 1))
182+composeMapAllInFilter =
183+ compose (S.filter (<= maxValue) . Prelude.fmap (subtract 1))
173184
174185{-# INLINABLE composeScaling #-}
175186composeScaling :: Monad m => Int -> Stream m Int -> m ()
src/Streamly/Prelude.hs+43−80
@@ -47,11 +47,11 @@ module Streamly.Prelude
4747 (
4848 -- * Construction
4949 -- | Primitives to construct or inspect a stream.
50− nil
50+ K.nil
5151 , K.yield
5252 , K.yieldM
53− , cons
54− , (.:)
53+ , K.cons
54+ , (K..:)
5555 , consM
5656 , (|:)
5757
@@ -116,6 +116,7 @@ module Streamly.Prelude
116116 , reverse
117117
118118 -- * Mapping
119+ , Serial.map
119120 , mapM
120121 , mapMaybe
121122 , mapMaybeM
@@ -140,25 +141,24 @@ module Streamly.Prelude
140141 )
141142where
142143
143−import Control.Monad (void)
144−import Control.Monad.IO.Class (MonadIO(..))
145−import Data.Maybe (isJust, fromJust)
146−import Prelude hiding (filter, drop, dropWhile, take,
147− takeWhile, zipWith, foldr, foldl,
148− mapM, mapM_, sequence, all, any,
149− sum, product, elem, notElem,
150− maximum, minimum, head, last,
151− tail, length, null, reverse,
152− iterate)
144+import Control.Monad.IO.Class (MonadIO(..))
145+import Data.Maybe (isJust, fromJust)
146+import Prelude
147+ hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
148+ foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
149+ notElem, maximum, minimum, head, last, tail, length, null,
150+ reverse, iterate)
153151import qualified Prelude
154152import qualified System.IO as IO
155153
156−import Streamly.Streams.StreamK (IsStream(..), cons, nil, (.:))
154+import Streamly.SVar (MonadAsync)
155+import Streamly.Streams.StreamK (IsStream(..))
156+import Streamly.Streams.Serial (SerialT)
157+import Streamly.Streams.Zip (zipWith, zipWithM, zipAsyncWith, zipAsyncWithM)
158+
157159import qualified Streamly.Streams.StreamK as K
158160import qualified Streamly.Streams.StreamD as D
159−import Streamly.Streams.Zip
160−import Streamly.Streams.Serial
161−import Streamly.SVar (MonadAsync)
161+import qualified Streamly.Streams.Serial as Serial
162162
163163------------------------------------------------------------------------------
164164-- Construction
@@ -260,7 +260,7 @@ fromListM = fromStream . D.toStreamK . D.fromListM
260260-- @since 0.3.0
261261{-# INLINE fromFoldableM #-}
262262fromFoldableM :: (IsStream t, MonadAsync m, Foldable f) => f (m a) -> t m a
263−fromFoldableM = Prelude.foldr consM nil
263+fromFoldableM = Prelude.foldr consM K.nil
264264
265265-- | Same as 'fromFoldable'.
266266--
@@ -284,7 +284,7 @@ each = K.fromFoldable
284284replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
285285replicateM n m = go n
286286 where
287− go cnt = if cnt <= 0 then nil else m |: go (cnt - 1)
287+ go cnt = if cnt <= 0 then K.nil else m |: go (cnt - 1)
288288
289289-- | Generate a stream by repeatedly executing a monadic action forever.
290290--
@@ -360,14 +360,11 @@ fromHandle h = fromStream go
360360-- @
361361--
362362-- @since 0.1.0
363+{-# INLINE foldr #-}
363364foldr :: Monad m => (a -> b -> b) -> b -> SerialT m a -> m b
364−foldr step acc m = go (toStream m)
365− where
366− go m1 =
367− let stop = return acc
368− single a = return (step a acc)
369− yieldk a r = go r >>= \b -> return (step a b)
370− in (K.unStream m1) Nothing stop single yieldk
365+-- XXX somehow this definition does not perform well, need to investigate
366+-- foldr step acc m = D.foldr step acc $ D.fromStreamK (toStream m)
367+foldr f = foldrM (\a b -> return (f a b))
371368
372369-- | Lazy right fold with a monadic step function. For example, to fold a
373370-- stream into a list:
@@ -380,13 +377,7 @@ foldr step acc m = go (toStream m)
380377-- @since 0.2.0
381378{-# INLINE foldrM #-}
382379foldrM :: Monad m => (a -> b -> m b) -> b -> SerialT m a -> m b
383−foldrM step acc m = go (toStream m)
384− where
385− go m1 =
386− let stop = return acc
387− single a = step a acc
388− yieldk a r = go r >>= step a
389− in (K.unStream m1) Nothing stop single yieldk
380+foldrM step acc m = D.foldrM step acc $ D.fromStreamK (toStream m)
390381
391382-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
392383-- user supplied extraction function (the third argument) at each step. This is
@@ -397,7 +388,7 @@ foldrM step acc m = go (toStream m)
397388{-# INLINE scanx #-}
398389scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
399390scanx step begin done m =
400− cons (done begin) $ fromStream $ go (toStream m) begin
391+ K.cons (done begin) $ fromStream $ go (toStream m) begin
401392 where
402393 go m1 !acc = K.Stream $ \_ stp sng yld ->
403394 let single a = sng (done $ step acc a)
@@ -430,24 +421,7 @@ scanl' step begin m = scanx step begin id m
430421-- @since 0.2.0
431422{-# INLINE foldx #-}
432423foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
433−foldx step begin done m = get $ go (toStream m) begin
434− where
435− {-# NOINLINE get #-}
436− get m1 =
437− let single = return . done
438− in (K.unStream m1) Nothing undefined single undefined
439−
440− -- Note, this can be implemented by making a recursive call to "go",
441− -- however that is more expensive because of unnecessary recursion
442− -- that cannot be tail call optimized. Unfolding recursion explicitly via
443− -- continuations is much more efficient.
444− go m1 !acc = K.Stream $ \_ _ sng yld ->
445− let stop = sng acc
446− single a = sng $ step acc a
447− yieldk a r =
448− let stream = go r (step acc a)
449− in (K.unStream stream) Nothing undefined sng yld
450− in (K.unStream m1) Nothing stop single yieldk
424+foldx = K.foldx
451425
452426-- |
453427-- @since 0.1.0
@@ -460,20 +434,14 @@ foldl = foldx
460434-- @since 0.2.0
461435{-# INLINE foldl' #-}
462436foldl' :: Monad m => (b -> a -> b) -> b -> SerialT m a -> m b
463−foldl' step begin m = foldx step begin id m
437+foldl' step begin m = D.foldl' step begin $ D.fromStreamK (toStream m)
464438
465439-- XXX replace the recursive "go" with explicit continuations.
466440-- | Like 'foldx', but with a monadic step function.
467441--
468442-- @since 0.2.0
469443foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
470−foldxM step begin done m = go begin (toStream m)
471− where
472− go !acc m1 =
473− let stop = acc >>= done
474− single a = acc >>= \b -> step b a >>= done
475− yieldk a r = acc >>= \b -> go (step b a) r
476− in (K.unStream m1) Nothing stop single yieldk
444+foldxM = K.foldxM
477445
478446-- |
479447-- @since 0.1.0
@@ -485,7 +453,7 @@ foldlM = foldxM
485453--
486454-- @since 0.2.0
487455foldlM' :: Monad m => (b -> a -> m b) -> b -> SerialT m a -> m b
488−foldlM' step begin m = foldxM step (return begin) return m
456+foldlM' step begin m = D.foldlM' step begin $ D.fromStreamK (toStream m)
489457
490458-- | Decompose a stream into its head and tail. If the stream is empty, returns
491459-- 'Nothing'. If the stream is non-empty, returns @Just (a, ma)@, where @a@ is
@@ -495,7 +463,7 @@ foldlM' step begin m = foldxM step (return begin) return m
495463uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
496464uncons m =
497465 let stop = return Nothing
498− single a = return (Just (a, nil))
466+ single a = return (Just (a, K.nil))
499467 yieldk a r = return (Just (a, fromStream r))
500468 in (K.unStream (toStream m)) Nothing stop single yieldk
501469
@@ -518,9 +486,9 @@ toHandle h m = go (toStream m)
518486-- | Convert a stream into a list in the underlying monad.
519487--
520488-- @since 0.1.0
521−{-# INLINABLE toList #-}
489+{-# INLINE toList #-}
522490toList :: Monad m => SerialT m a -> m [a]
523−toList = foldrM (\a xs -> return (a : xs)) []
491+toList m = D.toList $ D.fromStreamK (toStream m)
524492
525493-- | Take first 'n' elements from the stream and discard the rest.
526494--
@@ -644,7 +612,7 @@ head m =
644612tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
645613tail m =
646614 let stop = return Nothing
647− single _ = return $ Just nil
615+ single _ = return $ Just K.nil
648616 yieldk _ r = return $ Just $ fromStream r
649617 in (K.unStream (toStream m)) Nothing stop single yieldk
650618
@@ -653,7 +621,7 @@ tail m =
653621-- @since 0.1.1
654622{-# INLINE last #-}
655623last :: Monad m => SerialT m a -> m (Maybe a)
656−last = foldl (\_ y -> Just y) Nothing id
624+last m = D.last $ D.fromStreamK (toStream m)
657625
658626-- | Determine whether the stream is empty.
659627--
@@ -761,14 +729,14 @@ maximum m = go Nothing (toStream m)
761729-- /Concurrent (do not use with 'parallely' on infinite streams)/
762730--
763731-- @since 0.1.0
764−{-# INLINE mapM #-}
732+{-# INLINE_EARLY mapM #-}
765733mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
766−mapM f m = go (toStream m)
767− where
768− go m1 = fromStream $ K.Stream $ \svr stp sng yld ->
769− let single a = f a >>= sng
770− yieldk a r = K.unStream (toStream (f a |: (go r))) svr stp sng yld
771− in (K.unStream m1) Nothing stp single yieldk
734+mapM = K.mapM
735+
736+{-# RULES "mapM serial" mapM = mapMSerial #-}
737+{-# INLINE mapMSerial #-}
738+mapMSerial :: Monad m => (a -> m b) -> SerialT m a -> SerialT m b
739+mapMSerial = Serial.mapM
772740
773741-- | Map a 'Maybe' returning function to a stream, filter out the 'Nothing'
774742-- elements, and return a stream of values extracted from 'Just'.
@@ -802,14 +770,9 @@ mapMaybeM f = fmap fromJust . filter isJust . mapM f
802770-- output of the action.
803771--
804772-- @since 0.1.0
773+{-# INLINE mapM_ #-}
805774mapM_ :: Monad m => (a -> m b) -> SerialT m a -> m ()
806−mapM_ f m = go (toStream m)
807− where
808− go m1 =
809− let stop = return ()
810− single a = void (f a)
811− yieldk a r = f a >> go r
812− in (K.unStream m1) Nothing stop single yieldk
775+mapM_ f m = D.mapM_ f $ D.fromStreamK (toStream m)
813776
814777-- | Reduce a stream of monadic actions to a stream of the output of those
815778-- actions.
src/Streamly/Streams/Ahead.hs+9−6
@@ -44,13 +44,16 @@ import Data.Semigroup (Semigroup(..))
4444import qualified Data.Heap as H
4545
4646import Streamly.Streams.SVar (fromSVar)
47−import Streamly.Streams.StreamK
47+import Streamly.Streams.Serial (map)
4848import Streamly.SVar
49+import Streamly.Streams.StreamK (IsStream(..), Stream(..))
50+import qualified Streamly.Streams.StreamK as K
4951
5052#ifdef DIAGNOSTICS
5153import Control.Monad (when)
5254import Data.IORef (writeIORef, readIORef)
5355#endif
56+import Prelude hiding (map)
5457
5558#include "Instances.hs"
5659
@@ -128,7 +131,7 @@ workLoopAhead sv q heap = runHeap
128131 else liftIO $ sendStop sv
129132
130133 singleToHeap seqNo a = toHeap seqNo (AheadEntryPure a)
131− yieldToHeap seqNo a r = toHeap seqNo (AheadEntryStream (a `cons` r))
134+ yieldToHeap seqNo a r = toHeap seqNo (AheadEntryStream (a `K.cons` r))
132135
133136 singleOutput seqNo a = do
134137 continue <- liftIO $ send sv (ChildYield a)
@@ -242,7 +245,7 @@ aheadS m1 m2 = Stream $ \svr stp sng yld -> do
242245-- of combining streams using ahead.
243246{-# INLINE consMAhead #-}
244247consMAhead :: MonadAsync m => m a -> Stream m a -> Stream m a
245−consMAhead m r = yieldM m `aheadS` r
248+consMAhead m r = K.yieldM m `aheadS` r
246249
247250------------------------------------------------------------------------------
248251-- AheadT
@@ -293,7 +296,7 @@ consMAhead m r = yieldM m `aheadS` r
293296--
294297-- @since 0.3.0
295298newtype AheadT m a = AheadT {getAheadT :: Stream m a}
296− deriving (Functor, MonadTrans)
299+ deriving (MonadTrans)
297300
298301-- | A serial IO stream of elements of type @a@ with concurrent lookahead. See
299302-- 'AheadT' documentation for more details.
@@ -305,7 +308,7 @@ type Ahead a = AheadT IO a
305308--
306309-- @since 0.3.0
307310aheadly :: IsStream t => AheadT m a -> t m a
308−aheadly = adapt
311+aheadly = K.adapt
309312
310313instance IsStream AheadT where
311314 toStream = getAheadT
@@ -339,7 +342,7 @@ instance MonadAsync m => Semigroup (AheadT m a) where
339342------------------------------------------------------------------------------
340343
341344instance MonadAsync m => Monoid (AheadT m a) where
342− mempty = nil
345+ mempty = K.nil
343346 mappend = (<>)
344347
345348------------------------------------------------------------------------------
src/Streamly/Streams/Async.hs+12−17
@@ -31,7 +31,6 @@ module Streamly.Streams.Async
3131 , WAsync
3232 , wAsyncly
3333 , wAsync
34− , runAsyncT -- deprecated
3534 )
3635where
3736
@@ -49,11 +48,14 @@ import Data.IORef (IORef, newIORef, readIORef)
4948import Data.Maybe (fromJust)
5049import Data.Semigroup (Semigroup(..))
5150
51+import Prelude hiding (map)
5252import qualified Data.Set as S
5353
5454import Streamly.Streams.SVar (fromSVar)
55−import Streamly.Streams.StreamK
55+import Streamly.Streams.Serial (map)
5656import Streamly.SVar
57+import Streamly.Streams.StreamK (IsStream(..), Stream(..), adapt)
58+import qualified Streamly.Streams.StreamK as K
5759
5860#include "Instances.hs"
5961
@@ -323,7 +325,7 @@ async m1 m2 = fromStream $
323325-- of combining streams using async.
324326{-# INLINE consMAsync #-}
325327consMAsync :: MonadAsync m => m a -> Stream m a -> Stream m a
326−consMAsync m r = yieldM m `asyncS` r
328+consMAsync m r = K.yieldM m `asyncS` r
327329
328330------------------------------------------------------------------------------
329331-- AsyncT
@@ -379,7 +381,7 @@ consMAsync m r = yieldM m `asyncS` r
379381--
380382-- @since 0.1.0
381383newtype AsyncT m a = AsyncT {getAsyncT :: Stream m a}
382− deriving (Functor, MonadTrans)
384+ deriving (MonadTrans)
383385
384386-- | A demand driven left biased parallely composing IO stream of elements of
385387-- type @a@. See 'AsyncT' documentation for more details.
@@ -417,7 +419,7 @@ instance MonadAsync m => Semigroup (AsyncT m a) where
417419------------------------------------------------------------------------------
418420
419421instance MonadAsync m => Monoid (AsyncT m a) where
420− mempty = nil
422+ mempty = K.nil
421423 mappend = (<>)
422424
423425------------------------------------------------------------------------------
@@ -426,7 +428,7 @@ instance MonadAsync m => Monoid (AsyncT m a) where
426428
427429instance MonadAsync m => Monad (AsyncT m) where
428430 return = pure
429− (AsyncT m) >>= f = AsyncT $ bindWith asyncS m (getAsyncT . f)
431+ (AsyncT m) >>= f = AsyncT $ K.bindWith asyncS m (getAsyncT . f)
430432
431433------------------------------------------------------------------------------
432434-- Other instances
@@ -447,7 +449,7 @@ wAsyncS = joinStreamVarAsync WAsyncVar
447449-- of combining streams using wAsync.
448450{-# INLINE consMWAsync #-}
449451consMWAsync :: MonadAsync m => m a -> Stream m a -> Stream m a
450−consMWAsync m r = yieldM m `wAsyncS` r
452+consMWAsync m r = K.yieldM m `wAsyncS` r
451453
452454-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WAsyncT'.
453455-- Merges two streams concurrently choosing elements from both fairly.
@@ -505,7 +507,7 @@ wAsync m1 m2 = fromStream $ wAsyncS (toStream m1) (toStream m2)
505507--
506508-- @since 0.2.0
507509newtype WAsyncT m a = WAsyncT {getWAsyncT :: Stream m a}
508− deriving (Functor, MonadTrans)
510+ deriving (MonadTrans)
509511
510512-- | A round robin parallely composing IO stream of elements of type @a@.
511513-- See 'WAsyncT' documentation for more details.
@@ -543,7 +545,7 @@ instance MonadAsync m => Semigroup (WAsyncT m a) where
543545------------------------------------------------------------------------------
544546
545547instance MonadAsync m => Monoid (WAsyncT m a) where
546− mempty = nil
548+ mempty = K.nil
547549 mappend = (<>)
548550
549551------------------------------------------------------------------------------
@@ -553,7 +555,7 @@ instance MonadAsync m => Monoid (WAsyncT m a) where
553555instance MonadAsync m => Monad (WAsyncT m) where
554556 return = pure
555557 (WAsyncT m) >>= f =
556− WAsyncT $ bindWith wAsyncS m (getWAsyncT . f)
558+ WAsyncT $ K.bindWith wAsyncS m (getWAsyncT . f)
557559
558560------------------------------------------------------------------------------
559561-- Other instances
@@ -561,10 +563,3 @@ instance MonadAsync m => Monad (WAsyncT m) where
561563
562564MONAD_APPLICATIVE_INSTANCE(WAsyncT,MONADPARALLEL)
563565MONAD_COMMON_INSTANCES(WAsyncT, MONADPARALLEL)
564−
565−-- | Same as @runStream . asyncly@.
566−--
567−-- @since 0.1.0
568−{-# DEPRECATED runAsyncT "Please use 'runStream . asyncly' instead." #-}
569−runAsyncT :: Monad m => AsyncT m a -> m ()
570−runAsyncT = runStream
src/Streamly/Streams/Instances.hs+5−2
@@ -9,10 +9,13 @@
99
1010#define MONAD_APPLICATIVE_INSTANCE(STREAM,CONSTRAINT) \
1111instance (Monad m CONSTRAINT) => Applicative (STREAM m) where { \
12− pure = STREAM . yield; \
12+ pure = STREAM . K.yield; \
1313 (<*>) = ap }
1414
1515#define MONAD_COMMON_INSTANCES(STREAM,CONSTRAINT) \
16+instance Monad m => Functor (STREAM m) where { \
17+ fmap = map }; \
18+ \
1619instance (MonadBase b m, Monad m CONSTRAINT) => MonadBase b (STREAM m) where {\
1720 liftBase = liftBaseDefault }; \
1821 \
@@ -31,7 +34,7 @@ instance (MonadError e m CONSTRAINT) => MonadError e (STREAM m) where { \
3134 \
3235instance (MonadReader r m CONSTRAINT) => MonadReader r (STREAM m) where { \
3336 ask = lift ask; \
34− local f m = fromStream $ withLocal f (toStream m) }; \
37+ local f m = fromStream $ K.withLocal f (toStream m) }; \
3538 \
3639instance (MonadState s m CONSTRAINT) => MonadState s (STREAM m) where { \
3740 get = lift get; \
src/Streamly/Streams/Parallel.hs+8−13
@@ -24,7 +24,6 @@ module Streamly.Streams.Parallel
2424 , Parallel
2525 , parallely
2626 , parallel
27− , runParallelT -- deprecated
2827
2928 -- * Function application
3029 , mkParallel
@@ -45,10 +44,13 @@ import Control.Monad.State.Class (MonadState(..))
4544import Control.Monad.Trans.Class (MonadTrans(lift))
4645import Data.Functor (void)
4746import Data.Semigroup (Semigroup(..))
47+import Prelude hiding (map)
4848
4949import Streamly.Streams.SVar (fromSVar)
50−import Streamly.Streams.StreamK
50+import Streamly.Streams.Serial (map)
5151import Streamly.SVar
52+import Streamly.Streams.StreamK (IsStream(..), Stream(..), adapt)
53+import qualified Streamly.Streams.StreamK as K
5254
5355#include "Instances.hs"
5456
@@ -96,7 +98,7 @@ parallelStream = joinStreamVarPar ParallelVar
9698-- of combining streams using parallel.
9799{-# INLINE consMParallel #-}
98100consMParallel :: MonadAsync m => m a -> Stream m a -> Stream m a
99−consMParallel m r = yieldM m `parallelStream` r
101+consMParallel m r = K.yieldM m `parallelStream` r
100102
101103-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'
102104-- Merges two streams concurrently.
@@ -307,7 +309,7 @@ x |&. f = f |$. x
307309--
308310-- @since 0.1.0
309311newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
310− deriving (Functor, MonadTrans)
312+ deriving (MonadTrans)
311313
312314-- | A parallely composing IO stream of elements of type @a@.
313315-- See 'ParallelT' documentation for more details.
@@ -345,7 +347,7 @@ instance MonadAsync m => Semigroup (ParallelT m a) where
345347------------------------------------------------------------------------------
346348
347349instance MonadAsync m => Monoid (ParallelT m a) where
348− mempty = nil
350+ mempty = K.nil
349351 mappend = (<>)
350352
351353------------------------------------------------------------------------------
@@ -355,7 +357,7 @@ instance MonadAsync m => Monoid (ParallelT m a) where
355357instance MonadAsync m => Monad (ParallelT m) where
356358 return = pure
357359 (ParallelT m) >>= f
358− = ParallelT $ bindWith parallelStream m (getParallelT . f)
360+ = ParallelT $ K.bindWith parallelStream m (getParallelT . f)
359361
360362------------------------------------------------------------------------------
361363-- Other instances
@@ -363,10 +365,3 @@ instance MonadAsync m => Monad (ParallelT m) where
363365
364366MONAD_APPLICATIVE_INSTANCE(ParallelT,MONADPARALLEL)
365367MONAD_COMMON_INSTANCES(ParallelT, MONADPARALLEL)
366−
367−-- | Same as @runStream . parallely@.
368−--
369−-- @since 0.1.0
370−{-# DEPRECATED runParallelT "Please use 'runStream . parallely' instead." #-}
371−runParallelT :: Monad m => ParallelT m a -> m ()
372−runParallelT = runStream
src/Streamly/Streams/Prelude.hs+59−7
@@ -29,7 +29,13 @@ module Streamly.Streams.Prelude
2929 (
3030 -- * Elimination
3131 runStream
32− , runStreaming -- deprecated
32+ , runStreaming -- deprecated
33+ , runStreamT -- deprecated
34+ , runInterleavedT -- deprecated
35+ , runParallelT -- deprecated
36+ , runAsyncT -- deprecated
37+ , runZipStream -- deprecated
38+ , runZipAsync -- deprecated
3339
3440 -- * Fold Utilities
3541 , foldWith
@@ -38,8 +44,12 @@ module Streamly.Streams.Prelude
3844 )
3945where
4046
41−import Streamly.Streams.Serial (SerialT)
42−import Streamly.Streams.StreamK hiding (runStream)
47+import Streamly.Streams.StreamK (IsStream(..))
48+import Streamly.Streams.Serial (SerialT, WSerialT)
49+import Streamly.Streams.Parallel (ParallelT)
50+import Streamly.Streams.Async (AsyncT)
51+import Streamly.Streams.Zip (ZipSerialM, ZipAsyncM)
52+
4353import qualified Streamly.Streams.StreamD as D
4454import qualified Streamly.Streams.StreamK as K
4555
@@ -63,7 +73,49 @@ runStream m = D.runStream $ D.fromStreamK (toStream m)
6373-- @since 0.1.0
6474{-# DEPRECATED runStreaming "Please use runStream instead." #-}
6575runStreaming :: (Monad m, IsStream t) => t m a -> m ()
66−runStreaming = runStream . adapt
76+runStreaming = runStream . K.adapt
77+
78+-- | Same as @runStream@.
79+--
80+-- @since 0.1.0
81+{-# DEPRECATED runStreamT "Please use runStream instead." #-}
82+runStreamT :: Monad m => SerialT m a -> m ()
83+runStreamT = runStream
84+
85+-- | Same as @runStream . wSerially@.
86+--
87+-- @since 0.1.0
88+{-# DEPRECATED runInterleavedT "Please use 'runStream . interleaving' instead." #-}
89+runInterleavedT :: Monad m => WSerialT m a -> m ()
90+runInterleavedT = runStream . K.adapt
91+
92+-- | Same as @runStream . parallely@.
93+--
94+-- @since 0.1.0
95+{-# DEPRECATED runParallelT "Please use 'runStream . parallely' instead." #-}
96+runParallelT :: Monad m => ParallelT m a -> m ()
97+runParallelT = runStream . K.adapt
98+
99+-- | Same as @runStream . asyncly@.
100+--
101+-- @since 0.1.0
102+{-# DEPRECATED runAsyncT "Please use 'runStream . asyncly' instead." #-}
103+runAsyncT :: Monad m => AsyncT m a -> m ()
104+runAsyncT = runStream . K.adapt
105+
106+-- | Same as @runStream . zipping@.
107+--
108+-- @since 0.1.0
109+{-# DEPRECATED runZipStream "Please use 'runStream . zipSerially instead." #-}
110+runZipStream :: Monad m => ZipSerialM m a -> m ()
111+runZipStream = runStream . K.adapt
112+
113+-- | Same as @runStream . zippingAsync@.
114+--
115+-- @since 0.1.0
116+{-# DEPRECATED runZipAsync "Please use 'runStream . zipAsyncly instead." #-}
117+runZipAsync :: Monad m => ZipAsyncM m a -> m ()
118+runZipAsync = runStream . K.adapt
67119
68120------------------------------------------------------------------------------
69121-- Fold Utilities
@@ -78,7 +130,7 @@ runStreaming = runStream . adapt
78130{-# INLINABLE foldWith #-}
79131foldWith :: (IsStream t, Foldable f)
80132 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
81−foldWith f = foldr f nil
133+foldWith f = foldr f K.nil
82134
83135-- | A variant of 'foldMap' that allows you to map a monadic streaming action
84136-- on a 'Foldable' container and then fold it using the specified stream sum
@@ -90,7 +142,7 @@ foldWith f = foldr f nil
90142{-# INLINABLE foldMapWith #-}
91143foldMapWith :: (IsStream t, Foldable f)
92144 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
93−foldMapWith f g = foldr (f . g) nil
145+foldMapWith f g = foldr (f . g) K.nil
94146
95147-- | Like 'foldMapWith' but with the last two arguments reversed i.e. the
96148-- monadic streaming function is the last argument.
@@ -99,4 +151,4 @@ foldMapWith f g = foldr (f . g) nil
99151{-# INLINABLE forEachWith #-}
100152forEachWith :: (IsStream t, Foldable f)
101153 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
102−forEachWith f xs g = foldr (f . g) nil xs
154+forEachWith f xs g = foldr (f . g) K.nil xs
src/Streamly/Streams/Serial.hs+22−29
@@ -36,9 +36,9 @@ module Streamly.Streams.Serial
3636 , wSerially
3737 , interleaving -- deprecated
3838
39− -- * Running Streams
40− , runStreamT -- deprecated
41− , runInterleavedT -- deprecated
39+ -- * Transformation
40+ , map
41+ , mapM
4242 )
4343where
4444
@@ -51,11 +51,14 @@ import Control.Monad.Reader.Class (MonadReader(..))
5151import Control.Monad.State.Class (MonadState(..))
5252import Control.Monad.Trans.Class (MonadTrans(lift))
5353import Data.Semigroup (Semigroup(..))
54+import Prelude hiding (map, mapM)
5455
55−import Streamly.Streams.StreamK hiding (serial)
56+import Streamly.Streams.StreamK (IsStream(..), adapt, Stream(..))
5657import qualified Streamly.Streams.StreamK as K
58+import qualified Streamly.Streams.StreamD as D
5759
5860#include "Instances.hs"
61+#include "inline.h"
5962
6063------------------------------------------------------------------------------
6164-- SerialT
@@ -118,7 +121,7 @@ import qualified Streamly.Streams.StreamK as K
118121--
119122-- @since 0.2.0
120123newtype SerialT m a = SerialT {getSerialT :: Stream m a}
121− deriving (Semigroup, Monoid, Functor, MonadTrans)
124+ deriving (Semigroup, Monoid, MonadTrans)
122125
123126-- | A serial IO stream of elements of type @a@. See 'SerialT' documentation
124127-- for more details.
@@ -144,12 +147,12 @@ instance IsStream SerialT where
144147 {-# INLINE consM #-}
145148 {-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
146149 consM :: Monad m => m a -> SerialT m a -> SerialT m a
147− consM m r = fromStream $ consMSerial m (toStream r)
150+ consM m r = fromStream $ K.consMSerial m (toStream r)
148151
149152 {-# INLINE (|:) #-}
150153 {-# SPECIALIZE (|:) :: IO a -> SerialT IO a -> SerialT IO a #-}
151154 (|:) :: Monad m => m a -> SerialT m a -> SerialT m a
152− m |: r = fromStream $ consMSerial m (toStream r)
155+ m |: r = fromStream $ K.consMSerial m (toStream r)
153156
154157------------------------------------------------------------------------------
155158-- Semigroup
@@ -180,6 +183,14 @@ instance Monad m => Monad (SerialT m) where
180183-- Other instances
181184------------------------------------------------------------------------------
182185
186+{-# INLINE_EARLY mapM #-}
187+mapM :: (IsStream t, Monad m) => (a -> m b) -> t m a -> t m b
188+mapM f m = fromStream $ D.toStreamK $ D.mapM f $ D.fromStreamK (toStream m)
189+
190+{-# INLINE map #-}
191+map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
192+map f = mapM (return . f)
193+
183194MONAD_APPLICATIVE_INSTANCE(SerialT,)
184195MONAD_COMMON_INSTANCES(SerialT,)
185196
@@ -225,7 +236,7 @@ MONAD_COMMON_INSTANCES(SerialT,)
225236--
226237-- @since 0.2.0
227238newtype WSerialT m a = WSerialT {getWSerialT :: Stream m a}
228− deriving (Functor, MonadTrans)
239+ deriving (MonadTrans)
229240
230241-- | An interleaving serial IO stream of elements of type @a@. See 'WSerialT'
231242-- documentation for more details.
@@ -258,12 +269,12 @@ instance IsStream WSerialT where
258269 {-# INLINE consM #-}
259270 {-# SPECIALIZE consM :: IO a -> WSerialT IO a -> WSerialT IO a #-}
260271 consM :: Monad m => m a -> WSerialT m a -> WSerialT m a
261− consM m r = fromStream $ consMSerial m (toStream r)
272+ consM m r = fromStream $ K.consMSerial m (toStream r)
262273
263274 {-# INLINE (|:) #-}
264275 {-# SPECIALIZE (|:) :: IO a -> WSerialT IO a -> WSerialT IO a #-}
265276 (|:) :: Monad m => m a -> WSerialT m a -> WSerialT m a
266− m |: r = fromStream $ consMSerial m (toStream r)
277+ m |: r = fromStream $ K.consMSerial m (toStream r)
267278
268279------------------------------------------------------------------------------
269280-- Semigroup
@@ -303,7 +314,7 @@ infixr 5 <=>
303314------------------------------------------------------------------------------
304315
305316instance Monoid (WSerialT m a) where
306− mempty = nil
317+ mempty = K.nil
307318 mappend = (<>)
308319
309320------------------------------------------------------------------------------
@@ -324,21 +335,3 @@ instance Monad m => Monad (WSerialT m) where
324335
325336MONAD_APPLICATIVE_INSTANCE(WSerialT,)
326337MONAD_COMMON_INSTANCES(WSerialT,)
327−
328−-------------------------------------------------------------------------------
329−-- Running Streams
330−-------------------------------------------------------------------------------
331−
332−-- | Same as @runStream@.
333−--
334−-- @since 0.1.0
335−{-# DEPRECATED runStreamT "Please use runStream instead." #-}
336−runStreamT :: Monad m => SerialT m a -> m ()
337−runStreamT = runStream
338−
339−-- | Same as @runStream . wSerially@.
340−--
341−-- @since 0.1.0
342−{-# DEPRECATED runInterleavedT "Please use 'runStream . interleaving' instead." #-}
343−runInterleavedT :: Monad m => InterleavedT m a -> m ()
344−runInterleavedT = runStream
src/Streamly/Streams/StreamD.hs+87−11
@@ -34,24 +34,40 @@ module Streamly.Streams.StreamD
3434 Step (..)
3535 , Stream (..)
3636
37− -- * Elimination
38− , runStream
39− , uncons
40−
41− -- * Generation
37+ -- * Construction
4238 , nil
4339 , yield
4440 , yieldM
41+
42+ -- * Generation by Unfolding
4543 , unfoldr
4644 , unfoldrM
45+
46+ -- * Special Generation
4747 , repeat
4848 , enumFromStepN
4949 , fromList
5050 , fromListM
5151
52− -- * Transformation
53− , mapM
52+ -- * Deconstruction
53+ , uncons
54+
55+ -- * Elimination by Folding
56+ -- ** General Folds
57+ , foldr
58+ , foldrM
59+ , foldl'
60+ , foldlM'
61+
62+ -- ** Special Folds
63+ , runStream
5464 , mapM_
65+ , toList
66+ , last
67+
68+ -- * Mapping
69+ , map
70+ , mapM
5571
5672 -- * Conversion
5773 , toStreamK
@@ -59,9 +75,11 @@ module Streamly.Streams.StreamD
5975 )
6076where
6177
78+import GHC.Types ( SPEC(..) )
79+import Prelude hiding (map, mapM, mapM_, repeat, foldr, last)
80+
6281import Streamly.SVar (MonadAsync)
6382import qualified Streamly.Streams.StreamK as K
64−import Prelude hiding (mapM, mapM_, repeat)
6583
6684------------------------------------------------------------------------------
6785-- The direct style stream type
@@ -208,6 +226,14 @@ mapM f (Stream step state) = Stream step' state
208226 Yield x s -> f x >>= \a -> return $ Yield a s
209227 Stop -> return Stop
210228
229+{-# INLINE map #-}
230+map :: Monad m => (a -> b) -> Stream m a -> Stream m b
231+map f = mapM (return . f)
232+
233+instance Monad m => Functor (Stream m) where
234+ {-# INLINE fmap #-}
235+ fmap = map
236+
211237-------------------------------------------------------------------------------
212238-- Elimination
213239-------------------------------------------------------------------------------
@@ -225,15 +251,65 @@ uncons (Stream step state) = go state
225251-- | Run a streaming composition, discard the results.
226252{-# INLINE_LATE runStream #-}
227253runStream :: Monad m => Stream m a -> m ()
228−runStream (Stream step state) = go state
254+runStream (Stream step state) = go SPEC state
229255 where
230− go st = do
256+ go !_ st = do
231257 r <- step st
232258 case r of
233− Yield _ s -> go s
259+ Yield _ s -> go SPEC s
234260 Stop -> return ()
235261
236262-- | Execute a monadic action for each element of the 'Stream'
237263{-# INLINE_NORMAL mapM_ #-}
238264mapM_ :: Monad m => (a -> m b) -> Stream m a -> m ()
239265mapM_ m = runStream . mapM m
266+
267+{-# INLINE_NORMAL foldrM #-}
268+foldrM :: Monad m => (a -> b -> m b) -> b -> Stream m a -> m b
269+foldrM f z (Stream step state) = go SPEC state
270+ where
271+ go !_ st = do
272+ r <- step st
273+ case r of
274+ Yield x s -> go SPEC s >>= f x
275+ Stop -> return z
276+
277+{-# INLINE_NORMAL foldr #-}
278+foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
279+foldr f = foldrM (\a b -> return (f a b))
280+
281+{-# INLINE_NORMAL foldlM' #-}
282+foldlM' :: Monad m => (b -> a -> m b) -> b -> Stream m a -> m b
283+foldlM' fstep begin (Stream step state) = go SPEC begin state
284+ where
285+ go !_ acc st = acc `seq` do
286+ r <- step st
287+ case r of
288+ Yield x s -> do
289+ acc' <- fstep acc x
290+ go SPEC acc' s
291+ Stop -> return acc
292+
293+{-# INLINE foldl' #-}
294+foldl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> m b
295+foldl' fstep = foldlM' (\b a -> return (fstep b a))
296+
297+{-# INLINE toList #-}
298+toList :: Monad m => Stream m a -> m [a]
299+toList = foldr (:) []
300+
301+{-# INLINE_NORMAL last #-}
302+last :: Monad m => Stream m a -> m (Maybe a)
303+last (Stream step state) = go0 SPEC state
304+ where
305+ go0 !_ st = do
306+ r <- step st
307+ case r of
308+ Yield x s -> go1 SPEC x s
309+ Stop -> return Nothing
310+
311+ go1 !_ x st = do
312+ r <- step st
313+ case r of
314+ Yield y s -> go1 SPEC y s
315+ Stop -> return (Just x)
src/Streamly/Streams/StreamK.hs+127−9
@@ -1,3 +1,4 @@
1+{-# LANGUAGE BangPatterns #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE ConstraintKinds #-}
34{-# LANGUAGE FlexibleContexts #-}
@@ -34,10 +35,6 @@ module Streamly.Streams.StreamK
3435 -- * The stream type
3536 , Stream (..)
3637
37− -- * Elimination
38− , foldStream
39− , runStream
40−
4138 -- * Construction
4239 , mkStream
4340 , nil
@@ -57,6 +54,24 @@ module Streamly.Streams.StreamK
5754 , repeat
5855 , fromFoldable
5956
57+ -- * Elimination
58+ , foldStream
59+ , foldr
60+ , foldrM
61+ , foldx
62+ , foldl'
63+ , foldxM
64+ , foldlM'
65+
66+ , runStream
67+ , mapM_
68+ , toList
69+ , last
70+
71+ -- * Transformation
72+ , map
73+ , mapM
74+
6075 -- * Semigroup Style Composition
6176 , serial
6277
@@ -71,10 +86,12 @@ module Streamly.Streams.StreamK
7186 )
7287where
7388
89+import Control.Monad (void)
7490import Control.Monad.Reader.Class (MonadReader(..))
7591import Control.Monad.Trans.Class (MonadTrans(lift))
7692import Data.Semigroup (Semigroup(..))
77−import Prelude hiding (repeat)
93+import Prelude hiding (foldl, foldr, last, map, mapM, mapM_, repeat)
94+import qualified Prelude
7895
7996import Streamly.SVar
8097
@@ -328,6 +345,74 @@ foldStream svr blank single step m =
328345 let yieldk a x = step a (fromStream x)
329346 in (unStream (toStream m)) svr blank single yieldk
330347
348+-- | Lazy right associative fold.
349+foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
350+foldr step acc m = go (toStream m)
351+ where
352+ go m1 =
353+ let stop = return acc
354+ single a = return (step a acc)
355+ yieldk a r = go r >>= \b -> return (step a b)
356+ in (unStream m1) Nothing stop single yieldk
357+
358+-- | Lazy right fold with a monadic step function.
359+{-# INLINE foldrM #-}
360+foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
361+foldrM step acc m = go (toStream m)
362+ where
363+ go m1 =
364+ let stop = return acc
365+ single a = step a acc
366+ yieldk a r = go r >>= step a
367+ in (unStream m1) Nothing stop single yieldk
368+
369+-- | Strict left fold with an extraction function. Like the standard strict
370+-- left fold, but applies a user supplied extraction function (the third
371+-- argument) to the folded value at the end. This is designed to work with the
372+-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
373+{-# INLINE foldx #-}
374+foldx :: (IsStream t, Monad m)
375+ => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
376+foldx step begin done m = get $ go (toStream m) begin
377+ where
378+ {-# NOINLINE get #-}
379+ get m1 =
380+ let single = return . done
381+ in (unStream m1) Nothing undefined single undefined
382+
383+ -- Note, this can be implemented by making a recursive call to "go",
384+ -- however that is more expensive because of unnecessary recursion
385+ -- that cannot be tail call optimized. Unfolding recursion explicitly via
386+ -- continuations is much more efficient.
387+ go m1 !acc = Stream $ \_ _ sng yld ->
388+ let stop = sng acc
389+ single a = sng $ step acc a
390+ yieldk a r =
391+ let stream = go r (step acc a)
392+ in (unStream stream) Nothing undefined sng yld
393+ in (unStream m1) Nothing stop single yieldk
394+
395+-- | Strict left associative fold.
396+{-# INLINE foldl' #-}
397+foldl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> m b
398+foldl' step begin m = foldx step begin id m
399+
400+-- XXX replace the recursive "go" with explicit continuations.
401+-- | Like 'foldx', but with a monadic step function.
402+foldxM :: (IsStream t, Monad m)
403+ => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
404+foldxM step begin done m = go begin (toStream m)
405+ where
406+ go !acc m1 =
407+ let stop = acc >>= done
408+ single a = acc >>= \b -> step b a >>= done
409+ yieldk a r = acc >>= \b -> go (step b a) r
410+ in (unStream m1) Nothing stop single yieldk
411+
412+-- | Like 'foldl'' but with a monadic step function.
413+foldlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> m b
414+foldlM' step begin m = foldxM step (return begin) return m
415+
331416runStream :: (Monad m, IsStream t) => t m a -> m ()
332417runStream m = go (toStream m)
333418 where
@@ -337,6 +422,26 @@ runStream m = go (toStream m)
337422 yieldk _ r = go (toStream r)
338423 in (unStream m1) Nothing stop single yieldk
339424
425+-- | Apply a monadic action to each element of the stream and discard the
426+-- output of the action.
427+mapM_ :: (IsStream t, Monad m) => (a -> m b) -> t m a -> m ()
428+mapM_ f m = go (toStream m)
429+ where
430+ go m1 =
431+ let stop = return ()
432+ single a = void (f a)
433+ yieldk a r = f a >> go r
434+ in (unStream m1) Nothing stop single yieldk
435+
436+{-# INLINABLE toList #-}
437+toList :: (IsStream t, Monad m) => t m a -> m [a]
438+toList = foldr (:) []
439+
440+-- | Extract the last element of the stream, if any.
441+{-# INLINE last #-}
442+last :: (IsStream t, Monad m) => t m a -> m (Maybe a)
443+last = foldx (\_ y -> Just y) Nothing id
444+
340445-------------------------------------------------------------------------------
341446-- Generation
342447-------------------------------------------------------------------------------
@@ -409,11 +514,24 @@ instance Monoid (Stream m a) where
409514-- Functor
410515-------------------------------------------------------------------------------
411516
517+{-# INLINE map #-}
518+map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
519+map f m = fromStream $ Stream $ \_ stp sng yld ->
520+ let single = sng . f
521+ yieldk a r = yld (f a) (fmap f r)
522+ in unStream (toStream m) Nothing stp single yieldk
523+
412524instance Monad m => Functor (Stream m) where
413− fmap f m = Stream $ \_ stp sng yld ->
414− let single = sng . f
415− yieldk a r = yld (f a) (fmap f r)
416− in (unStream m) Nothing stp single yieldk
525+ fmap = map
526+
527+{-# INLINE mapM #-}
528+mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
529+mapM f m = go (toStream m)
530+ where
531+ go m1 = fromStream $ Stream $ \svr stp sng yld ->
532+ let single a = f a >>= sng
533+ yieldk a r = unStream (toStream (f a |: (go r))) svr stp sng yld
534+ in (unStream m1) Nothing stp single yieldk
417535
418536-------------------------------------------------------------------------------
419537-- Bind utility
src/Streamly/Streams/Zip.hs+23−30
@@ -30,23 +30,24 @@ module Streamly.Streams.Zip
3030 , ZipStream -- deprecated
3131 , zipSerially
3232 , zipping -- deprecated
33− , runZipStream -- deprecated
3433
3534 , ZipAsyncM
3635 , ZipAsync
3736 , zipAsyncly
3837 , zippingAsync -- deprecated
39− , runZipAsync -- deprecated
4038 )
4139where
4240
4341import Data.Semigroup (Semigroup(..))
44−import Prelude hiding (repeat, zipWith)
42+import Prelude hiding (map, repeat, zipWith)
4543
44+import Streamly.Streams.StreamK (IsStream(..), Stream(..))
4645import Streamly.Streams.Async (mkAsync)
47−import Streamly.Streams.StreamK
46+import Streamly.Streams.Serial (map)
4847import Streamly.SVar (MonadAsync)
4948
49+import qualified Streamly.Streams.StreamK as K
50+
5051#include "Instances.hs"
5152
5253------------------------------------------------------------------------------
@@ -62,7 +63,7 @@ zipWithS f m1 m2 = go m1 m2
6263 let single2 b = sng (f a b)
6364 yield2 b rb = yld (f a b) (go ra rb)
6465 in unStream my Nothing stp single2 yield2
65− let single1 a = merge a nil
66+ let single1 a = merge a K.nil
6667 yield1 a ra = merge a ra
6768 unStream mx Nothing stp single1 yield1
6869
@@ -85,7 +86,7 @@ zipWithM f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
8586 single2 b = runIt $ toStream (f a b)
8687 yield2 b rb = runIt $ toStream (f a b) <> go ra rb
8788 in unStream my Nothing stp single2 yield2
88− let single1 a = merge a nil
89+ let single1 a = merge a K.nil
8990 yield1 a ra = merge a ra
9091 unStream mx Nothing stp single1 yield1
9192
@@ -112,7 +113,7 @@ zipWithM f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
112113--
113114-- @since 0.2.0
114115newtype ZipSerialM m a = ZipSerialM {getZipSerialM :: Stream m a}
115− deriving (Functor, Semigroup, Monoid)
116+ deriving (Semigroup, Monoid)
116117
117118-- |
118119-- @since 0.1.0
@@ -128,7 +129,7 @@ type ZipSerial a = ZipSerialM IO a
128129--
129130-- @since 0.2.0
130131zipSerially :: IsStream t => ZipSerialM m a -> t m a
131−zipSerially = adapt
132+zipSerially = K.adapt
132133
133134-- | Same as 'zipSerially'.
134135--
@@ -144,15 +145,18 @@ instance IsStream ZipSerialM where
144145 {-# INLINE consM #-}
145146 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
146147 consM :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
147− consM m r = fromStream $ consMSerial m (toStream r)
148+ consM m r = fromStream $ K.consMSerial m (toStream r)
148149
149150 {-# INLINE (|:) #-}
150151 {-# SPECIALIZE (|:) :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
151152 (|:) :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
152− m |: r = fromStream $ consMSerial m (toStream r)
153+ m |: r = fromStream $ K.consMSerial m (toStream r)
154+
155+instance Monad m => Functor (ZipSerialM m) where
156+ fmap = map
153157
154158instance Monad m => Applicative (ZipSerialM m) where
155− pure = ZipSerialM . repeat
159+ pure = ZipSerialM . K.repeat
156160 m1 <*> m2 = fromStream $ zipWith id (toStream m1) (toStream m2)
157161
158162------------------------------------------------------------------------------
@@ -203,7 +207,7 @@ zipAsyncWithM f m1 m2 = fromStream $ Stream $ \_ stp sng yld -> do
203207--
204208-- @since 0.2.0
205209newtype ZipAsyncM m a = ZipAsyncM {getZipAsyncM :: Stream m a}
206− deriving (Functor, Semigroup, Monoid)
210+ deriving (Semigroup, Monoid)
207211
208212-- | An IO stream whose applicative instance zips streams wAsyncly.
209213--
@@ -214,7 +218,7 @@ type ZipAsync a = ZipAsyncM IO a
214218--
215219-- @since 0.2.0
216220zipAsyncly :: IsStream t => ZipAsyncM m a -> t m a
217−zipAsyncly = adapt
221+zipAsyncly = K.adapt
218222
219223-- | Same as 'zipAsyncly'.
220224--
@@ -229,27 +233,16 @@ instance IsStream ZipAsyncM where
229233 {-# INLINE consM #-}
230234 {-# SPECIALIZE consM :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
231235 consM :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
232− consM m r = fromStream $ consMSerial m (toStream r)
236+ consM m r = fromStream $ K.consMSerial m (toStream r)
233237
234238 {-# INLINE (|:) #-}
235239 {-# SPECIALIZE (|:) :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
236240 (|:) :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
237− m |: r = fromStream $ consMSerial m (toStream r)
241+ m |: r = fromStream $ K.consMSerial m (toStream r)
242+
243+instance Monad m => Functor (ZipAsyncM m) where
244+ fmap = map
238245
239246instance MonadAsync m => Applicative (ZipAsyncM m) where
240− pure = ZipAsyncM . repeat
247+ pure = ZipAsyncM . K.repeat
241248 m1 <*> m2 = zipAsyncWith id m1 m2
242−
243−-- | Same as @runStream . zipping@.
244−--
245−-- @since 0.1.0
246−{-# DEPRECATED runZipStream "Please use 'runStream . zipSerially instead." #-}
247−runZipStream :: Monad m => ZipSerialM m a -> m ()
248−runZipStream = runStream
249−
250−-- | Same as @runStream . zippingAsync@.
251−--
252−-- @since 0.1.0
253−{-# DEPRECATED runZipAsync "Please use 'runStream . zipAsyncly instead." #-}
254−runZipAsync :: Monad m => ZipAsyncM m a -> m ()
255−runZipAsync = runStream
streamly.cabal+1
@@ -160,6 +160,7 @@ library
160160 -Wnoncanonical-monadfail-instances
161161
162162 build-depends: base >= 4.8 && < 5
163+ , ghc-prim >= 0.2 && < 0.6
163164 , containers >= 0.5 && < 0.6
164165 , heaps >= 0.3 && < 0.4
165166