Haskell 如何捕获runResourceT中的异常
我希望在不释放资源的情况下捕获runResourceT内部的异常,但是函数catch在IO内部运行计算。有没有一种方法可以捕获runResourceT内部的异常,或者什么是重构代码的推荐方法 谢谢你的帮助Haskell 如何捕获runResourceT中的异常,haskell,Haskell,我希望在不释放资源的情况下捕获runResourceT内部的异常,但是函数catch在IO内部运行计算。有没有一种方法可以捕获runResourceT内部的异常,或者什么是重构代码的推荐方法 谢谢你的帮助 {-# LANGUAGE FlexibleContexts #-} module Main where import Control.Exception as EX import Control.Monad.IO.Class import Control.Monad.Trans.Resou
{-# 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."
{-#语言灵活上下文}
模块主要在哪里
导入控制。异常为EX
导入控制.Monad.IO.Class
导入控制.Monad.Trans.Resource
类型资源=字符串
allocResource::IO资源
allocResource=let r=“资源”
在putStrLn中(r++“打开”)>>返回r
closeResource::Resource->IO()
closeResource r=putStrLn$r++“已关闭。”
withResource::(MonadIO m
,MonadBaseControl IO m
,MonadThrow m
,MonadUnsafeIO m
)=>(资源->资源并购)->并购
withResource f=runResourceT$do
(ur)资源->资源m Int
useResource r=liftIO$putStrLn(“使用”++r)>>返回1
main::IO()
main=do
putStrLn“开始…”
withResource$\r->do
xResourceT
是来自该软件包的一个实例,该软件包设计用于将控制结构(如forkIO
和catch
提升为转换单体)
该软件包构建在monad控件之上,包含具有标准控件结构版本的模块,可在任何MonadBaseControl
中工作。对于异常处理,您可以使用模块中的函数。因此,只需将import qualified Control.Exception.Lifted改为EX
1,您的代码就可以正常工作了
1注意此处的合格;相当令人困惑的是,import A as B
实际上将A
中的所有定义导入范围,并将B
定义为模块的别名!您需要使用qualified
来确保定义不被纳入范围,而是通过B
别名专门访问。作为替代方法,您可以使用包中的实例。您只需从Control.Monad.catch
替换广义版本的catch
:
import Control.Monad.Catch
…
main = do
…
withResource $ \r -> do
…
y <- Control.Monad.Catch.catch (useResource r) (\e -> …)
import Control.Monad.Catch
…
main=do
…
withResource$\r->do
…
y…)
感谢您的回答和评论。它的工作原理和预期一样,帮助我更好地理解monads变形金刚。