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
我遇到的问题是:
- 在
Control.Exception
,catch
仅适用于裸IO
; - 在
Control.Exception.Lifted
,catch
需要MonadBaseControl
的实例,不幸的是MonadResource
不是(我想知道为什么);< -
MonadResource
暗示MonadThrow
它定义了一个monadThrow
函数,但没有等效的“catch”(我想知道为什么);
看起来处理IO
异常的唯一方法是退出ResourceT
层,这让我很困扰:我希望能够在本地处理异常无需遍历 monad 转换器堆栈。
关于信息,在我的真实代码中,a
和b
实际上是来自Network.HTTP.Conduit
的http
函数。 .
感谢您的见解。
有问题的最少代码
可通过安装了 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
,它会抛出 HttpException
而 InternalIOException
是后者的构造函数之一。
如果您想捕获所有异常,您应该捕获 HttpException
或 SomeException
。
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。