@@ -1680,6 +1680,7 @@ fromStreamD = K.fromStream . toStreamK
1680------------------------------------------------------------------------------
1680------------------------------------------------------------------------------
1682-- | Run a side effect before the stream yields its first element.
1682-- | Run a side effect before the stream yields its first element.
1683+{-# INLINE_NORMAL before #-}
1683before :: Monad m => m b -> Stream m a -> Stream m a
1684before :: Monad m => m b -> Stream m a -> Stream m a
1684before action (Stream step state) = Stream step' Nothing
1685before action (Stream step state) = Stream step' Nothing
@@ -1696,6 +1697,7 @@ before action (Stream step state) = Stream step' Nothing
1696 Stop -> return Stop
1697 Stop -> return Stop
1698-- | Run a side effect whenever the stream stops normally.
1699-- | Run a side effect whenever the stream stops normally.
1700+{-# INLINE_NORMAL after #-}
1699after :: Monad m => m b -> Stream m a -> Stream m a
1701after :: Monad m => m b -> Stream m a -> Stream m a
1700after action (Stream step state) = Stream step' state
1702after action (Stream step state) = Stream step' state
@@ -1709,8 +1711,18 @@ after action (Stream step state) = Stream step' state
1709 Skip s -> return $ Skip s
1711 Skip s -> return $ Skip s
1710 Stop -> action >> return Stop
1712 Stop -> action >> return Stop
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.
1720+-- XXX For high performance error checks in busy streams we may need another
1721+-- Error constructor in step.
1712-- | Run a side effect whenever the stream aborts due to an exception. The
1723-- | Run a side effect whenever the stream aborts due to an exception. The
1713-- exception is not caught simply rethrown.
1724-- exception is not caught simply rethrown.
1725+{-# INLINE_NORMAL onException #-}
1714onException :: MonadCatch m => m b -> Stream m a -> Stream m a
1726onException :: MonadCatch m => m b -> Stream m a -> Stream m a
1715onException action (Stream step state) = Stream step' state
1727onException action (Stream step state) = Stream step' state
@@ -1728,13 +1740,19 @@ onException action (Stream step state) = Stream step' state
1729-- | Run a side effect whenever the stream stops normally or aborts due to an
1741-- | Run a side effect whenever the stream stops normally or aborts due to an
1730-- exception.
1742-- exception.
1743+{-# INLINE finally #-}
1731finally :: MonadCatch m => m b -> Stream m a -> Stream m a
1744finally :: MonadCatch m => m b -> Stream m a -> Stream m a
1732finally action xs = after action $ onException action xs
1745finally action xs = after action $ onException action xs
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
1734-- | Run the first action before the stream starts and remember its output,
1751-- | Run the first action before the stream starts and remember its output,
1735-- generate a stream using the output, run the second action using the
1752-- generate a stream using the output, run the second action using the
1736-- remembered value as an argument whenever the stream ends normally or due to
1753-- remembered value as an argument whenever the stream ends normally or due to
1737-- an exception.
1754-- an exception.
1755+{-# INLINE_NORMAL bracket #-}
1738bracket :: MonadCatch m => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
1756bracket :: MonadCatch m => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
1739bracket bef aft bet = Stream step' Nothing
1757bracket bef aft bet = Stream step' Nothing
@@ -1743,7 +1761,9 @@ bracket bef aft bet = Stream step' Nothing
1743 {-# INLINE_LATE step' #-}
1761 {-# INLINE_LATE step' #-}
1744 step' _ Nothing = bef >>= \x -> return (Skip (Just (bet x, x)))
1762 step' _ Nothing = bef >>= \x -> return (Skip (Just (bet x, x)))
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.
1746− step' gst (Just (Stream step state, v)) = do
1766+ step' gst (Just (UnStream step state, v)) = do
1747 res <- step gst state `MC.onException` aft v
1767 res <- step gst state `MC.onException` aft v
1748 case res of
1768 case res of
1749 Yield x s -> return $ Yield x (Just (Stream step s, v))
1769 Yield x s -> return $ Yield x (Just (Stream step s, v))
@@ -1752,6 +1772,7 @@ bracket bef aft bet = Stream step' Nothing
1753-- | When evaluating a stream if an exception occurs, stream evaluation aborts
1773-- | When evaluating a stream if an exception occurs, stream evaluation aborts
1754-- and the specified exception handler is run with the exception as argument.
1774-- and the specified exception handler is run with the exception as argument.
1775+{-# INLINE_NORMAL handle #-}
1755handle :: (MonadCatch m, Exception e) => (e -> m a) -> Stream m a -> Stream m a
1776handle :: (MonadCatch m, Exception e) => (e -> m a) -> Stream m a -> Stream m a
1756handle f (Stream step state) = Stream step' (Just state)
1777handle f (Stream step state) = Stream step' (Just state)