on master help sign in
specialize the typeclass instances to recover performance
commitede29df8d0c90b77f7209b8b60dee22052512912 authorHarendra Kumar <harendra.kumar@gmail.com> dateFri 28 Dec 2018, 12:25 (8 years ago) parentc042050
9 files changed+135−68
benchmark/Linear.hs+1 benchmark/LinearAsync.hs+25−13 benchmark/LinearOps.hs+16−2 src/Streamly/SVar.hs+1 src/Streamly/Streams/Ahead.hs+16−11 src/Streamly/Streams/Async.hs+42−22 src/Streamly/Streams/Parallel.hs+15−4 src/Streamly/Streams/Serial.hs+2−8 src/Streamly/Streams/StreamK/Type.hs+17−8
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+25−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,12 +87,15 @@ 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
benchmark/LinearOps.hs+16−2
@@ -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)
src/Streamly/SVar.hs+1
@@ -2016,6 +2016,7 @@ newSVarStats = do
20162016 , svarStopTime = stpTime
20172017 }
20182018
2019+-- XXX remove polymorphism in t, inline f
20192020getAheadSVar :: MonadAsync m
20202021 => State t m a
20212022 -> ( IORef ([t m a], Int)
src/Streamly/Streams/Ahead.hs+16−11
@@ -580,8 +580,9 @@ ahead m1 m2 = mkStream $ \st stp sng yld ->
580580-- | XXX we can implement it more efficienty by directly implementing instead
581581-- of combining streams using ahead.
582582{-# INLINE consMAhead #-}
583−consMAhead :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
584−consMAhead m r = K.yieldM m `ahead` 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)
585586
586587------------------------------------------------------------------------------
587588-- AheadT
@@ -649,21 +650,20 @@ aheadly = K.adapt
649650instance IsStream AheadT where
650651 toStream = getAheadT
651652 fromStream = AheadT
652−
653− {-# INLINE consM #-}
654− {-# SPECIALIZE consM :: IO a -> AheadT IO a -> AheadT IO a #-}
655653 consM = consMAhead
656−
657− {-# INLINE (|:) #-}
658− {-# SPECIALIZE (|:) :: IO a -> AheadT IO a -> AheadT IO a #-}
659− (|:) = consM
654+ (|:) = consMAhead
660655
661656------------------------------------------------------------------------------
662657-- Semigroup
663658------------------------------------------------------------------------------
664659
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+
665665instance MonadAsync m => Semigroup (AheadT m a) where
666− (<>) = ahead
666+ (<>) = mappendAhead
667667
668668------------------------------------------------------------------------------
669669-- Monoid
@@ -677,9 +677,14 @@ instance MonadAsync m => Monoid (AheadT m a) where
677677-- Monad
678678------------------------------------------------------------------------------
679679
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+
680685instance MonadAsync m => Monad (AheadT m) where
681686 return = pure
682− (>>=) = K.bindWith ahead
687+ (>>=) = bindAhead
683688
684689------------------------------------------------------------------------------
685690-- Other instances
src/Streamly/Streams/Async.hs+42−22
@@ -572,11 +572,16 @@ async = joinStreamVarAsync AsyncVar
572572(<|) :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
573573(<|) = async
574574
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+--
575579-- | XXX we can implement it more efficienty by directly implementing instead
576580-- of combining streams using async.
577581{-# INLINE consMAsync #-}
578−consMAsync :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
579−consMAsync m r = K.yieldM m `async` 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)
580585
581586------------------------------------------------------------------------------
582587-- AsyncT
@@ -649,21 +654,22 @@ asyncly = adapt
649654instance IsStream AsyncT where
650655 toStream = getAsyncT
651656 fromStream = AsyncT
652−
653− {-# INLINE consM #-}
654− {-# SPECIALIZE consM :: IO a -> AsyncT IO a -> AsyncT IO a #-}
655657 consM = consMAsync
656−
657− {-# INLINE (|:) #-}
658− {-# SPECIALIZE (|:) :: IO a -> AsyncT IO a -> AsyncT IO a #-}
659− (|:) = consM
658+ (|:) = consMAsync
660659
661660------------------------------------------------------------------------------
662661-- Semigroup
663662------------------------------------------------------------------------------
664663
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+
665671instance MonadAsync m => Semigroup (AsyncT m a) where
666− (<>) = async
672+ (<>) = mappendAsync
667673
668674------------------------------------------------------------------------------
669675-- Monoid
@@ -677,14 +683,21 @@ instance MonadAsync m => Monoid (AsyncT m a) where
677683-- Monad
678684------------------------------------------------------------------------------
679685
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+
680691instance MonadAsync m => Monad (AsyncT m) where
681692 return = pure
682− (>>=) = K.bindWith async
693+ (>>=) = bindAsync
683694
684695------------------------------------------------------------------------------
685696-- Other instances
686697------------------------------------------------------------------------------
687698
699+-- XXX SPECIALIZE the applicative as well?
700+
688701MONAD_APPLICATIVE_INSTANCE(AsyncT,MONADPARALLEL)
689702MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
690703
@@ -695,8 +708,9 @@ MONAD_COMMON_INSTANCES(AsyncT, MONADPARALLEL)
695708-- | XXX we can implement it more efficienty by directly implementing instead
696709-- of combining streams using wAsync.
697710{-# INLINE consMWAsync #-}
698−consMWAsync :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
699−consMWAsync m r = K.yieldM m `wAsync` r
711+{-# SPECIALIZE consMWAsync :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
712+consMWAsync :: MonadAsync m => m a -> WAsyncT m a -> WAsyncT m a
713+consMWAsync m r = fromStream $ K.yieldM m `wAsync` (toStream r)
700714
701715-- | Polymorphic version of the 'Semigroup' operation '<>' of 'WAsyncT'.
702716-- Merges two streams concurrently choosing elements from both fairly.
@@ -771,21 +785,20 @@ wAsyncly = adapt
771785instance IsStream WAsyncT where
772786 toStream = getWAsyncT
773787 fromStream = WAsyncT
774−
775− {-# INLINE consM #-}
776− {-# SPECIALIZE consM :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
777788 consM = consMWAsync
778−
779− {-# INLINE (|:) #-}
780− {-# SPECIALIZE (|:) :: IO a -> WAsyncT IO a -> WAsyncT IO a #-}
781− (|:) = consM
789+ (|:) = consMWAsync
782790
783791------------------------------------------------------------------------------
784792-- Semigroup
785793------------------------------------------------------------------------------
786794
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+
787800instance MonadAsync m => Semigroup (WAsyncT m a) where
788− (<>) = wAsync
801+ (<>) = mappendWAsync
789802
790803------------------------------------------------------------------------------
791804-- Monoid
@@ -799,9 +812,16 @@ instance MonadAsync m => Monoid (WAsyncT m a) where
799812-- Monad
800813------------------------------------------------------------------------------
801814
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+
802820instance MonadAsync m => Monad (WAsyncT m) where
803821 return = pure
804− (>>=) = K.bindWith wAsync
822+ (>>=) = bindWAsync
823+
824+-- XXX SPECIALIZE the applicative as well?
805825
806826------------------------------------------------------------------------------
807827-- Other instances
src/Streamly/Streams/Parallel.hs+15−4
@@ -108,8 +108,9 @@ joinStreamVarPar style m1 m2 = mkStream $ \st yld sng stp ->
108108-- | XXX we can implement it more efficienty by directly implementing instead
109109-- of combining streams using parallel.
110110{-# INLINE consMParallel #-}
111−consMParallel :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
112−consMParallel m r = K.yieldM m `parallel` 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)
113114
114115-- | Polymorphic version of the 'Semigroup' operation '<>' of 'ParallelT'
115116-- Merges two streams concurrently.
@@ -350,8 +351,13 @@ instance IsStream ParallelT where
350351-- Semigroup
351352------------------------------------------------------------------------------
352353
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+
353359instance MonadAsync m => Semigroup (ParallelT m a) where
354− (<>) = parallel
360+ (<>) = mappendParallel
355361
356362------------------------------------------------------------------------------
357363-- Monoid
@@ -365,9 +371,14 @@ instance MonadAsync m => Monoid (ParallelT m a) where
365371-- Monad
366372------------------------------------------------------------------------------
367373
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+
368379instance MonadAsync m => Monad (ParallelT m) where
369380 return = pure
370− (>>=) = K.bindWith parallel
381+ (>>=) = bindParallel
371382
372383------------------------------------------------------------------------------
373384-- Other instances
src/Streamly/Streams/Serial.hs+2−8
@@ -149,21 +149,15 @@ 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 #-}
152154consMSerial :: Monad m => m a -> SerialT m a -> SerialT m a
153155consMSerial m ms = fromStream $ K.consMStream m (toStream ms)
154156
155157instance IsStream SerialT where
156158 toStream = getSerialT
157159 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
162160 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
167161 (|:) = consMSerial
168162
169163------------------------------------------------------------------------------
src/Streamly/Streams/StreamK/Type.hs+17−8
@@ -184,7 +184,7 @@ adapt = fromStream . toStream
184184--
185185-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
186186-- continuation and a yield continuation.
187−{-# INLINABLE mkStream #-}
187+{-# INLINE mkStream #-}
188188mkStream:: IsStream t
189189 => (forall r. State Stream m a
190190 -> (a -> t m a -> m r)
@@ -280,7 +280,11 @@ foldStreamSVar sv st yld sng stp m =
280280-- Instances
281281-------------------------------------------------------------------------------
282282
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.
283286{-# INLINE consMStream #-}
287+{-# SPECIALIZE consMStream :: IO a -> Stream IO a -> Stream IO a #-}
284288consMStream :: (Monad m) => m a -> Stream m a -> Stream m a
285289consMStream m r = MkStream $ \_ yld _ _ -> m >>= \a -> yld a r
286290
@@ -336,6 +340,7 @@ instance Semigroup (Stream m a) where
336340-- @
337341--
338342-- @since 0.1.0
343+{-# INLINE nil #-}
339344nil :: IsStream t => t m a
340345nil = mkStream $ \_ _ _ stp -> stp
341346
@@ -347,14 +352,18 @@ instance Monoid (Stream m a) where
347352-- Functor
348353-------------------------------------------------------------------------------
349354
350−
351355{-# INLINE map #-}
352−map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
353−map f m = mkStream $ \st yld sng stp ->
354− let single = sng . f
355− yieldk a r = yld (f a) (map f r)
356− in foldStream (adaptState st) yieldk single stp m
357−
356+map :: IsStream t => (a -> b) -> t m a -> t m b
357+map f m = go m
358+ where
359+ go m1 =
360+ mkStream $ \st yld sng stp ->
361+ let single = sng . f
362+ yieldk a r = yld (f a) (go r)
363+ in foldStream (adaptState st) yieldk single stp m1
364+
365+-- in fact use the Stream type everywhere and only use polymorphism in the high
366+-- level modules/prelude.
358367instance Monad m => Functor (Stream m) where
359368 fmap = map
360369