使用`exceptions`包的邪恶异常行为

时间:2015-03-29 19:58:33

标签: haskell

使用exceptions包时,我对一些特殊的行为感到吃惊。

我有一个看起来像的函数:

testme ::(MonadThrow m , Monad O m, Applicative m) => FilePath -> Text -> m ()
testme fp t = testfoo fp t >> testbar fp t

testfoo :: (MonadThrow m , MonadIO m, Applicative m) => FilePath -> Text -> m ()
testbar :: (MonadThrow m , MonadIO m, Applicative m) => FilePath -> Text -> m ()

另一个模块将捕获这里抛出的所有特定异常:

catching _PrettyError
         (do {testCatalog workingdir c; return stm})
         (return . S.Left)

_PrettyError定义如下:

_PrettyError :: Prism' SomeException PrettyError
_PrettyError = prism' toException fromException

我的第一个惊喜来自于如果我更改testme

testme = testfoo  >> testbar

Ghc拒绝编译,因为它无法推断出MonadThrow。

尝试此签名:

testme :: FilePath -> Text -> IO ()
testme = testfoo >> testbar

Ghc仍然不想推断MonadThrow,我觉得更令人惊讶。

我现在正在进行另一种类型的签名更改:

testfoo :: FilePath -> Text -> IO ()
testbar :: FilePath -> Text -> IO ()

并且...它确实编译但是在完全困惑的时候我意识到只有来自第二个调用(testbar)的异常才会被catching捕获。 testfoo抛出的那些只是以某种方式丢失......

我很惊讶改变签名会彻底改变异常处理。

The commit of the real code is here(附注)。

当前代码确实按预期工作。

我的问题是为什么从显式约束到特定IO monad的签名更改会导致这种意外行为(>>的第一项中的例外不再被捕获)。我的理解是,在这两种情况下IO monad都在起作用。

感谢您的帮助。

1 个答案:

答案 0 :(得分:5)

您可能需要testme fp t = testfoo fp t >> testbar fp t而不是testme = testfoo >> testbar。在后者中,(>>)来自(->) r实例,这让您感到惊讶:f >> gg monad的(->) r相同(但是让你的电脑变得更热一些。)