Haskell 为什么不是';t'catch'捕获此异常?
我有一个服务应用程序和一个端点,它在数据库中创建一个记录,然后尝试在S3位置之间复制一个文件。如果复制失败,我想回滚事务。我有这个接线员Haskell 为什么不是';t'catch'捕获此异常?,haskell,Haskell,我有一个服务应用程序和一个端点,它在数据库中创建一个记录,然后尝试在S3位置之间复制一个文件。如果复制失败,我想回滚事务。我有这个接线员 {-# LANGUAGE TemplateHaskell #-} import Control.Monad.Catch import Control.Monad.Except import Control.Monad.Logger (<??) :: (MonadError e m, MonadCatch m, MonadLogger m)
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad.Logger
(<??)
:: (MonadError e m, MonadCatch m, MonadLogger m)
=> e
-> m a
-> m a
(<??) err a = a `catchAll` (\e -> $(logErrorSH) e >> throwError err)
infixr 0 <??
为了测试逻辑,我移动了我的AWS凭证文件,希望内部AWS操作会抛出一个,然后
(如果你的应用程序
类型最终是一个,问题可能是异常
的MonadError
和MonadCatch
实例不匹配:
MonadError
实例在ExceptT e
MonadCatch
intance捕获底层monad中的异常,而不是ExceptT e
错误
MonadCatch(不包括e m)
的代码如下:
-- | Catches exceptions from the base monad.
instance MonadCatch m => MonadCatch (ExceptT e m) where
catch (ExceptT m) f = ExceptT $ catch m (runExceptT . f)
有一个实例,因此可以将其作为两个实例抛出
Edit:“exceptions”类MonadMask
提供了一个功能,即使对于ExceptT
,它也表现得相当好:它在ExceptT e
异常和常规异常的情况下运行清理操作:
仅在主操作中引发错误时运行操作。与
一个例外,这适用于所有类型的错误,而不仅仅是异常。
例如,如果f是一个异常计算,它以左键终止,
计算onError f g将执行g,而onException f g将执行g
不是
处理回滚时,这是一个比catch更好的选择。Hmm,好吧。我想我明白了。我的App a
是一个ReaderT配置(LoggingT(除了ServantErr IO))一个
,其中包含MonadError
、MonadCatch
和MonadThrow
的实例。我是否需要为其中任何一个或所有实例编写自定义实例?或者我如何才能确保在抛出异常的monad中捕获异常?也许您可以修改(感谢您的额外编辑!我将给onError
一个镜头。因此,在我的处理程序中使用onError
而不是catch
,似乎确实可以做到这一点。不过,我确实同意,现在我考虑了更多,混合MonadError
和MonadThrow/catch
似乎是错误的(一开始就造成了这种混乱)。但是,如果我将我的throwError
s更改为throwM
,这会导致错误不会传播回客户端,例如,引发异常,响应为500,例如,如果我使用throwError err400
,则会创建正确的响应。使用throwM
会更好吗Y在处理程序中的何处,catch
error,然后对其使用throwerr
?
-- | Catches exceptions from the base monad.
instance MonadCatch m => MonadCatch (ExceptT e m) where
catch (ExceptT m) f = ExceptT $ catch m (runExceptT . f)