gpt4 book ai didi

exception - Haskell 错误处理方法

转载 作者:行者123 更新时间:2023-12-03 07:17:39 27 4
gpt4 key购买 nike

这里没有争论在 Haskell 中有各种机制来处理错误并正确处理它们。错误 monad、Either、Maybe、异常等。

那么为什么在其他语言中编写易发生异常的代码比在 Haskell 中更直接呢?

假设我想编写一个命令行工具来处理在命令行上传递的文件。我想:

  • 验证是否提供了文件名
  • 验证文件可用且可读
  • 验证文件具有有效的标题
  • 创建输出文件夹并验证输出文件是否可写
  • 处理文件、解析错误、不变错误等错误
  • 输出文件、写入错误、磁盘已满等错误

  • 所以一个非常直接的文件处理工具。

    在 Haskell 中,我会将这段代码包装在某种 monad 组合中,使用 Maybe 和 Being 并根据需要翻译和传播错误。最后,这一切都进入了一个 IO monad,在那里我可以将状态输出给用户。

    在另一种语言中,我只是抛出一个异常并在适当的地方捕获。直截了当。我不会花太多时间在认知边缘试图解开我需要的机制组合。

    我只是在接近这个错误还是这种感觉有一些实质内容?

    编辑:好的,我收到反馈告诉我它只是感觉更难,但实际上并非如此。所以这是一个痛点。在 Haskell 中,我正在处理成堆的 monad,如果我必须处理错误,我会在这个 monad 堆栈中添加另一层。我不知道我不得不添加多少个提升和其他句法垃圾才能使代码编译但添加零语义含义。没有人觉得这增加了复杂性?

    最佳答案

    In Haskell, I'd be wrapping this code in some combination of monads, using Maybe's and Either's and translating and propagating errors as necessary. In the end, it all gets to an IO monad where I am able to output the status to the user.

    In another language, I simply throw an exception and catch in the appropriate place. Straightforward. I don't spend much time in cognitive limbo trying to unravel what combination of mechanisms I need.


    我不会说你一定是错误地接近它。相反,您的错误在于认为这两种情况不同;他们不是。
    “简单地抛出和捕获”相当于将与 Haskell 错误处理方法的某种组合完全相同的概念结构强加给整个程序。确切的组合取决于您与之比较的语言的错误处理系统,这说明了为什么 Haskell 看起来更复杂:它允许您根据需要混合和匹配错误处理结构,而不是给您一个隐含的、一个- 最适合的解决方案。
    所以,如果你需要一种特定的错误处理方式,你可以使用它;并且您只将它用于需要它的代码。不需要它的代码——由于既不生成也不处理相关类型的错误——被标记为这样,这意味着您可以使用该代码而不必担心会创建那种错误。

    关于语法笨拙的主题,这是一个尴尬的主题。理论上,它应该是无痛的,但是:
  • Haskell 是一种研究驱动的语言有一段时间了,在它的早期,很多东西还在不断变化,有用的习语还没有普及,所以漂浮的旧代码很可能是一个糟糕的榜样
  • 一些库在错误处理方式上并不灵活,要么是由于上述旧代码的僵化,要么只是缺乏润色
  • 我不知道关于如何最好地构建用于错误处理的新代码的任何指南,因此新手可以自行决定

  • 我猜你很可能以某种方式“做错了”,并且可以避免大部分语法困惑,但是期望你(或任何普通的 Haskell 程序员)自己找到最好的方法可能是不合理的.
    就 monad 变压器堆栈而言,我认为标准方法是 newtype应用程序的整个堆栈,为相关类型类派生或实现实例(例如, MonadError ),然后使用通常不需要的类型类的函数 lift ing。您为应用程序核心编写的 Monadic 函数都应该使用 newtype d 堆栈,因此也不需要提升。关于唯一无法避免的低语义意义的事情是 liftIO , 我认为。
    处理大量的变压器可能是一个真正令人头疼的问题,但只有当有很多不同变压器的嵌套层时(将 StateTErrorT 的交替层与 ContT 放在中间,然后尝试告诉我你的代码实际上会做什么)。但是,这很少是您真正想要的。

    编辑 :作为一个小附录,我想提请注意我在写一些评论时想到的更一般的观点。
    正如我所说和@sclv 很好地展示的那样,正确的错误处理真的很复杂。你所能做的就是改变复杂性,而不是消除它,因为无论你在执行多个可能独立产生错误的操作,并且你的程序需要以某种方式处理每一种可能的组合,即使这种“处理”只是简单地下降结束并死去。
    也就是说,Haskell 在某一方面确实与大多数语言存在本质上的不同:通常,错误处理既是明确的又是一流的,这意味着一切都是公开的,可以自由操作。另一方面是隐式错误处理的损失,这意味着即使您只想打印错误消息并死掉,您也必须明确地这样做。所以实际上在 Haskell 中进行错误处理更容易,因为它有一流的抽象,但忽略错误更难。然而,这种“全员弃船”错误非处理在任何现实世界的生产使用中几乎永远不会正确,这就是为什么看起来笨拙被搁置一旁的原因。
    所以,虽然当你需要明确地处理错误时,事情一开始会更复杂,但重要的是要记住 这就是全部 .一旦你学会了如何使用正确的错误处理抽象,复杂性就会达到一个稳定水平,并且不会随着程序的扩展而变得更加困难;你使用这些抽象的次数越多,它们就越自然。

    关于exception - Haskell 错误处理方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6537766/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com