当前位置: 首页 > 知识库问答 >
问题:

如何积累错误?

叶鹭洋
2023-03-14

假设我有几个case类和函数来测试它们:

case class PersonName(...)
case class Address(...)
case class Phone(...)

def testPersonName(pn: PersonName): Either[String, PersonName] = ...
def testAddress(a: Address): Either[String, Address] = ...
def testPhone(p: Phone): Either[String, Phone] = ...

现在我定义了一个新的case类< code>Person和一个测试函数,它很快就会失败。

case class Person(name: PersonName, address: Address, phone: Phone)

def testPerson(person: Person): Either[String, Person] = for {
  pn <- testPersonName(person.name).right
  a <- testAddress(person.address).right
  p <- testPhone(person.phone).right
} yield person;

现在,我希望函数testPerson累积错误,而不是快速失败。

我希望 testPerson 始终执行所有这些 test* 函数并返回 Either[List[String], Person]。我该怎么做?

共有3个答案

屠锦
2023-03-14

正如@TravisBrown告诉你的,因为理解并没有真正与错误累积混合在一起。事实上,当您不想要细粒度的错误控制时,通常会使用它们。

A for understanding将在发现第一个错误时“短路”自己,这几乎总是你想要的。

你做的不好的事情是使用< code>String来做异常的流控制。您应该始终使用< code >任一[Exception,Whatever]并通过< code > Scala . util . control . nostacktrace 和< code>scala.util.NonFatal微调日志记录。

有更好的选择,特别是:

scalaz.要么Tscalaz。验证内尔

更新:(这是不完整的,我不知道你到底想要什么)。您有比匹配更好的选项,例如getOrElserecover

def testPerson(person: Person): Person = {
  val attempt = Try {
    val pn = testPersonName(person.name)
    val a = testAddress(person.address)
    testPhone(person.phone)
  }
  attempt match {
    case Success(person) => //..
    case Failure(exception) => //..
  }
}
归鹤龄
2023-03-14

Scala的<code>for</code>理解(它是对<code>、flatMap</code>和<code<map>调用的组合)旨在允许您对一元计算进行排序,这样您就可以在后续步骤中访问早期计算的结果。考虑以下因素:

def parseInt(s: String) = try Right(s.toInt) catch {
  case _: Throwable => Left("Not an integer!")
}

def checkNonzero(i: Int) = if (i == 0) Left("Zero!") else Right(i)

def inverse(s: String): Either[String, Double] = for {
  i <- parseInt(s).right
  v <- checkNonzero(i).right
} yield 1.0 / v

这不会累积误差,事实上也没有合理的方法可以累积误差。假设我们调用< code>inverse("foo")。那么< code>parseInt显然会失败,这意味着我们无法为< code>i赋值,这意味着我们无法继续执行序列中的< code > check非零(i)步骤。

在您的情况下,您的计算没有这种依赖性,但您使用的抽象(一元排序)不知道这一点。您需要的是一个类似于<code>的类型,它不是一元的,但具有应用性。有关差异的详细信息,请参见我的回答。

例如,您可以使用Scalaz的验证编写以下内容,而无需更改任何单独的验证方法:

import scalaz._, syntax.apply._, syntax.std.either._

def testPerson(person: Person): Either[List[String], Person] = (
  testPersonName(person.name).validation.toValidationNel |@|
  testAddress(person.address).validation.toValidationNel |@|
  testPhone(person.phone).validation.toValidationNel
)(Person).leftMap(_.list).toEither

当然,这比必要的更冗长,并且会丢弃一些信息,并且在整个过程中使用验证会更干净一些。

张翰海
2023-03-14

您想隔离测试*方法并停止使用理解!

假设(不管出于什么原因)scalaz不适合你...这可以在不添加依赖性的情况下完成。

与许多scalaz示例不同,这是一个库不会比“常规”scala减少太多详细信息的示例:

def testPerson(person: Person): Either[List[String], Person] = {
  val name  = testPersonName(person.name)
  val addr  = testAddress(person.address)
  val phone = testPhone(person.phone)

  val errors = List(name, addr, phone) collect { case Left(err) => err }

  if(errors.isEmpty) Right(person) else Left(errors)      
}
 类似资料:
  • 我想知道为什么需要(又名reduce)第3个参数。对于那些不知道是什么的人,它的用法如下: 调用等同于: 还有可选第4个参数,它允许用任何其他操作替换加法。 我听说的一个基本原理是,如果你不需要加起来,而是乘一个向量的元素,我们需要其他的(非零)初始值: 但是为什么不像Python那样-为设置初始值,并使用从开始的范围。类似这样的事情: 这对任何行动都管用。为什么需要第三个参数?

  • 问题内容: 如果我使用这样的1或NaN命名: 我想计算该系列的总和,但应在NaN的位置将其重置(设置为零),如下所示: 理想情况下,我希望有一个矢量化解决方案! 我曾经在Matlab上看到过类似的问题: 在NaN上重置Matlabcumsum吗? 但我不知道如何翻译这行 问题答案: Matlab代码的简单Numpy翻译是这样的: 执行此代码将返回结果。此解决方案仅会与原始解决方案一样有效,但是如果

  • 动态添加对象的属性 Vue中,动态新增对象的属性时,不能直接添加。正确的做法是:Vue.set(obj,key,value)。参考链接:# 判断一个checkbox是否被选中 <!-- v-model里的内容是变量,变量里的值可能是 true 后者 false --> <input type="checkbox" v-model="isSelected"> <!-- 选中时,值为 true。未选

  • 问题内容: 我已经实现了一定数量的所有素数的列表。我试图做的事情很难解释,所以我只用一些硬代码展示一下: 所以从本质上讲,我试图从上一个列表中按顺序取出一个元素,然后按指数倍增,然后将其追加到其他列表中。 我意识到我可以做到这一点,这可能会更容易: 我需要一些想法才能在某种程度上做到这一点。 问题答案: 您需要 累积产品 清单。这是一个简单的食谱: 另一种方法,使用itertools: 或者,也许

  • 此问题看起来类似:SocketException:打开的文件太多 至于我的用例,我从一个网站接收订单,并将它们处理到ERP中,然后将状态传回网站和其他系统。将消息发送回网站API有点慢,在事件发生时,可能有700条消息排队。 网站使用AMQP,我的消息路由使用JMS。 这是我的broker.xml 这就是那个我认为给我带来麻烦的客户。

  • 我开始使用 Scalaz 7 验证和/或析取来处理可能失败的操作列表并管理其结果。 这种用例有两个很好的记录案例: 1/你想检查某件事情的条件列表,并累积每个错误(如果有的话)。在这里,你总是走到列表的末尾,如果有任何错误,你将失败作为全局结果。这是一个应用仿函数在起作用。 2/ 您希望执行几个可能失败的步骤,并在第一个步骤失败时停止。在这里,我们有一个monad,它在Scala中很好理解。 因此