1{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE ExistentialQuantification #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE PatternSynonyms #-}
6{-# LANGUAGE RankNTypes #-}
7{-# LANGUAGE RecordWildCards #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TupleSections #-}
14-- Module : Streamly.Internal.Data.Unfold
15-- Copyright : (c) 2019 Composewell Technologies
17-- Maintainer : streamly@composewell.com
18-- Stability : experimental
21-- Streams forcing a closed control flow loop can be categorized under
22-- two types, unfolds and folds, both of these are duals of each other.
24-- Unfold streams are really generators of a sequence of elements, we can also
25-- call them pull style streams. These are lazy producers of streams. On each
26-- evaluation the producer generates the next element. A consumer can
27-- therefore pull elements from the stream whenever it wants to. A stream
28-- consumer can multiplex pull streams by pulling elements from the chosen
29-- streams, therefore, pull streams allow merging or multiplexing. On the
30-- other hand, with this representation we cannot split or demultiplex a
31-- stream. So really these are stream sources that can be generated from a
32-- seed and can be merged or zipped into a single stream.
34-- The dual of Unfolds are Folds. Folds can also be called as push style
35-- streams or reducers. These are strict consumers of streams. We keep pushing
36-- elements to a fold and we can extract the result at any point. A driver can
37-- choose which fold to push to and can also push the same element to multiple
38-- folds. Therefore, folds allow splitting or demultiplexing a stream. On the
39-- other hand, we cannot merge streams using this representation. So really
40-- these are stream consumers that reduce the stream to a single value, these
41-- consumers can be composed such that a stream can be split over multiple
46-- Composing a tree or graph of computations with unfolds can be much more
47-- efficient compared to composing with the Monad instance. The reason is that
48-- unfolds allow the compiler to statically know the state and optimize it
49-- using stream fusion whereas it is not possible with the monad bind because
50-- the state is determined dynamically.
52-- Open control flow style streams can also have two representations. StreamK
53-- is a producer style representation. We can also have a consumer style
54-- representation. We can use that for composable folds in StreamK
57module Streamly.Internal.Data.Unfold
62 -- * Operations on Input
74 -- * Operations on Output
92 , enumerateFromStepIntegral
93 , enumerateFromToIntegral
94 , enumerateFromIntegral
128import Control.Exception (Exception)
129import Control.Monad.IO.Class (MonadIO(..))
130import Control.Monad.Trans.Control (MonadBaseControl)
131import Data.IORef (readIORef, writeIORef)
132import Data.Void (Void)
133import GHC.Types (SPEC(..))
134import Prelude hiding (concat, map, mapM, takeWhile, take, filter, const)
136import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
137#if __GLASGOW_HASKELL__ < 800
138import Streamly.Internal.Data.Stream.StreamD.Type (pattern Stream)
140import Streamly.Internal.Data.Unfold.Types (Unfold(..))
141import Streamly.Internal.Data.Fold.Types (Fold(..))
142import Streamly.Internal.Data.SVar (defState, MonadAsync)
143import Control.Monad.Catch (MonadCatch)
145import qualified Prelude
146import qualified Control.Monad.Catch as MC
147import qualified Data.Tuple as Tuple
148import qualified Streamly.Internal.Data.Stream.StreamK as K
149import qualified Streamly.Internal.Data.Stream.StreamD as D
151-------------------------------------------------------------------------------
153-------------------------------------------------------------------------------
155-- | Map a function on the input argument of the 'Unfold'.
158{-# INLINE_NORMAL lmap #-}
159lmap :: (a -> c) -> Unfold m c b -> Unfold m a b
160lmap f (Unfold ustep uinject) = Unfold ustep (uinject . f)
162-- | Map an action on the input argument of the 'Unfold'.
165{-# INLINE_NORMAL lmapM #-}
166lmapM :: Monad m => (a -> m c) -> Unfold m c b -> Unfold m a b
167lmapM f (Unfold ustep uinject) = Unfold ustep (\x -> f x >>= uinject)
169-- | Supply the seed to an unfold closing the input end of the unfold.
173{-# INLINE_NORMAL supply #-}
174supply :: Unfold m a b -> a -> Unfold m Void b
175supply unf a = lmap (Prelude.const a) unf
177-- | Supply the first component of the tuple to an unfold that accepts a tuple
178-- as a seed resulting in a fold that accepts the second component of the tuple
183{-# INLINE_NORMAL supplyFirst #-}
184supplyFirst :: Unfold m (a, b) c -> a -> Unfold m b c
185supplyFirst unf a = lmap (a, ) unf
187-- | Supply the second component of the tuple to an unfold that accepts a tuple
188-- as a seed resulting in a fold that accepts the first component of the tuple
193{-# INLINE_NORMAL supplySecond #-}
194supplySecond :: Unfold m (a, b) c -> b -> Unfold m a c
195supplySecond unf b = lmap (, b) unf
197-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
198-- using the argument of the original fold as the second element of tuple and
199-- discarding the first element of the tuple.
203{-# INLINE_NORMAL discardFirst #-}
204discardFirst :: Unfold m a b -> Unfold m (c, a) b
205discardFirst = lmap snd
207-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
208-- using the argument of the original fold as the first element of tuple and
209-- discarding the second element of the tuple.
213{-# INLINE_NORMAL discardSecond #-}
214discardSecond :: Unfold m a b -> Unfold m (a, c) b
215discardSecond = lmap fst
217-- | Convert an 'Unfold' that accepts a tuple as an argument into an unfold
218-- that accepts a tuple with elements swapped.
222{-# INLINE_NORMAL swap #-}
223swap :: Unfold m (a, c) b -> Unfold m (c, a) b
224swap = lmap Tuple.swap
226-------------------------------------------------------------------------------
228-------------------------------------------------------------------------------
230-- | Compose an 'Unfold' and a 'Fold'. Given an @Unfold m a b@ and a
231-- @Fold m b c@, returns a monadic action @a -> m c@ representing the
232-- application of the fold on the unfolded stream.
236{-# INLINE_NORMAL fold #-}
237fold :: Monad m => Unfold m a b -> Fold m b c -> a -> m c
238fold (Unfold ustep inject) (Fold fstep initial extract) a =
239 initial >>= \x -> inject a >>= go SPEC x
242 {-# INLINE_LATE go #-}
243 go !_ acc st = acc `seq` do
249 Skip s -> go SPEC acc s
252{-# INLINE_NORMAL map #-}
253map :: Monad m => (b -> c) -> Unfold m a b -> Unfold m a c
254map f (Unfold ustep uinject) = Unfold step uinject
256 {-# INLINE_LATE step #-}
260 Yield x s -> Yield (f x) s
264{-# INLINE_NORMAL mapM #-}
265mapM :: Monad m => (b -> m c) -> Unfold m a b -> Unfold m a c
266mapM f (Unfold ustep uinject) = Unfold step uinject
268 {-# INLINE_LATE step #-}
272 Yield x s -> f x >>= \a -> return $ Yield a s
273 Skip s -> return $ Skip s
274 Stop -> return $ Stop
276{-# INLINE_NORMAL mapMWithInput #-}
277mapMWithInput :: Monad m => (a -> b -> m c) -> Unfold m a b -> Unfold m a c
278mapMWithInput f (Unfold ustep uinject) = Unfold step inject
284 {-# INLINE_LATE step #-}
288 Yield x s -> f inp x >>= \a -> return $ Yield a (inp, s)
289 Skip s -> return $ Skip (inp, s)
290 Stop -> return $ Stop
292-------------------------------------------------------------------------------
293-- Convert streams into unfolds
294-------------------------------------------------------------------------------
296{-# INLINE_LATE streamStep #-}
297streamStep :: Monad m => Stream m a -> m (Step (Stream m a) a)
298streamStep (Stream step1 state) = do
299 r <- step1 defState state
301 Yield x s -> Yield x (Stream step1 s)
302 Skip s -> Skip (Stream step1 s)
305-- | Convert a stream into an 'Unfold'. Note that a stream converted to an
306-- 'Unfold' may not be as efficient as an 'Unfold' in some situations.
309fromStream :: (K.IsStream t, Monad m) => t m b -> Unfold m Void b
310fromStream str = Unfold streamStep (\_ -> return $ D.toStreamD str)
312-- | Convert a single argument stream generator function into an
313-- 'Unfold'. Note that a stream converted to an 'Unfold' may not be as
314-- efficient as an 'Unfold' in some situations.
317fromStream1 :: (K.IsStream t, Monad m) => (a -> t m b) -> Unfold m a b
318fromStream1 f = Unfold streamStep (return . D.toStreamD . f)
320-- | Convert a two argument stream generator function into an 'Unfold'. Note
321-- that a stream converted to an 'Unfold' may not be as efficient as an
322-- 'Unfold' in some situations.
325fromStream2 :: (K.IsStream t, Monad m)
326 => (a -> b -> t m c) -> Unfold m (a, b) c
327fromStream2 f = Unfold streamStep (\(a, b) -> return $ D.toStreamD $ f a b)
329-------------------------------------------------------------------------------
331-------------------------------------------------------------------------------
333-- | Lift a monadic function into an unfold generating a nil stream with a side
337nilM :: Monad m => (a -> m c) -> Unfold m a b
338nilM f = Unfold step return
340 {-# INLINE_LATE step #-}
341 step x = f x >> return Stop
343-- | Prepend a monadic single element generator function to an 'Unfold'.
346{-# INLINE_NORMAL consM #-}
347consM :: Monad m => (a -> m b) -> Unfold m a b -> Unfold m a b
348consM action unf = Unfold step inject
352 inject = return . Left
354 {-# INLINE_LATE step #-}
356 action a >>= \r -> return $ Yield r (Right (D.unfold unf a))
357 step (Right (UnStream step1 st)) = do
358 res <- step1 defState st
360 Yield x s -> return $ Yield x (Right (Stream step1 s))
361 Skip s -> return $ Skip (Right (Stream step1 s))
364-- | Lift a monadic effect into an unfold generating a singleton stream.
367effect :: Monad m => m b -> Unfold m Void b
368effect eff = Unfold step inject
370 inject _ = return True
371 {-# INLINE_LATE step #-}
372 step True = eff >>= \r -> return $ Yield r False
373 step False = return Stop
375-- | Lift a monadic function into an unfold generating a singleton stream.
377{-# INLINE singleton #-}
378singleton :: Monad m => (a -> m b) -> Unfold m a b
379singleton f = Unfold step inject
381 inject x = return $ Just x
382 {-# INLINE_LATE step #-}
383 step (Just x) = f x >>= \r -> return $ Yield r Nothing
384 step Nothing = return Stop
386-- | Identity unfold. Generates a singleton stream with the seed as the only
387-- element in the stream.
389-- > identity = singleton return
391{-# INLINE identity #-}
392identity :: Monad m => Unfold m a a
393identity = singleton return
395const :: Monad m => m b -> Unfold m a b
396const m = Unfold step inject
399 step () = m >>= \r -> return $ Yield r ()
401-- | Generates a stream replicating the seed @n@ times.
403{-# INLINE replicateM #-}
404replicateM :: Monad m => Int -> Unfold m a a
405replicateM n = Unfold step inject
407 inject x = return (x, n)
408 {-# INLINE_LATE step #-}
409 step (x, i) = return $
412 else Yield x (x, (i - 1))
414-- | Generates an infinite stream repeating the seed.
416{-# INLINE repeatM #-}
417repeatM :: Monad m => Unfold m a a
418repeatM = Unfold step return
420 {-# INLINE_LATE step #-}
421 step x = return $ Yield x x
423-- | Convert a list of pure values to a 'Stream'
424{-# INLINE_LATE fromList #-}
425fromList :: Monad m => Unfold m [a] a
426fromList = Unfold step inject
429 {-# INLINE_LATE step #-}
430 step (x:xs) = return $ Yield x xs
431 step [] = return Stop
433-- | Convert a list of monadic values to a 'Stream'
434{-# INLINE_LATE fromListM #-}
435fromListM :: Monad m => Unfold m [m a] a
436fromListM = Unfold step inject
439 {-# INLINE_LATE step #-}
440 step (x:xs) = x >>= \r -> return $ Yield r xs
441 step [] = return Stop
443-------------------------------------------------------------------------------
445-------------------------------------------------------------------------------
447{-# INLINE_NORMAL take #-}
448take :: Monad m => Int -> Unfold m a b -> Unfold m a b
449take n (Unfold step1 inject1) = Unfold step inject
454 {-# INLINE_LATE step #-}
455 step (st, i) | i < n = do
458 Yield x s -> Yield x (s, i + 1)
459 Skip s -> Skip (s, i)
461 step (_, _) = return Stop
463{-# INLINE_NORMAL takeWhileM #-}
464takeWhileM :: Monad m => (b -> m Bool) -> Unfold m a b -> Unfold m a b
465takeWhileM f (Unfold step1 inject1) = Unfold step inject1
467 {-# INLINE_LATE step #-}
473 return $ if b then Yield x s else Stop
474 Skip s -> return $ Skip s
477{-# INLINE takeWhile #-}
478takeWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
479takeWhile f = takeWhileM (return . f)
481{-# INLINE_NORMAL filterM #-}
482filterM :: Monad m => (b -> m Bool) -> Unfold m a b -> Unfold m a b
483filterM f (Unfold step1 inject1) = Unfold step inject1
485 {-# INLINE_LATE step #-}
491 return $ if b then Yield x s else Skip s
492 Skip s -> return $ Skip s
496filter :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
497filter f = filterM (return . f)
499-------------------------------------------------------------------------------
501-------------------------------------------------------------------------------
503-- | Can be used to enumerate unbounded integrals. This does not check for
504-- overflow or underflow for bounded integrals.
505{-# INLINE_NORMAL enumerateFromStepIntegral #-}
506enumerateFromStepIntegral :: (Integral a, Monad m) => Unfold m (a, a) a
507enumerateFromStepIntegral = Unfold step inject
509 inject (from, stride) = from `seq` stride `seq` return (from, stride)
510 {-# INLINE_LATE step #-}
511 step !(x, stride) = return $ Yield x $! (x + stride, stride)
513-- We are assuming that "to" is constrained by the type to be within
515{-# INLINE enumerateFromToIntegral #-}
516enumerateFromToIntegral :: (Monad m, Integral a) => a -> Unfold m a a
517enumerateFromToIntegral to =
518 takeWhile (<= to) $ supplySecond enumerateFromStepIntegral 1
520{-# INLINE enumerateFromIntegral #-}
521enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
522enumerateFromIntegral = enumerateFromToIntegral maxBound
524-------------------------------------------------------------------------------
526-------------------------------------------------------------------------------
528data ConcatState s1 s2 = ConcatOuter s1 | ConcatInner s1 s2
530{-# INLINE_NORMAL concat #-}
531concat :: Monad m => Unfold m a b -> Unfold m b c -> Unfold m a c
532concat (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
536 return $ ConcatOuter s
538 {-# INLINE_LATE step #-}
539 step (ConcatOuter st) = do
544 return $ Skip (ConcatInner s innerSt)
545 Skip s -> return $ Skip (ConcatOuter s)
548 step (ConcatInner ost ist) = do
551 Yield x s -> Yield x (ConcatInner ost s)
552 Skip s -> Skip (ConcatInner ost s)
553 Stop -> Skip (ConcatOuter ost)
555data OuterProductState s1 s2 sy x y =
556 OuterProductOuter s1 y | OuterProductInner s1 sy s2 x
558{-# INLINE_NORMAL outerProduct #-}
559outerProduct :: Monad m
560 => Unfold m a b -> Unfold m c d -> Unfold m (a, c) (b, d)
561outerProduct (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
565 return $ OuterProductOuter s1 y
567 {-# INLINE_LATE step #-}
568 step (OuterProductOuter st1 sy) = do
573 return $ Skip (OuterProductInner s sy s2 x)
574 Skip s -> return $ Skip (OuterProductOuter s sy)
577 step (OuterProductInner ost sy ist x) = do
580 Yield y s -> Yield (x, y) (OuterProductInner ost sy s x)
581 Skip s -> Skip (OuterProductInner ost sy s x)
582 Stop -> Skip (OuterProductOuter ost sy)
584-- XXX This can be used to implement a Monad instance for "Unfold m ()".
586data ConcatMapState s1 s2 = ConcatMapOuter s1 | ConcatMapInner s1 s2
588{-# INLINE_NORMAL concatMapM #-}
590 => (b -> m (Unfold m () c)) -> Unfold m a b -> Unfold m a c
591concatMapM f (Unfold step1 inject1) = Unfold step inject
595 return $ ConcatMapOuter s
597 {-# INLINE_LATE step #-}
598 step (ConcatMapOuter st) = do
602 Unfold step2 inject2 <- f x
603 innerSt <- inject2 ()
604 return $ Skip (ConcatMapInner s (Stream (\_ ss -> step2 ss)
606 Skip s -> return $ Skip (ConcatMapOuter s)
609 step (ConcatMapInner ost (UnStream istep ist)) = do
610 r <- istep defState ist
612 Yield x s -> Yield x (ConcatMapInner ost (Stream istep s))
613 Skip s -> Skip (ConcatMapInner ost (Stream istep s))
614 Stop -> Skip (ConcatMapOuter ost)
616------------------------------------------------------------------------------
618------------------------------------------------------------------------------
620-- | The most general bracketing and exception combinator. All other
621-- combinators can be expressed in terms of this combinator. This can also be
622-- used for cases which are not covered by the standard combinators.
626{-# INLINE_NORMAL gbracket #-}
629 => (a -> m c) -- ^ before
630 -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
631 -> (c -> m d) -- ^ after, on normal stop
632 -> Unfold m (c, e) b -- ^ on exception
633 -> Unfold m c b -- ^ unfold to run
635gbracket bef exc aft (Unfold estep einject) (Unfold step1 inject1) =
643 return $ Right (s, r)
645 {-# INLINE_LATE step #-}
646 step (Right (st, v)) = do
647 res <- exc $ step1 st
650 Yield x s -> return $ Yield x (Right (s, v))
651 Skip s -> return $ Skip (Right (s, v))
652 Stop -> aft v >> return Stop
655 return $ Skip (Left r)
659 Yield x s -> return $ Yield x (Left s)
660 Skip s -> return $ Skip (Left s)
663-- | The most general bracketing and exception combinator. All other
664-- combinators can be expressed in terms of this combinator. This can also be
665-- used for cases which are not covered by the standard combinators.
669{-# INLINE_NORMAL gbracketIO #-}
671 :: (MonadIO m, MonadBaseControl IO m)
672 => (a -> m c) -- ^ before
673 -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
674 -> (c -> m d) -- ^ after, on normal stop, or GC
675 -> Unfold m (c, e) b -- ^ on exception
676 -> Unfold m c b -- ^ unfold to run
678gbracketIO bef exc aft (Unfold estep einject) (Unfold step1 inject1) =
685 ref <- D.newFinalizedIORef (aft r)
687 return $ Right (s, r, ref)
689 {-# INLINE_LATE step #-}
690 step (Right (st, v, ref)) = do
691 res <- exc $ step1 st
694 Yield x s -> return $ Yield x (Right (s, v, ref))
695 Skip s -> return $ Skip (Right (s, v, ref))
697 liftIO $ writeIORef ref Nothing
700 liftIO (writeIORef ref Nothing)
702 return $ Skip (Left r)
706 Yield x s -> return $ Yield x (Left s)
707 Skip s -> return $ Skip (Left s)
710-- The custom implementation of "before" is slightly faster (5-7%) than
711-- "_before". This is just to document and make sure that we can always use
712-- gbracket to implement before. The same applies to other combinators as well.
714{-# INLINE_NORMAL _before #-}
715_before :: Monad m => (a -> m c) -> Unfold m a b -> Unfold m a b
716_before action unf = gbracket (\x -> action x >> return x) (fmap Right)
717 (\_ -> return ()) undefined unf
719-- | Run a side effect before the unfold yields its first element.
722{-# INLINE_NORMAL before #-}
723before :: Monad m => (a -> m c) -> Unfold m a b -> Unfold m a b
724before action (Unfold step1 inject1) = Unfold step inject
733 {-# INLINE_LATE step #-}
737 Yield x s -> return $ Yield x s
738 Skip s -> return $ Skip s
741{-# INLINE_NORMAL _after #-}
742_after :: Monad m => (a -> m c) -> Unfold m a b -> Unfold m a b
743_after aft = gbracket return (fmap Right) aft undefined
745-- | Run a side effect whenever the unfold stops normally.
747-- Prefer afterIO over this as the @after@ action in this combinator is not
748-- executed if the unfold is partially evaluated lazily and then garbage
752{-# INLINE_NORMAL after #-}
753after :: Monad m => (a -> m c) -> Unfold m a b -> Unfold m a b
754after action (Unfold step1 inject1) = Unfold step inject
762 {-# INLINE_LATE step #-}
766 Yield x s -> return $ Yield x (s, v)
767 Skip s -> return $ Skip (s, v)
768 Stop -> action v >> return Stop
770-- | Run a side effect whenever the unfold stops normally
771-- or is garbage collected after a partial lazy evaluation.
774{-# INLINE_NORMAL afterIO #-}
775afterIO :: (MonadIO m, MonadBaseControl IO m)
776 => (a -> m c) -> Unfold m a b -> Unfold m a b
777afterIO action (Unfold step1 inject1) = Unfold step inject
783 ref <- D.newFinalizedIORef (action x)
786 {-# INLINE_LATE step #-}
790 Yield x s -> return $ Yield x (s, ref)
791 Skip s -> return $ Skip (s, ref)
793 Just f <- readIORef ref
794 writeIORef ref Nothing
797{-# INLINE_NORMAL _onException #-}
798_onException :: MonadCatch m => (a -> m c) -> Unfold m a b -> Unfold m a b
799_onException action unf =
800 gbracket return MC.try
802 (nilM (\(a, (e :: MC.SomeException)) -> action a >> MC.throwM e)) unf
804-- | Run a side effect whenever the unfold aborts due to an exception.
807{-# INLINE_NORMAL onException #-}
808onException :: MonadCatch m => (a -> m c) -> Unfold m a b -> Unfold m a b
809onException action (Unfold step1 inject1) = Unfold step inject
817 {-# INLINE_LATE step #-}
819 res <- step1 st `MC.onException` action v
821 Yield x s -> return $ Yield x (s, v)
822 Skip s -> return $ Skip (s, v)
825{-# INLINE_NORMAL _finally #-}
826_finally :: MonadCatch m => (a -> m c) -> Unfold m a b -> Unfold m a b
828 gbracket return MC.try action
829 (nilM (\(a, (e :: MC.SomeException)) -> action a >> MC.throwM e)) unf
831-- | Run a side effect whenever the unfold stops normally or aborts due to an
834-- Prefer finallyIO over this as the @after@ action in this combinator is not
835-- executed if the unfold is partially evaluated lazily and then garbage
839{-# INLINE_NORMAL finally #-}
840finally :: MonadCatch m => (a -> m c) -> Unfold m a b -> Unfold m a b
841finally action (Unfold step1 inject1) = Unfold step inject
849 {-# INLINE_LATE step #-}
851 res <- step1 st `MC.onException` action v
853 Yield x s -> return $ Yield x (s, v)
854 Skip s -> return $ Skip (s, v)
855 Stop -> action v >> return Stop
857-- | Run a side effect whenever the unfold stops normally, aborts due to an
858-- exception or if it is garbage collected after a partial lazy evaluation.
861{-# INLINE_NORMAL finallyIO #-}
862finallyIO :: (MonadAsync m, MonadCatch m)
863 => (a -> m c) -> Unfold m a b -> Unfold m a b
864finallyIO action (Unfold step1 inject1) = Unfold step inject
870 ref <- D.newFinalizedIORef (action x)
873 {-# INLINE_LATE step #-}
874 step (st, v, ref) = do
875 res <- step1 st `MC.onException` action v
877 Yield x s -> return $ Yield x (s, v, ref)
878 Skip s -> return $ Skip (s, v, ref)
880 liftIO (writeIORef ref Nothing)
881 action v >> return Stop
883{-# INLINE_NORMAL _bracket #-}
884_bracket :: MonadCatch m
885 => (a -> m c) -> (c -> m d) -> Unfold m c b -> Unfold m a b
886_bracket bef aft unf =
887 gbracket bef MC.try aft (nilM (\(a, (e :: MC.SomeException)) -> aft a >>
890-- | @bracket before after between@ runs the @before@ action and then unfolds
891-- its output using the @between@ unfold. When the @between@ unfold is done or
892-- if an exception occurs then the @after@ action is run with the output of
893-- @before@ as argument.
895-- Prefer bracketIO over this as the @after@ action in this combinator is not
896-- executed if the unfold is partially evaluated lazily and then garbage
900{-# INLINE_NORMAL bracket #-}
901bracket :: MonadCatch m
902 => (a -> m c) -> (c -> m d) -> Unfold m c b -> Unfold m a b
903bracket bef aft (Unfold step1 inject1) = Unfold step inject
912 {-# INLINE_LATE step #-}
914 res <- step1 st `MC.onException` aft v
916 Yield x s -> return $ Yield x (s, v)
917 Skip s -> return $ Skip (s, v)
918 Stop -> aft v >> return Stop
920-- | @bracket before after between@ runs the @before@ action and then unfolds
921-- its output using the @between@ unfold. When the @between@ unfold is done or
922-- if an exception occurs then the @after@ action is run with the output of
923-- @before@ as argument. The after action is also executed if the unfold is
924-- paritally evaluated and then garbage collected.
927{-# INLINE_NORMAL bracketIO #-}
928bracketIO :: (MonadAsync m, MonadCatch m)
929 => (a -> m c) -> (c -> m d) -> Unfold m c b -> Unfold m a b
930bracketIO bef aft (Unfold step1 inject1) = Unfold step inject
937 ref <- D.newFinalizedIORef (aft r)
940 {-# INLINE_LATE step #-}
941 step (st, v, ref) = do
942 res <- step1 st `MC.onException` aft v
944 Yield x s -> return $ Yield x (s, v, ref)
945 Skip s -> return $ Skip (s, v, ref)
947 liftIO (writeIORef ref Nothing)
950-- | When unfolding if an exception occurs, unfold the exception using the
951-- exception unfold supplied as the first argument to 'handle'.
954{-# INLINE_NORMAL handle #-}
955handle :: (MonadCatch m, Exception e)
956 => Unfold m e b -> Unfold m a b -> Unfold m a b
958 gbracket return MC.try (\_ -> return ()) (discardFirst exc) unf
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list