Pierre R
Pierre R

Reputation: 216

Wicked exceptions behavior using the `exceptions` package

I have been taken aback by some peculiar behavior while using the exceptions package.

I have a function that looks like:

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

with

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

Another module will catch all the specific exceptions thrown here doing something along the line:

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

And _PrettyError is defined as such:

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

My first surprise comes from the fact that if I change testme for:

testme = testfoo  >> testbar

Ghc refuses to compile because it can't deduce MonadThrow.

Trying this signature:

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

Ghc still don't want to deduce MonadThrow which I find more surprising.

I am now making another type signature change:

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

And ... it does compile but in utter bewilderment I have then realized that only the exceptions from the second call (testbar) would be caught by catching. The ones throws by testfoo are just lost somehow ...

I am amazed that changing signatures would completely change the exception handling.

The commit of the real code is here (with notes).

The current code does work as expected.

My question is really why the signature change from explicit constraints to a specific IO monad causes such an unexpected behavior (the exceptions from the first term of >> aren't caught anymore). My understanding is that in both case the IO monad is at play.

Thanks for your help.

Upvotes: 1

Views: 59

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153102

You probably meant testme fp t = testfoo fp t >> testbar fp t instead of testme = testfoo >> testbar. In the latter, the (>>) is from the (->) r instance, which is what's surprising you: f >> g is the same as just g for the (->) r monad (but makes your computer a little hotter).

Upvotes: 5

Related Questions