简洁版本
与此处相同的问题,但在通用MonadResource实例中而不是在明确的ResourceT m.
长版
您将如何定义catch这样的函数:
import Control.Exception (Exception, IOException)
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
catch :: (MonadResource m, Exception e) -> m () -> (e -> m ()) -> m ()
catch = undefined
-- 'a' and 'b' are functions from an external library,
-- so I can't actually change their implementation
a, b :: MonadResource m => m ()
a = -- Something that might throw IO exceptions
b = -- Something that might throw IO exceptions
main :: IO ()
main = runResourceT $ do
a `catch` \(e :: IOException) -> -- Exception handling
b `catch` \(e :: IOException) -> -- Exception handling
我遇到的问题是:
- 在
Control.Exception,catch仅适用于裸IOs ; - 在
Control.Exception.Lifted,catch需要一个 的实例MonadBaseControl,MonadResource不幸的是不是(我想知道为什么); MonadResource暗示MonadThrow它定义了一个monadThrow没有“catch”等价物的函数(我想知道为什么);
看起来处理IO异常的唯一方法是退出ResourceT层,这让我很困扰:我希望能够在本地处理异常,而无需通过 monad 转换器堆栈。
有关信息,在我的真实代码中,a实际上b是http来自Network.HTTP.Conduit.
感谢您的见解。
有问题的最少代码
ghc --make example.hs与安装的库一起编译http-conduit:
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
import Control.Exception.Lifted (IOException, catch)
import Control.Monad.Base (liftBase)
import Control.Monad.Error (MonadError(..), runErrorT)
import Control.Monad.Trans.Control (MonadBaseControl)
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
import Data.Conduit
import Data.Conduit.List (consume)
import Data.Conduit.Text (decode, utf8)
import Data.Text (Text)
import Network.HTTP.Client
import Network.HTTP.Conduit (http)
main :: IO ()
main = do
result <- runErrorT $ runResourceT f
putStrLn $ "OK: " ++ show result
f :: (MonadBaseControl IO m, MonadResource m, MonadError String m) => m [Text]
f = do
req <- liftBase $ parseUrl "http://uri-that-does-not-exist.abc"
manager <- liftBase $ newManager defaultManagerSettings
response <- (http req manager `catch` \(e :: IOException) -> throwError $ show e)
response $$+- decode utf8 =$ consume
执行时,该程序以错误结束,输出如下:
InternalIOException getAddrInfo: does not exist (Name or service not known)