exception之在 MonadResource 实例中捕获 IO 异常

wayfarer 阅读:144 2025-02-15 21:57:57 评论:0

精简版

here 中的问题相同,但在通用 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 

我遇到的问题是:

看起来处理IO异常的唯一方法是退出ResourceT层,这让我很困扰:我希望能够在本地处理异常无需遍历 monad 转换器堆栈。

关于信息,在我的真实代码中,ab 实际上是来自Network.HTTP.Conduithttp 函数。 .

感谢您的见解。

有问题的最少代码

可通过安装了 http-conduit 库的 ghc --make example.hs 进行编译:

{-# 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) 

请您参考如下方法:

http 不会抛出 IOException,它会抛出 HttpExceptionInternalIOException 是后者的构造函数之一。

如果您想捕获所有异常,您应该捕获 HttpExceptionSomeException


标签:Exception
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号