Haskell库引发异常的背后的想法是什么 [英] What's the idea behind Haskell libraries throwing exceptions
问题描述
为什么图书馆(例如404
上的 wreq
)会抛出一个而不是将结果包装到Maybe
?
Why would a library (wreq
on a 404
for example) throw an exception instead of wrapping the result into something like Maybe
?
天真的,我认为Maybe
会更好(例如,如果我不处理所有情况,编译器会警告我).为什么我在这里错了?
Naively, I think Maybe
would be better (compiler warning me if I'm not handling all the cases for example). Why am I wrong here?
推荐答案
Haskellers竭力避免抛出来自 functions 的异常–函数仅应在真正例外的情况下抛出异常,即这种情况永远不会发生",例如用户传递了文档明确禁止的某些输入.如果纯函数定期抛出异常,那么这将是一个大问题,不仅因为类型没有说明应该准备捕获什么,而且不能也不能捕获纯函数中的异常,而仅仅是在调用该函数的IO
代码中.而且即使您原则上可以捕获异常,也可能很难预测在何处,因为惰性评估会延迟实际发生的时间.
Haskellers do strongly strive to avoid throwing exceptions from functions – a function should only throw an exception in truely exceptional cases, i.e. in "this should never happen" situations like the user passing some input that's explicitly forbidden by the documentation. If pure functions regularly threw exceptions, this would be a big problem not only because the type doesn't say what one should be prepared to catch, also one can't catch exceptions within a pure function but only in IO
code that calls the function. And even if you can in principle catch the exception, it may be hard to predict where it needs to be done because lazy evaluation can delay the point where it actually happens.
事实上,即使在 Wreq.get
,该函数不会引发任何异常.
Prelude Network.Wreq> get "htt:/p/this-isn't even valid URL syntax" `seq` "Ok"
"Ok"
执行时抛出的是IO
动作:
It is the IO
action that throws, when you execute it:
Prelude Network.Wreq> get "htt:/p/this-isn't even valid URL syntax" >> pure ()
*** Exception: InvalidUrlException "htt:/p/this-isn't%20even%20valid%20URL%20syntax" "Invalid scheme"
现在使用IO
动作,情况有所不同. IO
操作的结果包装在Maybe
中将导致与Java中类似的情况,在Java中,每个引用都可能为空.这不会告诉您任何信息,而且人们通常也不会想出处理此问题的明智方法.
Now with an IO
action, the situation is a bit different. Lots of IO
actions can have potentially very different errors in different situations that may be hard or impossible to predict, like a hard-drive crash. Catalogising all the possible errors in a suitable data type for each action would be a major undertaking, and it would be really quite cumbersome to handle every possible case or figure out which parts just to pass on. And simply wrapping the result of every single IO
action in Maybe
would just lead to a similar situation as in Java where every reference can possibly null. This doesn't tell you anything, and people often wouldn't come up with sensible ways of handling this either.
这几乎就是为什么首先发明例外的问题,它在程序语言中和在Haskell中一样适用(或更确切地说,它是程序cDSL,即IO
).而且由于与纯函数不同,IO
在控制流中确实具有明确定义的时间顺序,因此,如果需要捕获某些特殊异常,则也很清楚必须在哪里执行.
This is pretty much the problem why exceptions were invented in the first place, and it holds just as well for procedural languages as it holds for Haskell (or rather, it's procedural eDSL that is IO
). And because unlike pure functions, IO
does have a well-defined time-sequence in its control flow, it's also pretty clear where you must do it if you need to catch some particular exception.
这并不是说IO
动作返回Maybe
/Either
值(使可能的错误变得明确)永远是没有意义的,但这并不总是值得的.
That's not to say it never makes sense for an IO
action to return a Maybe
/ Either
value that makes the possible errors explicit, just this isn't always worthwhile.
这篇关于Haskell库引发异常的背后的想法是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!