@@ -1680,6 +1680,7 @@ fromStreamD = K.fromStream . toStreamK
16801680------------------------------------------------------------------------------
16811681
16821682-- | Run a side effect before the stream yields its first element.
1683+{-# INLINE_NORMAL before #-}
16831684before :: Monad m => m b -> Stream m a -> Stream m a
16841685before action (Stream step state) = Stream step' Nothing
16851686
@@ -1696,6 +1697,7 @@ before action (Stream step state) = Stream step' Nothing
16961697 Stop -> return Stop
16971698
16981699-- | Run a side effect whenever the stream stops normally.
1700+{-# INLINE_NORMAL after #-}
16991701after :: Monad m => m b -> Stream m a -> Stream m a
17001702after action (Stream step state) = Stream step' state
17011703
@@ -1709,8 +1711,18 @@ after action (Stream step state) = Stream step' state
17091711 Skip s -> return $ Skip s
17101712 Stop -> action >> return Stop
17111713
1714+-- XXX These combinators are expensive due to the call to
1715+-- onException/handle/try on each step. Therefore, they should called in an
1716+-- outer loop where we perform less iterations. For example, we cannot call
1717+-- them on each iteration in a char stream, instead we can call them when doing
1718+-- an IO on an array.
1719+--
1720+-- XXX For high performance error checks in busy streams we may need another
1721+-- Error constructor in step.
1722+--
17121723-- | Run a side effect whenever the stream aborts due to an exception. The
17131724-- exception is not caught simply rethrown.
1725+{-# INLINE_NORMAL onException #-}
17141726onException :: MonadCatch m => m b -> Stream m a -> Stream m a
17151727onException action (Stream step state) = Stream step' state
17161728
@@ -1728,13 +1740,19 @@ onException action (Stream step state) = Stream step' state
17281740--
17291741-- | Run a side effect whenever the stream stops normally or aborts due to an
17301742-- exception.
1743+{-# INLINE finally #-}
17311744finally :: MonadCatch m => m b -> Stream m a -> Stream m a
17321745finally action xs = after action $ onException action xs
17331746
1747+-- XXX bracket is like concatMap, it generates a stream and then flattens it.
1748+-- Like concatMap it has 10x worse performance compared to linear fused
1749+-- compositions.
1750+--
17341751-- | Run the first action before the stream starts and remember its output,
17351752-- generate a stream using the output, run the second action using the
17361753-- remembered value as an argument whenever the stream ends normally or due to
17371754-- an exception.
1755+{-# INLINE_NORMAL bracket #-}
17381756bracket :: MonadCatch m => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
17391757bracket bef aft bet = Stream step' Nothing
17401758
@@ -1743,7 +1761,9 @@ bracket bef aft bet = Stream step' Nothing
17431761 {-# INLINE_LATE step' #-}
17441762 step' _ Nothing = bef >>= \x -> return (Skip (Just (bet x, x)))
17451763
1746− step' gst (Just (Stream step state, v)) = do
1764+ -- NOTE: It is important to use UnStream instead of the Stream pattern
1765+ -- here, otherwise we get huge perf degradation, see note in concatMap.
1766+ step' gst (Just (UnStream step state, v)) = do
17471767 res <- step gst state `MC.onException` aft v
17481768 case res of
17491769 Yield x s -> return $ Yield x (Just (Stream step s, v))
@@ -1752,6 +1772,7 @@ bracket bef aft bet = Stream step' Nothing
17521772
17531773-- | When evaluating a stream if an exception occurs, stream evaluation aborts
17541774-- and the specified exception handler is run with the exception as argument.
1775+{-# INLINE_NORMAL handle #-}
17551776handle :: (MonadCatch m, Exception e) => (e -> m a) -> Stream m a -> Stream m a
17561777handle f (Stream step state) = Stream step' (Just state)
17571778