Haskell异常的含义

时间:2011-10-09 16:51:39

标签: haskell

Haskell中异常的含义是什么?我看到的唯一用法是在代码中放入undefinederror来阻止程序运行。否则,我认为将异常编程作为逻辑设计缺陷。但是Haskell有一个高级异常模块Control.Exception,由Prelude使用。我读到C ++中异常的原因是为了防止代码中出现很多“调用函数,然后检查状态”。但是这些东西可以在Haskell中抽象出来。我可以在Haskell中看到异常处理的另一个原因是使用FFI处理外部异常,但仅限于内部使用Haskell函数包装调用。

5 个答案:

答案 0 :(得分:27)

在我看来,例外意味着“你违反了职能合同”。我不是在谈论类型合同,我在谈论你通常在评论中找到的东西。

-- The reciprocal is not defined for the value 0
myRecip :: Fractional a => a -> a
myRecip x | x == 0    = throw DivideByZero
          | otherwise = 1 / x

当然,你总能以“安全”的方式提供这些功能:

safeRecip :: Fractional a => a -> Maybe a
safeRecip x | x == 0    = Nothing
            | otherwise = Just $ 1 / x

也许我们甚至应该抽象这种模式

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

您可以想象使用Either代替Maybe来报告失败的类似组合器。因为我们有能力用纯函数处理这些东西,为什么还要用不纯的异常模型呢?好吧,大多数Haskellers会告诉你坚持纯洁。但是黑暗的事实是,添加额外的层只是一种痛苦。你不能再写了

prop_recip x = x == (recip . recip) x

因为现在recip x的结果位于Maybe。您可以使用(a -> a)函数执行一些有用的操作。现在你必须考虑组成Maybes。当然,如果你对monad感到满意,这是微不足道的:

prop_recip 0 = (safeRecip >=> safeRecip) 0 == Nothing
prop_recip x = (safeRecip >=> safeRecip) x == Just x

但其中存在瑕疵。在涉及一元作文时,新手通常几乎一无所知。 Haskell委员会,就像#haskell irc频道上的许多人会很快告诉你的那样,为了迎合新手而做出了一些关于语言设计的相当不稳定的决定。我们希望能够说“你不需要知道monad就可以开始在Haskell中制作有用的东西”。我一般都同意这种观点。

<强> TL;博士 这个问题的几个快速答案:什么是例外?

  • 肮脏的黑客,所以我们不必使我们的功能完全安全
  • IO monad的“try / catch”控制流机制(IO是一个sin bin,为什么不在罪恶列表中抛出 try / catch?)

可能还有其他解释。

另见Haskell Report > Basic Input/Output > Exception Handling in the IO Monad

*我实际问过#haskell irc他们是否批准了这个声明。我得到的唯一回应是"wonky" :),所以很明显,没有人反对就证明了这一点。


[编辑]请注意,errorundefined是根据throw定义的:

error :: [Char] -> a
error s = throw (ErrorCall s)

undefined :: a
undefined =  error "Prelude.undefined"

答案 1 :(得分:5)

“错误”函数用于当函数接收到无效输入时,或者当内部发生应该永远不会发生的事情时(即错误)。简而言之,调用“error”代表一个错误 - 无论是在调用者还是被调用者。

对于不应该使用的值,“未定义”常量更多 - 通常是因为它们将被其他东西替换,或者因为它们是用于获取特定类型的幻像值。 (它实际上是作为对“错误”的调用实现的。)

那么为什么我们会Control.Exception拥有它的所有幻想呢?

基本上,“因为I / O操作可以抛出异常”。您可以愉快地通过TCP套接字与FTP服务器通话,突然连接断开。结果?您的程序抛出异常。或者你可能会用完RAM,或者磁盘可能会填满,或者其他什么。

请注意,几乎所有这些事情都不是你的错误。如果您可以预见某个特定的错误,您应该使用MaybeEither等内容以纯粹的方式处理它。 (例如,如果您要反转矩阵,那么矩阵可能是不可逆的,因此您最好返回Maybe Matrix作为结果。)对于您无法合理预期的事物(例如,其他一些程序刚刚删除了你正在尝试处理的文件),例外就是这样。

请注意,Control.Exception包含许多处理异常的内容,以及定义许多不同类型的内容。如果我调用的代码做了一些不正确的错误,那么我就不会关心;我仍然希望能够告诉客户我刚才正在谈论连接即将关闭,将描述记录到某个地方的日志文件,并做其他清理工作,而不是只是突然有我的程序,你知道,停止

答案 2 :(得分:5)

答案 3 :(得分:1)

例外是流量控制的合法形式。我不清楚为什么,当给定一个工具时,程序员坚持认为它“仅适用于”某些情况并排除其他可能的用途。

例如,如果您正在执行回溯计算,则可以使用异常来回溯。在Haskell中,使用list monad可能更常见,但异常是合法的方式。

答案 4 :(得分:0)

这个问题似乎在这里讨论了:http://haskell.org/haskellwiki/Exception 正如所指出的,我不知道这个问题是否实际上是可以回答的。