我有以下代码:
handledIO :: Int -> IO Int
handledIO x = handle (printException x) $ return $ [1, 2, 3] !! x
printException :: Int -> SomeException -> IO Int
printException x (SomeException e) = do
print ("Exception", x, e)
throw e
当我在ghci中键入handledIO 8
时,我希望看到("Exception", 8, "*** Exception: Prelude.!!: index too large")
将被打印,但实际上仅打印异常。为什么?
答案 0 :(得分:12)
原因有点微妙,与Haskell的懒惰有关。
让我们使用具有相同问题的此示例版本:
EventLoop
问题是handledIO :: Int -> IO Int
handledIO x = handle (printException x) $ return undefined
仅捕获在运行作为参数传递的handle
操作时引发的异常。动作IO
成功完成了 ,因为从未从动作中 检查return undefined
。但是,当其他undefined
操作尝试实际检查返回的值时(例如,尝试将其打印到控制台),则会遇到令人讨厌的惊喜。
此“ IO
中的延迟异常抛出结果值”问题的一种解决方案是使用IO
中的evaluate
函数而不是Control.Exception
。 return
注意在evaluate
操作返回之前将参数减为WHNF,因此它会触发异常:
IO
现在可以使用了
handledIO :: Int -> IO Int
handledIO x = handle (printException x) $ evaluate $ undefined
此外,您正在*Main> handledIO 10
("Exception",10,Prelude.undefined
动作中使用throw
。在进行IO
动作时,throwIO
比IO
更好。