我需要执行许多计算,这些计算可能会以多种难以想象的方式失败,但这些失败可以忽略(通知用户)。但是,我不想像UserInterrupt
那样忽略AsyncException
,所以用户可以使用Control-C来停止程序。
如果我尝试中止下面的程序,它将只输出# failed: user interrupt
—就好像异常不能转换为AsyncException
一样。从user interrupt
被打印出来,我们知道异常是UserInterrupt
,它可以被强制转换(cast UserInterrupt :: Maybe AsyncException
)。
UserInterrupt
异常没有被识别并且被重新抛出?import Control.Exception
import Control.Monad
import Data.Typeable
main = forM_ [1..500000] processNumber
processNumber n =
handle h (simulateComputation n)
where
h (SomeException e) =
case (cast e :: Maybe AsyncException) of
Just ae ->
throw ae
Nothing ->
putStrLn $ show n ++ " failed: " ++ show e
simulateComputation n = do
putStrLn "...Obtaining data and computing..."
--when (n `mod` 1000 == 0) $
-- throw (ErrorCall "ComputationFailed")
--when (n `mod` 1111 == 0) $
-- throw DivideByZero
这是语言的黑暗角落。实际上,AsyncException
在转换为SomeException
时被包装成SomeAsyncException
。使用asyncExceptionFromException
代替cast
(或强制转换为SomeAsyncException
)