Haskell中异常的含义是什么?我看到的唯一用法是放入undefined或error放入我的代码中以阻止程序运行.否则,我认为将异常编程作为逻辑设计缺陷.但是Haskell有一个高级异常模块Control.Exception,它被使用Prelude.我读到C++中异常的原因是为了防止代码中出现很多"调用函数,然后检查状态".但是这些东西可以在Haskell中抽象出来.我可以在Haskell中看到异常处理的另一个原因是使用FFI处理外部异常,但仅限于内部用于包装调用的Haskell函数.
Dan*_*ton 27
在我看来,例外意味着"你违反了职能合同".我不是在谈论类型合同,我在谈论你通常在评论中找到的东西.
-- The reciprocal is not defined for the value 0
myRecip :: Fractional a => a -> a
myRecip x | x == 0 = throw DivideByZero
| otherwise = 1 / x
Run Code Online (Sandbox Code Playgroud)
当然,你总能以"安全"的方式提供这些功能:
safeRecip :: Fractional a => a -> Maybe a
safeRecip x | x == 0 = Nothing
| otherwise = Just $ 1 / x
Run Code Online (Sandbox Code Playgroud)
也许我们甚至应该抽象出这种模式
restrictInput :: (a -> Bool) -> (a -> b) -> (a -> Maybe b)
restrictInput pred f x = if pred x then Just (f x) else Nothing
safeRecip' = restrictInput (/= 0) myRecip
Run Code Online (Sandbox Code Playgroud)
您可以想象使用类似的组合器来Either代替Maybe报告故障.因为我们有能力用纯函数处理这些东西,为什么还要用不纯的异常模型呢?好吧,大多数Haskellers会告诉你坚持纯洁.但是黑暗的事实是,添加额外的层只是一种痛苦.你不能再写了
prop_recip x = x == (recip . recip) x
Run Code Online (Sandbox Code Playgroud)
因为现在结果recip x是在Maybe.对于您不能再执行的(a -> a)功能,您可以执行一些有用的操作.现在你必须考虑组成Maybes.当然,如果你对monad感到满意,这是微不足道的:
prop_recip 0 = (safeRecip >=> safeRecip) 0 == Nothing
prop_recip x = (safeRecip >=> safeRecip) x == Just x
Run Code Online (Sandbox Code Playgroud)
但其中存在着摩擦.在涉及一元作文时,新手通常几乎一无所知.Haskell委员会,就像#haskell irc频道上的许多人会很快告诉你的那样,为了迎合新手而做出了一些关于语言设计的相当不稳定的决定.我们希望能够说"你不需要知道monad就可以开始在Haskell中制作有用的东西".我普遍同意这种观点.
tl; dr 这个问题的几个快速答案:什么是例外?
可能还有其他解释.
另请参阅IO Monad中的Haskell报告>基本输入/输出>异常处理
*我实际问过#haskell irc他们是否批准了这个声明.我得到的唯一回应"wonky" :)是,如果没有异议,这显然是正确的.
[编辑]请注意error并按undefined以下方式定义throw:
error :: [Char] -> a
error s = throw (ErrorCall s)
undefined :: a
undefined = error "Prelude.undefined"
Run Code Online (Sandbox Code Playgroud)
"错误"函数用于函数接收无效输入时,或者当内部发生应该永远不会发生的事情时(即错误).简而言之,调用"error"代表一个错误 - 无论是在调用者还是被调用者中.
对于不应该使用的值,"未定义"常量更多 - 通常是因为它们将被其他东西替换,或者因为它们是用于获取特定类型的幻像值.(它实际上是作为对"错误"的调用实现的.)
那么为什么我们拥有Control.Exception它的所有功能呢?
基本上,"因为I/O操作可以抛出异常".您可以愉快地通过TCP套接字与FTP服务器通话,突然连接断开.结果?您的程序抛出异常.或者你可能用完RAM,或者磁盘可能会填满,或者其他什么.
请注意,几乎所有这些都不是你的错.如果你能预料到某个特定的事情会出错,你应该使用类似的东西Maybe并Either以纯粹的方式处理它.(例如,如果你要反转一个矩阵,那么矩阵可能是不可逆的,所以你最好返回一个Maybe Matrix结果.)对于你无法合理预期的事情(例如,其他一些程序)刚刚删除了你正在尝试处理的文件),例外就是这样.
请注意,它Control.Exception包含许多用于处理异常的内容,以及仅定义许多不同类型的内容.我不在乎我调用的代码是否做了不正确的事情,因此是一个错误; 我仍然希望能够告诉客户我刚才正在谈论连接即将关闭,将描述记录到某个地方的日志文件,并做其他清理工作,而不是只是突然有我的程序,你知道,停下来.