假设我有几个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]
。我该怎么做?
正如@TravisBrown告诉你的,因为理解并没有真正与错误累积混合在一起。事实上,当您不想要细粒度的错误控制时,通常会使用它们。
A for understanding将在发现第一个错误时“短路”自己,这几乎总是你想要的。
你做的不好的事情是使用< code>String来做异常的流控制。您应该始终使用< code >任一[Exception,Whatever]并通过< code > Scala . util . control . nostacktrace 和< code>scala.util.NonFatal微调日志记录。
有更好的选择,特别是:
scalaz.要么T
和scalaz。验证内尔
。
更新:(这是不完整的,我不知道你到底想要什么)。您有比匹配更好的选项,例如getOrElse
和recover
。
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) => //..
}
}
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
当然,这比必要的更冗长,并且会丢弃一些信息,并且在整个过程中使用验证
会更干净一些。
您想隔离测试*
方法并停止使用理解!
假设(不管出于什么原因)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中很好理解。 因此