finally
and onException
是模块中的两个函数Control.Exception
,它们具有相同的签名但行为不同。Here https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.11.1.0/Control-Exception.html#v:onException是文档。
为了finally
, 它说:
finally
:: IO a -- computation to run first
-> IO b -- computation to run afterward (even if an exception was raised)
-> IO a
,同时对于onException
, 它说:
Like finally
,但仅在存在时才执行最终操作
计算引发的异常。
所以我做了以下测试:
ghci> finally (return $ div 4 2) (putStrLn "Oops!")
Oops!
2
ghci> finally (return $ div 4 0) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero
其行为符合预期。
然而,onException
才不是:
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
如上所述,onException
仅在引发异常时执行最终操作,但上面的示例表明onException
不执行最终操作,即putStrLn "Oops!"
当发生异常时。
检查后源代码 https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.11.1.0/src/Control.Exception.Base.html#onException for onException
,我尝试如下测试:
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
可以看出,当显式引发异常时,将执行最终操作。
所以问题是return $ div 4 0
确实抛出异常,但是why onException (return $ div 4 0) (putStrLn "Oops!")
不执行最后的动作putStrLn "Oops!"
?我缺少什么?以及异常是如何执行的?
ghci> throwIO (SomeException DivideByZero)
*** Exception: divide by zero
ghci> (return $ div 4 0) :: IO Int
*** Exception: divide by zero