throwIO变量应优先于throw引发,以在IO monad中引发异常,因为它可以保证相对于其他IO操作的排序,而throw则不能。
看完之后我还是很困惑。有没有一个例子表明throw会引起问题,而throwIO不会引起问题?
其他问题:
以下陈述正确吗?
throw
在IO中引发异常,则不能保证异常的顺序。throw
以非IO值引发异常,则可以保证异常的顺序。如果我需要在Monad Transformer中抛出异常,而我必须使用throw
而不是throwIO
,那么它可以保证异常的顺序吗?
答案 0 :(得分:4)
我认为文档可以改进。 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
这可以说是您想要发生的事情,但通常不是。例如而不是上面的元组,您可能最终会得到一个带有单个爆炸元素的大数据结构,该结构会导致您的Web服务器向用户返回200或其他之后引发异常。
throwIO
允许您顺序引发异常,就像它是另一个IO操作一样,因此可以对其进行严格控制:
Prelude Control.Exception> throwIO Underflow >> putStrLn "this is fine"
*** Exception: arithmetic underflow
...就像做print 1 >> print 2
一样。
但是请注意,您实际上可以将throwIO
替换为throw
,例如:
Prelude Control.Exception> throw Underflow >> putStrLn "this is fine"
*** Exception: arithmetic underflow
由于现在爆炸值的类型为IO a
。除了记录成语之外,我实际上还不清楚为什么throwIO
存在。也许其他人可以回答。
作为最后一个示例,这与我的第一个示例存在相同的问题:
Prelude Control.Exception> return (throw Underflow) >> putStrLn "this is fine"
this is fine
答案 1 :(得分:1)
throw
是undefined
的概括,而throwIO
是实际的IO
动作。一个关键的区别是,在考虑严格性时(即当您拥有undefined
(或throw
和seq
)时,许多法律并不完全适用。
> (throw Underflow :: IO ()) `seq` ()
*** Exception: arithmetic underflow
> (throw Underflow >>= pure) `seq` ()
()
因此违反法律m >>= pure = m
。 throwIO
没有这个问题,因此它是引发异常的更原则的方法。