Guest User

Untitled

a guest
Jun 23rd, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.12 KB | None | 0 0
  1. {-# LANGUAGE LambdaCase #-}
  2. {-# LANGUAGE TupleSections #-}
  3. {-# LANGUAGE RankNTypes #-}
  4.  
  5. module Control.Monad.Catch.Scope (
  6. Scope,
  7. FinalizationException (..),
  8. withScope,
  9. withScopeLiftedTo,
  10. atEndOf,
  11. scopedTo,
  12. scoped
  13. ) where
  14.  
  15. import Control.Monad (void, (>=>))
  16. import Control.Monad.Catch (Exception, MonadCatch, MonadMask, SomeException, bracket, mask_, catchAll, throwM)
  17. import Control.Monad.IO.Class (MonadIO, liftIO)
  18. import Data.IORef (IORef, newIORef, readIORef, atomicModifyIORef)
  19. import Data.Functor (($>))
  20. import Data.Maybe (catMaybes)
  21. import Type.Reflection (Typeable)
  22.  
  23. newtype Scope m = Scope { addFinalizer :: m () -> IO () }
  24.  
  25. newtype FinalizationException = FinalizationException [SomeException] deriving (Show, Typeable)
  26. instance Exception FinalizationException
  27.  
  28. withScope :: (MonadMask m, MonadIO m) => (Scope m -> m a) -> m a
  29. withScope useScope = bracket (liftIO $ newIORef []) finalize (useScope . newScope)
  30. where
  31. newScope :: MonadIO m => IORef [m ()] -> Scope m
  32. newScope ref = Scope $ \finalizer -> liftIO $ atomicModifyIORef ref $ (, ()) . (finalizer :)
  33.  
  34. finalize :: (MonadCatch m, MonadIO m) => IORef [m ()] -> m ()
  35. finalize =
  36. liftIO . readIORef >=>
  37. fmap catMaybes . mapM maybeCaughtException >=>
  38. \case
  39. [] -> return ()
  40. exceptions -> throwM $ FinalizationException exceptions
  41.  
  42. maybeCaughtException :: MonadCatch m => m () -> m (Maybe SomeException)
  43. maybeCaughtException m = catchAll (m $> Nothing) (return . Just)
  44.  
  45. withScopeLiftedTo :: (MonadIO super, MonadIO sub) => Scope super -> (forall b. sub b -> super b) -> (Scope sub -> sub a) -> super a
  46. withScopeLiftedTo superScope lift useSubScope = lift $ useSubScope $ Scope $ addFinalizer superScope . lift
  47.  
  48. atEndOf :: MonadIO n => Scope m -> m () -> n ()
  49. atEndOf scope finalizer = liftIO $ addFinalizer scope finalizer
  50.  
  51. scoped :: (MonadMask m, MonadIO m) => m a -> (a -> m b) -> Scope m -> m a
  52. scoped acquire release scope = mask_ $ do
  53. a <- acquire
  54. atEndOf scope (void $ release a)
  55. return a
  56.  
  57. scopedTo :: (MonadMask m, MonadIO m) => Scope m -> m a -> (a -> m b) -> m a
  58. scopedTo scope acquire release = scoped acquire release scope
Add Comment
Please, Sign In to add comment