throw和throwIO有什么区别

Leo*_*ang 5 haskell exception

该文件说:

throwIO变量应优先使用throw引发IO monad中的异常,因为它可以保证相对于其他IO操作的排序,而throw则不能。

看完之后我还是很困惑。是否有示例显示throw会导致问题,而throwIO不会导致问题?

附加问题:

以下陈述正确吗?

  1. 如果throw用于在IO中引发异常,则不能保证异常的顺序。
  2. 如果throw用于将异常抛出为非IO值,则可以保证异常的顺序。

如果我需要在Monad Transformer中抛出一个异常,我必须使用它来throw代替throwIO,它是否可以保证异常的顺序?

jbe*_*man 5

我认为文档可以改进。您需要记住的问题throw等是throw返回一个在评估时“爆炸”(引发异常)的底部值;但是由于懒惰,很难控制是否以及何时进行评估。

例如:

Prelude Control.Exception> let f n = if odd n then throw Underflow else True
Prelude Control.Exception> snd (f 1, putStrLn "this is fine")
this is fine
Run Code Online (Sandbox Code Playgroud)

这可以说是你想要发生的事情,但通常不是。例如,不是上面的元组,您最终可能会得到一个大数据结构,其中包含一个爆炸元素,导致在您的 Web 服务器向用户返回 200 或其他内容后引发异常。

throwIO 允许您按顺序引发异常,就好像它是另一个 IO 操作一样,因此可以对其进行严格控制:

Prelude Control.Exception> throwIO Underflow >> putStrLn "this is fine"
*** Exception: arithmetic underflow
Run Code Online (Sandbox Code Playgroud)

...就像做print 1 >> print 2

但请注意,你其实可以代替throwIOthrow,例如:

Prelude Control.Exception> throw Underflow >> putStrLn "this is fine"
*** Exception: arithmetic underflow
Run Code Online (Sandbox Code Playgroud)

从现在开始,爆炸值的类型为IO athrowIO除了记录一个习语之外,我实际上不清楚为什么存在。也许其他人可以回答这个问题。

作为最后一个示例,这与我的第一个示例存在相同的问题:

Prelude Control.Exception> return (throw Underflow) >> putStrLn "this is fine"
this is fine
Run Code Online (Sandbox Code Playgroud)

  • 还有比这更多的东西。`throw` 导致不精确的异常 - 当涉及到 GHC 时,允许以奇怪的方式重写代码,因为 GHC 允许将所有底部视为等效。`throwIO` 防止以这种方式重写 - 您得到的异常将以您期望的方式抛出。 (2认同)