on master help sign in
specialize the typeclass instances to recover performance
ede29dfHarendra Kumar
benchmark/Linear.hs+1
@@ -97,6 +97,7 @@ main =
97 -- These are essentially appends
97 -- These are essentially appends
98 , benchIOSrc serially "foldMapWith" Ops.sourceFoldMapWith
98 , benchIOSrc serially "foldMapWith" Ops.sourceFoldMapWith
99 , benchIOSrc serially "foldMapWithM" Ops.sourceFoldMapWithM
99 , benchIOSrc serially "foldMapWithM" Ops.sourceFoldMapWithM
100+ , benchIOSrc serially "foldMapM" Ops.sourceFoldMapM
100 ]
101 ]
101 , bgroup "elimination"
102 , bgroup "elimination"
102 [ benchIOSink "toNull" $ Ops.toNull serially
103 [ benchIOSink "toNull" $ Ops.toNull serially
benchmark/LinearAsync.hs+25−13
@@ -40,12 +40,15 @@ main :: IO ()
40main =
40main =
41 defaultMain
41 defaultMain
42 [ bgroup "asyncly"
42 [ bgroup "asyncly"
43− [ -- benchIO "unfoldr" $ Ops.toNull asyncly
43+ [ benchSrcIO asyncly "unfoldr" Ops.sourceUnfoldr
44− benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
44+ , benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
45− -- , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
45+ , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
46 , benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
46 , benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
47− -- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
47+ , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
48 , benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
48 , 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
49 , benchIO "mapM" $ Ops.mapM asyncly 1
52 , benchIO "mapM" $ Ops.mapM asyncly 1
50 , benchSrcIO asyncly "unfoldrM maxThreads 1"
53 , benchSrcIO asyncly "unfoldrM maxThreads 1"
51 (maxThreads 1 . Ops.sourceUnfoldrM)
54 (maxThreads 1 . Ops.sourceUnfoldrM)
@@ -53,23 +56,29 @@ main =
53 (maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
56 (maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
54 ]
57 ]
55 , bgroup "wAsyncly"
58 , bgroup "wAsyncly"
56− [ -- benchIO "unfoldr" $ Ops.toNull wAsyncly
59+ [ benchSrcIO wAsyncly "unfoldr" Ops.sourceUnfoldr
57− benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
60+ , benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
58− -- , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
61+ , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
59 , benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
62 , benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
60− -- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
63+ , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
61 , benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
64 , 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
62 , benchIO "mapM" $ Ops.mapM wAsyncly 1
68 , benchIO "mapM" $ Ops.mapM wAsyncly 1
63 ]
69 ]
64 -- unfoldr and fromFoldable are always serial and thereofore the same for
70 -- unfoldr and fromFoldable are always serial and thereofore the same for
65 -- all stream types.
71 -- all stream types.
66 , bgroup "aheadly"
72 , bgroup "aheadly"
67− [ -- benchIO "unfoldr" $ Ops.toNull aheadly
73+ [ benchSrcIO aheadly "unfoldr" Ops.sourceUnfoldr
68− benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
74+ , benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
69 , benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
75 , benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
70 -- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
76 -- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
71 , benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
77 , benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
78+ , benchSrcIO aheadly "foldMapM" Ops.sourceFoldMapM
79+ , benchIO "map" $ Ops.map' aheadly 1
80+ , benchIO "fmap" $ Ops.fmap' aheadly 1
72− , benchIO "mapM" $ Ops.mapM aheadly 1
81+ , benchIO "mapM" $ Ops.mapM aheadly 1
73 , benchSrcIO aheadly "unfoldrM maxThreads 1"
82 , benchSrcIO aheadly "unfoldrM maxThreads 1"
74 (maxThreads 1 . Ops.sourceUnfoldrM)
83 (maxThreads 1 . Ops.sourceUnfoldrM)
75 , benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
84 , benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
@@ -78,12 +87,15 @@ main =
78 ]
87 ]
79 -- XXX need to use smaller streams to finish in reasonable time
88 -- XXX need to use smaller streams to finish in reasonable time
80 , bgroup "parallely"
89 , bgroup "parallely"
81− [ --benchIO "unfoldr" $ Ops.toNull parallely
90+ [ benchSrcIO parallely "unfoldr" Ops.sourceUnfoldr
82− benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
91+ , benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
83 --, benchSrcIO parallely "fromFoldable" Ops.sourceFromFoldable
92 --, benchSrcIO parallely "fromFoldable" Ops.sourceFromFoldable
84 , benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
93 , benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
85 -- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
94 -- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
86 , benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
95 , 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
87 , benchIO "mapM" $ Ops.mapM parallely 1
99 , benchIO "mapM" $ Ops.mapM parallely 1
88 -- Zip has only one parallel flavor
100 -- Zip has only one parallel flavor
89 , benchIO "zip" Ops.zipAsync
101 , benchIO "zip" Ops.zipAsync
benchmark/LinearOps.hs+16−2
@@ -49,7 +49,7 @@ type Stream m a = S.SerialT m a
49
49
50{-# INLINE source #-}
50{-# INLINE source #-}
51source :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
51source :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
52−source n = S.serially $ sourceUnfoldrM n
52+source n = sourceUnfoldrM n
53
53
54{-# INLINE sourceIntFromTo #-}
54{-# INLINE sourceIntFromTo #-}
55sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> t m Int
55sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> t m Int
@@ -98,6 +98,11 @@ sourceFoldMapWithM :: (S.IsStream t, Monad m, S.Semigroup (t m Int))
98 => Int -> t m Int
98 => Int -> t m Int
99sourceFoldMapWithM n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
99sourceFoldMapWithM n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
100
100
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+
101{-# INLINE sourceUnfoldr #-}
106{-# INLINE sourceUnfoldr #-}
102sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> t m Int
107sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> t m Int
103sourceUnfoldr n = S.unfoldr step n
108sourceUnfoldr n = S.unfoldr step n
@@ -173,6 +178,8 @@ last, minimum, maximum, find, findIndex, elemIndex, foldl1', foldr1
173minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
178minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
174
179
175{-# INLINE foldl' #-}
180{-# INLINE foldl' #-}
181+{-# INLINE foldr #-}
182+{-# INLINE foldrM #-}
176{-# INLINE length #-}
183{-# INLINE length #-}
177{-# INLINE sum #-}
184{-# INLINE sum #-}
178{-# INLINE product #-}
185{-# INLINE product #-}
@@ -307,7 +314,12 @@ scan, scanl1', map, fmap, mapMaybe, filterEven, filterAllOut,
307mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
314mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
308
315
309{-# INLINE mapM #-}
316{-# INLINE mapM #-}
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+
310−mapM :: (S.IsStream t, S.MonadAsync m)
322+fmap' :: (S.IsStream t, S.MonadAsync m, P.Functor (t m))
311 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
323 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
312
324
313{-# INLINE sequence #-}
325{-# INLINE sequence #-}
@@ -317,7 +329,9 @@ sequence :: (S.IsStream t, S.MonadAsync m)
317scan n = composeN n $ S.scanl' (+) 0
329scan n = composeN n $ S.scanl' (+) 0
318scanl1' n = composeN n $ S.scanl1' (+)
330scanl1' n = composeN n $ S.scanl1' (+)
319fmap n = composeN n $ Prelude.fmap (+1)
331fmap n = composeN n $ Prelude.fmap (+1)
332+fmap' t n = composeN' n $ t . Prelude.fmap (+1)
320map n = composeN n $ S.map (+1)
333map n = composeN n $ S.map (+1)
334+map' t n = composeN' n $ t . S.map (+1)
321mapM t n = composeN' n $ t . S.mapM return
335mapM t n = composeN' n $ t . S.mapM return
322mapMaybe n = composeN n $ S.mapMaybe
336mapMaybe n = composeN n $ S.mapMaybe
323 (\x -> if Prelude.odd x then Nothing else Just x)
337 (\x -> if Prelude.odd x then Nothing else Just x)
src/Streamly/SVar.hs+1
@@ -2016,6 +2016,7 @@ newSVarStats = do
2016 , svarStopTime = stpTime
2016 , svarStopTime = stpTime
2017 }
2017 }
2018
2018
2019+-- XXX remove polymorphism in t, inline f
2019getAheadSVar :: MonadAsync m
2020getAheadSVar :: MonadAsync m
2020 => State t m a
2021 => State t m a
2021 -> ( IORef ([t m a], Int)
2022 -> ( IORef ([t m a], Int)
src/Streamly/Streams/Ahead.hs+16−11
@@ -580,8 +580,9 @@ ahead m1 m2 = mkStream $ \st stp sng yld ->
580-- | XXX we can implement it more efficienty by directly implementing instead
580-- | XXX we can implement it more efficienty by directly implementing instead
581-- of combining streams using ahead.
581-- of combining streams using ahead.
582{-# INLINE consMAhead #-}
582{-# INLINE consMAhead #-}
583+{-# SPECIALIZE consMAhead :: IO a -> AheadT IO a -> AheadT IO a #-}
583−consMAhead :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
584+consMAhead :: MonadAsync m => m a -> AheadT m a -> AheadT m a
584−consMAhead m r = K.yieldM m `ahead` r
585+consMAhead m r = fromStream $ K.yieldM m `ahead` (toStream r)
585
586
586------------------------------------------------------------------------------
587------------------------------------------------------------------------------
587-- AheadT
588-- AheadT
@@ -649,21 +650,20 @@ aheadly = K.adapt
649instance IsStream AheadT where
650instance IsStream AheadT where
650 toStream = getAheadT
651 toStream = getAheadT
651 fromStream = AheadT
652 fromStream = AheadT
652−
653− {-# INLINE consM #-}
654− {-# SPECIALIZE consM :: IO a -> AheadT IO a -> AheadT IO a #-}
655 consM = consMAhead
653 consM = consMAhead
656−
654+ (|:) = consMAhead
657− {-# INLINE (|:) #-}
658− {-# SPECIALIZE (|:) :: IO a -> AheadT IO a -> AheadT IO a #-}
659− (|:) = consM
660
655
661------------------------------------------------------------------------------
656------------------------------------------------------------------------------
662-- Semigroup
657-- Semigroup
663------------------------------------------------------------------------------
658------------------------------------------------------------------------------
664
659
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)
664+
665instance MonadAsync m => Semigroup (AheadT m a) where
665instance MonadAsync m => Semigroup (AheadT m a) where
666− (<>) = ahead
666+ (<>) = mappendAhead
667
667
668------------------------------------------------------------------------------
668------------------------------------------------------------------------------
669-- Monoid
669-- Monoid
@@ -677,9 +677,14 @@ instance MonadAsync m => Monoid (AheadT m a) where
677-- Monad
677-- Monad
678------------------------------------------------------------------------------
678------------------------------------------------------------------------------
679
679
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)
684+
680instance MonadAsync m => Monad (AheadT m) where
685instance MonadAsync m => Monad (AheadT m) where
681 return = pure
686 return = pure
682− (>>=) = K.bindWith ahead
687+ (>>=) = bindAhead
683
688
684------------------------------------------------------------------------------
689------------------------------------------------------------------------------
685-- Other instances
690-- Other instances
src/Streamly/Streams/Async.hs+42−22
@@ -572,11 +572,16 @@ async = joinStreamVarAsync AsyncVar
572(<|) :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
572(<|) :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
573(<|) = async
573(<|) = async
574
574
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+--
575-- | XXX we can implement it more efficienty by directly implementing instead
579-- | XXX we can implement it more efficienty by directly implementing instead
576-- of combining streams using async.
580-- of combining streams using async.
577{-# INLINE consMAsync #-}
581{-# INLINE consMAsync #-}
582+{-# SPECIALIZE consMAsync :: IO a -> AsyncT IO a -> AsyncT IO a #-}
578−consMAsync :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
583+consMAsync :: MonadAsync m => m a -> AsyncT m a -> AsyncT m a
579−consMAsync m r = K.yieldM m `async` r
584+consMAsync m r = fromStream $ K.yieldM m `async` (toStream r)
580
585
581------------------------------------------------------------------------------
586------------------------------------------------------------------------------
582-- AsyncT
587-- AsyncT
@@ -649,21 +654,22 @@ asyncly = adapt
649instance IsStream AsyncT where
654instance IsStream AsyncT where
650 toStream = getAsyncT
655 toStream = getAsyncT
651 fromStream = AsyncT
656 fromStream = AsyncT
652−
653− {-# INLINE consM #-}
654− {-# SPECIALIZE consM :: IO a -> AsyncT IO a -> AsyncT IO a #-}
655 consM = consMAsync
657 consM = consMAsync
656−
658+ (|:) = consMAsync
657− {-# INLINE (|:) #-}
658− {-# SPECIALIZE (|:) :: IO a -> AsyncT IO a -> AsyncT IO a #-}
659− (|:) = consM
660
659
661------------------------------------------------------------------------------
660------------------------------------------------------------------------------
662-- Semigroup
661-- Semigroup
663------------------------------------------------------------------------------
662------------------------------------------------------------------------------
664
663
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+
665instance MonadAsync m => Semigroup (AsyncT m a) where
671instance MonadAsync m => Semigroup (AsyncT m a) where
666− (<>) = async
672+ (<>) = mappendAsync
667
673
668------------------------------------------------------------------------------
674------------------------------------------------------------------------------
669-- Monoid
675-- Monoid
@@ -677,14 +683,21 @@ instance MonadAsync m => Monoid (AsyncT m a) where
677-- Monad
683-- Monad
678------------------------------------------------------------------------------
684------------------------------------------------------------------------------
679
685
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+
680instance MonadAsync m => Monad (AsyncT m) where
691instance MonadAsync m => Monad (AsyncT m) where
681 return = pure
692 return = pure
682− (>>=) = K.bindWith async
693+ (>>=) = bindAsync
683
694
684------------------------------------------------------------------------------
695------------------------------------------------------------------------------
685-- Other instances
696-- Other instances
686------------------------------------------------------------------------------
697------------------------------------------------------------------------------
687
698
699+-- XXX SPECIALIZE the applicative as well?
700+
688MONAD_APPLICATIVE_INSTANCE(AsyncT,MONADPARALLEL)
701MONAD_APPLICATIVE_INSTANCE(AsyncT,MONADPARALLEL)
689MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
702MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
690
703
@@ -695,8 +708,9 @@ MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
695-- | XXX we can implement it more efficienty by directly implementing instead
708-- | XXX we can implement it more efficienty by directly implementing instead
696-- of combining streams using wAsync.
709-- of combining streams using wAsync.
697{-# INLINE consMWAsync #-}
710{-# INLINE consMWAsync #-}
711+{-# SPECIALIZE consMWAsync :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
698−consMWAsync :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
712+consMWAsync :: MonadAsync m => m a -> WAsyncT m a -> WAsyncT m a
699−consMWAsync m r = K.yieldM m `wAsync` r
713+consMWAsync m r = fromStream $ K.yieldM m `wAsync` (toStream r)
700
714
701-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WAsyncT'.
715-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WAsyncT'.
702-- Merges two streams concurrently choosing elements from both fairly.
716-- Merges two streams concurrently choosing elements from both fairly.
@@ -771,21 +785,20 @@ wAsyncly = adapt
771instance IsStream WAsyncT where
785instance IsStream WAsyncT where
772 toStream = getWAsyncT
786 toStream = getWAsyncT
773 fromStream = WAsyncT
787 fromStream = WAsyncT
774−
775− {-# INLINE consM #-}
776− {-# SPECIALIZE consM :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
777 consM = consMWAsync
788 consM = consMWAsync
778−
789+ (|:) = consMWAsync
779− {-# INLINE (|:) #-}
780− {-# SPECIALIZE (|:) :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
781− (|:) = consM
782
790
783------------------------------------------------------------------------------
791------------------------------------------------------------------------------
784-- Semigroup
792-- Semigroup
785------------------------------------------------------------------------------
793------------------------------------------------------------------------------
786
794
795+{-# INLINE mappendWAsync #-}
796+{-# SPECIALIZE mappendWAsync :: WAsyncT IO a -> WAsyncT IO a -> WAsyncT IO a #-}
797+mappendWAsync :: MonadAsync m => WAsyncT m a -> WAsyncT m a -> WAsyncT m a
798+mappendWAsync m1 m2 = fromStream $ wAsync (toStream m1) (toStream m2)
799+
787instance MonadAsync m => Semigroup (WAsyncT m a) where
800instance MonadAsync m => Semigroup (WAsyncT m a) where
788− (<>) = wAsync
801+ (<>) = mappendWAsync
789
802
790------------------------------------------------------------------------------
803------------------------------------------------------------------------------
791-- Monoid
804-- Monoid
@@ -799,9 +812,16 @@ instance MonadAsync m => Monoid (WAsyncT m a) where
799-- Monad
812-- Monad
800------------------------------------------------------------------------------
813------------------------------------------------------------------------------
801
814
815+{-# INLINE bindWAsync #-}
816+{-# SPECIALIZE bindWAsync :: WAsyncT IO a -> (a -> WAsyncT IO b) -> WAsyncT IO b #-}
817+bindWAsync :: MonadAsync m => WAsyncT m a -> (a -> WAsyncT m b) -> WAsyncT m b
818+bindWAsync m f = fromStream $ K.bindWith wAsync (adapt m) (\a -> adapt $ f a)
819+
802instance MonadAsync m => Monad (WAsyncT m) where
820instance MonadAsync m => Monad (WAsyncT m) where
803 return = pure
821 return = pure
804− (>>=) = K.bindWith wAsync
822+ (>>=) = bindWAsync
823+
824+-- XXX SPECIALIZE the applicative as well?
805
825
806------------------------------------------------------------------------------
826------------------------------------------------------------------------------
807-- Other instances
827-- Other instances
src/Streamly/Streams/Parallel.hs+15−4
@@ -108,8 +108,9 @@ joinStreamVarPar style m1 m2 = mkStream $ \st yld sng stp ->
108-- | XXX we can implement it more efficienty by directly implementing instead
108-- | XXX we can implement it more efficienty by directly implementing instead
109-- of combining streams using parallel.
109-- of combining streams using parallel.
110{-# INLINE consMParallel #-}
110{-# INLINE consMParallel #-}
111−consMParallel :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
111+{-# SPECIALIZE consMParallel :: IO a -> ParallelT IO a -> ParallelT IO a #-}
112+consMParallel :: MonadAsync m => m a -> ParallelT m a -> ParallelT m a
112−consMParallel m r = K.yieldM m `parallel` r
113+consMParallel m r = fromStream $ K.yieldM m `parallel` (toStream r)
113
114
114-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'
115-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'
115-- Merges two streams concurrently.
116-- Merges two streams concurrently.
@@ -350,8 +351,13 @@ instance IsStream ParallelT where
350-- Semigroup
351-- Semigroup
351------------------------------------------------------------------------------
352------------------------------------------------------------------------------
352
353
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+
353instance MonadAsync m => Semigroup (ParallelT m a) where
359instance MonadAsync m => Semigroup (ParallelT m a) where
354− (<>) = parallel
360+ (<>) = mappendParallel
355
361
356------------------------------------------------------------------------------
362------------------------------------------------------------------------------
357-- Monoid
363-- Monoid
@@ -365,9 +371,14 @@ instance MonadAsync m => Monoid (ParallelT m a) where
365-- Monad
371-- Monad
366------------------------------------------------------------------------------
372------------------------------------------------------------------------------
367
373
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+
368instance MonadAsync m => Monad (ParallelT m) where
379instance MonadAsync m => Monad (ParallelT m) where
369 return = pure
380 return = pure
370− (>>=) = K.bindWith parallel
381+ (>>=) = bindParallel
371
382
372------------------------------------------------------------------------------
383------------------------------------------------------------------------------
373-- Other instances
384-- Other instances
src/Streamly/Streams/Serial.hs+2−8
@@ -149,21 +149,15 @@ type StreamT = SerialT
149serially :: IsStream t => SerialT m a -> t m a
149serially :: IsStream t => SerialT m a -> t m a
150serially = adapt
150serially = adapt
151
151
152+{-# INLINE consMSerial #-}
153+{-# SPECIALIZE consMSerial :: IO a -> SerialT IO a -> SerialT IO a #-}
152consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
154consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
153consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
155consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
154
156
155instance IsStream SerialT where
157instance IsStream SerialT where
156 toStream = getSerialT
158 toStream = getSerialT
157 fromStream = SerialT
159 fromStream = SerialT
158−
159− {-# INLINE consM #-}
160− {-# SPECIALIZE consM :: IO a -> SerialT IO a -> SerialT IO a #-}
161− consM :: Monad m => m a -> SerialT m a -> SerialT m a
162 consM = consMSerial
160 consM = consMSerial
163−
164− {-# INLINE (|:) #-}
165− {-# SPECIALIZE (|:) :: IO a -> SerialT IO a -> SerialT IO a #-}
166− (|:) :: Monad m => m a -> SerialT m a -> SerialT m a
167 (|:) = consMSerial
161 (|:) = consMSerial
168
162
169------------------------------------------------------------------------------
163------------------------------------------------------------------------------
src/Streamly/Streams/StreamK/Type.hs+17−8
@@ -184,7 +184,7 @@ adapt = fromStream . toStream
184--
184--
185-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
185-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
186-- continuation and a yield continuation.
186-- continuation and a yield continuation.
187−{-# INLINABLE mkStream #-}
187+{-# INLINE mkStream #-}
188mkStream:: IsStream t
188mkStream:: IsStream t
189 => (forall r. State Stream m a
189 => (forall r. State Stream m a
190 -> (a -> t m a -> m r)
190 -> (a -> t m a -> m r)
@@ -280,7 +280,11 @@ foldStreamSVar sv st yld sng stp m =
280-- Instances
280-- Instances
281-------------------------------------------------------------------------------
281-------------------------------------------------------------------------------
282
282
283+-- NOTE: specializing the function outside the instance definition seems to
284+-- improve performance quite a bit at times, even if we have the same
285+-- SPECIALIZE in the instance definition.
283{-# INLINE consMStream #-}
286{-# INLINE consMStream #-}
287+{-# SPECIALIZE consMStream :: IO a -> Stream IO a -> Stream IO a #-}
284consMStream :: (Monad m) => m a -> Stream m a -> Stream m a
288consMStream :: (Monad m) => m a -> Stream m a -> Stream m a
285consMStream m r = MkStream $ \_ yld _ _ -> m >>= \a -> yld a r
289consMStream m r = MkStream $ \_ yld _ _ -> m >>= \a -> yld a r
286
290
@@ -336,6 +340,7 @@ instance Semigroup (Stream m a) where
336-- @
340-- @
337--
341--
338-- @since 0.1.0
342-- @since 0.1.0
343+{-# INLINE nil #-}
339nil :: IsStream t => t m a
344nil :: IsStream t => t m a
340nil = mkStream $ \_ _ _ stp -> stp
345nil = mkStream $ \_ _ _ stp -> stp
341
346
@@ -347,14 +352,18 @@ instance Monoid (Stream m a) where
347-- Functor
352-- Functor
348-------------------------------------------------------------------------------
353-------------------------------------------------------------------------------
349
354
350−
351{-# INLINE map #-}
355{-# INLINE map #-}
352−map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
356+map :: IsStream t => (a -> b) -> t m a -> t m b
357+map f m = go m
358+ where
359+ go m1 =
353−map f m = mkStream $ \st yld sng stp ->
360+ mkStream $ \st yld sng stp ->
354− let single = sng . f
361+ let single = sng . f
355− yieldk a r = yld (f a) (map f r)
362+ yieldk a r = yld (f a) (go r)
356− in foldStream (adaptState st) yieldk single stp m
363+ in foldStream (adaptState st) yieldk single stp m1
357−
364+
365+-- in fact use the Stream type everywhere and only use polymorphism in the high
366+-- level modules/prelude.
358instance Monad m => Functor (Stream m) where
367instance Monad m => Functor (Stream m) where
359 fmap = map
368 fmap = map
360
369