Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell例外的含义_Haskell - Fatal编程技术网

Haskell例外的含义

Haskell例外的含义,haskell,Haskell,Haskell中例外的含义是什么?我看到的唯一用法是在代码中输入undefined或error,以停止程序运行。否则,我认为有例外的编程是一个逻辑设计缺陷。但是Haskell有一个高级异常模块Control.exception,由Prelude使用。我读到C++中的异常原因是为了防止大量的“调用函数,然后检查状态”——代码中的行。但这些东西可以在哈斯克尔中抽象出来。在Haskell中处理异常的另一个原因是FFI,它可以处理外部异常,但只能用于包装调用的Haskell函数的内部使用。在我看来,异常

Haskell中例外的含义是什么?我看到的唯一用法是在代码中输入
undefined
error
,以停止程序运行。否则,我认为有例外的编程是一个逻辑设计缺陷。但是Haskell有一个高级异常模块
Control.exception
,由
Prelude
使用。我读到C++中的异常原因是为了防止大量的“调用函数,然后检查状态”——代码中的行。但这些东西可以在哈斯克尔中抽象出来。在Haskell中处理异常的另一个原因是FFI,它可以处理外部异常,但只能用于包装调用的Haskell函数的内部使用。

在我看来,异常意味着“你破坏了函数的契约”。我不是在谈论类型合同,我是在谈论你通常在评论中找到的东西

-- The reciprocal is not defined for the value 0
myRecip :: Fractional a => a -> a
myRecip x | x == 0    = throw DivideByZero
          | otherwise = 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
您可以想象类似的组合器使用
而不是
来报告失败。既然我们有能力用纯函数来处理这些事情,为什么还要用不纯异常模型呢?大多数哈斯凯尔人会告诉你要保持纯洁。但黑暗的事实是,增加额外的一层只是一种痛苦。你不能再写了

prop_recip x = x == (recip . recip) x
因为现在,
recipx
的结果在a
中,可能是
。你可以用
(a->a)
函数做一些有用的事情,而这些事情你已经做不到了。现在,你必须考虑创作“也许”。当然,如果您对单子感到满意,这是微不足道的:

prop_recip 0 = (safeRecip >=> safeRecip) 0 == Nothing
prop_recip x = (safeRecip >=> safeRecip) x == Just x
但问题就在这里。新手对一元合成几乎一无所知。哈斯凯尔委员会,正如许多哈斯凯尔irc频道的人会很快告诉你的*,已经做出了一些关于语言设计的不可靠决定,以迎合新手。我们希望能够说“你不需要了解单子就可以开始在Haskell中制作有用的东西”。我大体上同意这种看法

tl;dr 对这个问题的一些快速回答:什么是例外

  • 一个肮脏的黑客,所以我们不必使我们的功能完全安全
  • IO monad的“try/catch”控制流机制(IO是一个sin容器,为什么不将try/catch也放在sin列表中?)
可能还有其他解释

另见

*我在haskell irc上问过他们是否同意这一声明。我得到的唯一回应是
“摇摇晃晃的”:
,因此,毫无异议的事实显然证明了这一点


[编辑]注意,
错误
未定义
是根据
抛出
定义的:

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

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

异常是流控制的一种合法形式。我不清楚,为什么当给了一个工具时,程序员坚持说它“只用于”某些情况,并排除了其他可能的用途

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

当函数接收到无效输入时,或当内部发生了本应永远不会发生的事情(即错误)时,“error”函数适用。简言之,调用“error”表示一个bug-在调用者或被调用者中

“undefined”常量更适用于不应该使用的值-通常是因为它们将被其他内容替换,或者是因为它们是用于获取特定类型的虚拟值。(它实际上是作为对“error”的调用实现的。)

那么,为什么我们有
控制。异常
和它所有的幻想呢

基本上,“因为I/O操作可以引发异常”。您可能正在通过TCP套接字与FTP服务器愉快地交谈,突然连接中断。结果如何?你的程序抛出一个异常。或者您可能会耗尽RAM,或者磁盘可能已满,或者诸如此类

请注意,几乎所有这些都不是你的错。如果你能预见到某件事情会出差错,你应该使用像
Maybe
这两种方法中的任何一种来处理它。(例如,如果你要反转一个矩阵,那么,这个矩阵可能是不可逆的,所以你最好返回一个
可能是矩阵
)作为结果。)对于你无法合理预期的事情(例如,某个其他程序刚刚删除了你正试图处理的文件),例外是一种方式


请注意,
Control.Exception
包含大量处理异常的内容,以及定义大量不同类型的内容。我不在乎我调用的代码是否做了不正确的事情,因此是一个bug;我仍然希望能够告诉我刚刚与之交谈的客户端,连接即将关闭,将描述记录到某个日志文件中,并执行其他清理工作,而不是让我的程序突然停止。

这里似乎讨论了这个问题:
我不知道这个问题是否真的可以回答,正如我所指出的。

有各种各样的理由可以让你得到一个例外。在一个无异常的系统中,当内存耗尽时会发生什么?操作系统发送信号?你除以零?你计算一个部分函数。。。并发现它是局部的!在我所知道的任何语言中,例外都不是一个很好的部分,但为了应对现实世界,它们是一个必要的部分。有没有真正的方法来回答这个问题,还是仅仅是一种咆哮?如果它只是一个咆哮,也许一篇博客文章将是一个更合适的媒介。是的,对于这样的事情,应该有可能停止程序,所以我们有“未定义”和“错误”,正如我所说的。被零除和计算“超出其范围”的函数是逻辑设计缺陷。但我看不出除了
error :: [Char] -> a
error s = throw (ErrorCall s)

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