How to catch an exception inside runResourceT

haskell

Solution

`ResourceT` is an instance of `MonadBaseControl` from the monad-control package, which is designed for lifting control structures like `forkIO` and `catch` into transformed monads.

The lifted-base package, which is built on top of monad-control, contains modules with versions of standard control structures that work in any `MonadBaseControl`. For exception handling, you can use the functions in the `Control.Exception.Lifted` module. So, just `import qualified Control.Exception.Lifted as EX`1 instead, and your code should work fine.

1 Note the `qualified` here; quite confusingly, `import A as B` actually imports all of the definitions in `A` into scope, and simply defines `B` as an alias for the module! You need to use `qualified` to ensure that the definitions are not brought into scope, and are instead accessed exclusively through the `B` alias.

Problem

I would like to catch an exception inside runResourceT without releasing the resource, but the function catch runs the computation inside IO. Is there a way to catch an exception inside runResourceT, or what is the recommended way to refactor the code ? Thank you for your help. ``` {-# LANGUAGE FlexibleContexts #-} module Main where import Control.Exception as EX import Control.Monad.IO.Class import Control.Monad.Trans.Resource type Resource = String allocResource :: IO Resource allocResource = let r = "Resource" in putStrLn (r ++ " opened.") >> return r closeResource :: Resource -> IO () closeResource r = putStrLn $ r ++ " closed." withResource :: ( MonadIO m , MonadBaseControl IO m , MonadThrow m , MonadUnsafeIO m ) => (Resource -> ResourceT m a) -> m a withResource f = runResourceT $ do (_, r) <- allocate allocResource closeResource f r useResource :: ( MonadIO m , MonadBaseControl IO m , MonadThrow m , MonadUnsafeIO m ) => Resource -> ResourceT m Int useResource r = liftIO $ putStrLn ("Using " ++ r) >> return 1 main :: IO () main = do putStrLn "Start..." withResource $ \r -> do x <- useResource r {-- This does not compile as the catch computation runs inside IO y <- liftIO $ EX.catch (useResource r) (\e -> do putStrLn $ show (e::SomeException) return 0) --} return () putStrLn "Done." ```

Original source