【问题标题】:Is Either the equivalent to checked exceptions?是否等同于检查的异常?
【发布时间】:2012-05-30 14:33:10
【问题描述】:

从 Scala 开始并阅读有关 Either 的信息,我自然会将新概念与我所知道的东西(在本例中来自 Java)进行比较。与检查异常的概念Either有什么不同吗?

在这两种情况下

  • 方法中明确注释了失败的可能性(throws 或返回Either
  • 程序员可以在错误发生时直接处理错误情况或将其向上移动(再次返回Either
  • 有一种方法可以通知调用者错误原因

我想有人在 Either 上使用 for-comprehensions 来编写代码,因为不会出现类似于检查异常的错误。

我想知道我是不是唯一一个看到差异有问题的初学者。

谢谢

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    Either 不仅可以用于异常。例如,如果您要让用户为您键入输入或指定包含该输入的文件,您可以将其表示为 Either[String, File]

    Either 经常用于异常处理。 Either 和检查异常之间的主要区别在于Either 的控制流始终是显式的。编译器真的不会让你忘记你正在处理一个Either;它不会在您不知情的情况下从多个地方收集Eithers,返回的所有内容都必须是Either,等等。因此,您使用Either,而不是在可能出现异常情况时,但作为控制程序执行的正常部分。此外,Either 不会捕获堆栈跟踪,这使其比典型异常更有效。

    另一个区别是异常可用于控制流。需要跳出三个嵌套循环?没问题——抛出异常(没有堆栈跟踪)并在外部捕获它。需要跳出五个嵌套的方法调用?没问题!要么不提供这样的东西。

    也就是说,正如您所指出的,它们有许多相似之处。您可以传回信息(尽管Either 使这变得微不足道,而受检异常使您可以编写自己的类来存储所需的任何额外信息);你可以传递Either 或者你可以把它折叠成别的东西,等等。

    因此,总而言之:虽然您可以使用Either 和检查异常来完成相同的事情,但它们在实践中却相对不同。特别是,Either 使得创建和传回不同的状态变得非常容易,而受检异常擅长绕过所有正常的控制流,希望返回到可以明智地处理异常情况的地方。

    【讨论】:

    • 谢谢。这很有趣,因为我看到的几乎所有示例都在谈论错误处理。不幸的是,我无法在教程中讨论您提到的其他案例。
    • 此外,如果你处理一个列表,比如一个带有一些验证功能的电子邮件列表并从这个函数中捕获一个异常,整个列表将失败(如果你放置了 catch i> 在循环之外的某个地方阻塞)。如果是 Either,您可以收集所有错误,而不仅仅是第一个错误。 控制流的异常不是反模式吗?
    • @om-nom-nom - 所以将 catch 块放在循环中(或 view-map-takeWhile 在 Eithers 上)。这不是根本区别。
    • 这是优点之一,我可以链接返回/接受一个 Either 的函数,但我不能用异常来做到这一点,因为它们会“破坏”链?
    • @ManuelSchmidt - 您可以与 Either 链接,但有例外。 Either 的工作量要少一些。
    【解决方案2】:

    是的,Either 是一种在语言中嵌入异常的方法;其中一组可能失败的操作可能会向某些非本地站点抛出错误值。

    除了 Rex 提到的实际问题之外,您还可以从 Either 的简单语义中获得一些额外的东西:

    • Either 形成一个单子;因此您可以对计算结果为Either 的表达式集使用一元操作。例如。无需测试结果即可进行短路评估
    • Either 在类型中——因此仅类型检查器就足以跟踪对值的错误处理

    一旦您能够返回错误消息(Left s) 或成功值Right v,您就可以将异常分层,就像Either 加上错误处理程序一样,就像for MonadError in Haskell 一样。

    【讨论】:

      【解决方案3】:

      就形成exclusive disjunction 的返回签名而言,两者都等同于已检查异常。结果可以是抛出的异常 X 或 A。但是,抛出异常并不等同于返回一个异常——第一个异常不是引用透明的。

      Scala 的 Either 不等效的地方(从 2.9 开始)是返回类型是正偏的,并且需要努力提取/解构异常, Either 是无偏的;您需要明确要求左值或右值。这是一个topic of some discussion,实际上有点痛苦——考虑以下三个对 Either 生成方法的调用

      for {
        a <- eitherA("input").right
        b <- eitherB(a).right
        c <- eitherC(b).right
      } yield c // Either[Exception, C]
      

      您需要手动穿过 RHS。这可能看起来不那么繁重,但实际上对于新手来说是一种痛苦并且有些令人惊讶。

      【讨论】:

      • 很好的评论,但是引用透明是什么意思?
      • 引用透明意味着我们可以用它的值替换表达式 - 抛出的异常是副作用,它不能变成一个值。 Left[SomeException] 的 Either 值不会被抛出,因此是引用透明的。可以在这里找到一个很好的解释:blog.higher-order.com/blog/2012/09/13/what-purity-is-and-isnt
      猜你喜欢
      • 2016-03-20
      • 2015-02-16
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2017-05-01
      • 2013-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多