finally and onException are two functions from the module Control.Exception, which have the same signature but behave differently.
Here is the document.
For finally, it says:
finally
:: IO a -- computation to run first
-> IO b -- computation to run afterward (even if an exception was raised)
-> IO a
, while for onException, it says:
Like
finally, but only performs the final action if there was an exception raised by the computation.
So I do the following test:
ghci> finally (return $ div 4 2) (putStrLn "Oops!")
Oops!
2
ghci> finally (return $ div 4 0) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero
which acts as expected.
However, onException does not:
ghci> onException (return $ div 4 2) (putStrLn "Oops!")
2
ghci> onException (return $ div 4 0) (putStrLn "Oops!") -- does not act as expected
*** Exception: divide by zero
As describe above, onException only performs the final action if an exception was raised, but the example above shows that onException does not perform the final action, i.e. putStrLn "Oops!" when an exception raised.
After checking the source code for onException, I try the test as follow:
ghci> throwIO (SomeException DivideByZero) `catch` \e -> do {_ <- putStrLn "Oops!"; throwIO (e :: SomeException)}
Oops!
*** Exception: divide by zero
ghci> onException (throwIO (SomeException DivideByZero)) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero
As can be seen, when an exception raised explicitly, the final action was performed.
So the question is return $ div 4 0 really throws an exception, but why onException (return $ div 4 0) (putStrLn "Oops!") does not perform the final action putStrLn "Oops!"? What am I missing? And how the exception was performed?
ghci> throwIO (SomeException DivideByZero)
*** Exception: divide by zero
ghci> (return $ div 4 0) :: IO Int
*** Exception: divide by zero