问题描述
我已经发布了很多关于 Scala 故障处理的问题,非常感谢大家的回答.
I have posted quite several questions about failure handling in Scala and I really thank you all for your answers.
我理解在处理任何和 Scalaz 或 a for comprehension 时我的选择,我还有另一个(最后一个?)问题:
I understand my options when dealing with Either and Scalaz or a for comprehension, and I have another (last?) question:
当操作处理外部非功能性世界(如数据库)时,如何执行快速失败的操作序列?
How to do a fail-fast sequence of operations when the operations are dealing with the outside non-functional world, like a DB?
我的意思是我有一个这样的方法:
I mean I have a method like that:
def insertItem(item: Item): Either[Error,Item]
感谢Either和这些答案,我知道如何使用Either做到这一点:链接方法调用与任一和Scala 中的方法参数验证,用于理解和 monad
Thanks to Either and these answers, I know how to do it with Either: Chaining method calls with Either andMethod parameters validation in Scala, with for comprehension and monads
但是我的 Item
案例类是不可变的,将它作为 Right
返回并没有什么意义,因为调用者已经拥有该值.
But my Item
case class is immutable and it doesn't really make sense to return it as a Right
since the caller already has the value.
因此我怎么能做同样的事情:
Thus how can I do the same kind of thing with:
def insertItem(item: Item): Option[Error]
在我的应用程序中,当创建一个用户时,我们也会为他创建一些项目.如果一个项目创建失败,那么整个过程应该停止.
In my application, when an user is created, we also create some items for him.If an item fails to create, then the whole process should stop.
当我在 a 中直接使用 Option[Error]
进行理解时,我认为我不会得到我期望的结果.
When I use directly Option[Error]
in a for comprehension, I don't think I'll get the result I expect.
我想这样做是有意义的:
I guess it makes sense to do something like that:
for {
_ <- insertItem(item1).toLeft("???").right
_ <- insertItem(item2).toLeft("???").right
_ <- insertItem(item3).toLeft("???").right
}
但是作为值???"我把我的权利从来没有用过,我想我错过了不涉及创建永远不会使用的权利的优雅解决方案.
But as the values "???" I put in my Right are never useful, I guess I'm missing the elegant solution which do not involve creating Rights that will never be used.
我想我正在寻找只有当结果为None
时才会继续进行理解的东西,这有点奇怪,因为我只想继续下一个操作,而不是做一个真正的map
操作.
I think I'm looking for something that will continue the for comprehension only when the result is None
, which is kind of weird because I just want to continue to the next operation, and not do a real map
operation.
顺便说一句,如果可能的话,我想要非 Scalaz 和 Scalaz 解决方案.我不确定 Scalaz 是否会处理这些事情,因为它似乎更专注于真正的函数式编程,并且可能不提供像我的用例那样的副作用行为的代码?
By the way, if possible, I would like both non-Scalaz and Scalaz solutions.I'm not sure Scalaz handle such things, because it seems more focused on real functional programming and perhaps do not provide code for side-effect behaviors like my use case?
推荐答案
在这种情况下(或至少我已经做到了,我并不为此感到内疚).假设我们有以下内容:
I don't see a principled reason not to use Either[Error, Unit]
in a case like this (or at least I've done it, and I don't feel guilty about it). Say we have the following:
def launch(thing: String): Either[String, Unit] = Either.cond(
thing.nonEmpty,
println("Launching the " + thing),
"Need something to launch!"
)
我们可以证明正确的投影单子是适当的懒惰:
We can show that the right projection monad is appropriately lazy:
scala> for {
| _ <- launch("flowers").right
| _ <- launch("").right
| r <- launch("MISSILES").right
| } yield r
Launching the flowers
res1: Either[String,Unit] = Left(Need something to launch!)
不按需要发射导弹.
值得注意的是,如果您使用 Option
而不是 Either
,您所描述的操作只是给定 的第一个"幺半群实例的总和Option
(其中加法运算只是orElse
).例如,我们可以使用 Scalaz 7 编写以下内容:
It's worth noting that if you use Option
instead of Either
, the operation you're describing is just the sum given the "First" monoid instance for Option
(where the addition operation is just orElse
). For example, we can write the following with Scalaz 7:
import scalaz._, Scalaz._
def fst[A](x: Option[A]): Option[A] @@ Tags.First = Tag(x)
def launch(thing: String): Option[String] = if (thing.isEmpty) Some(
"Need something to launch!"
) else {
println("Launching the " + thing)
None
}
现在:
scala> val r: Option[String] = fst(launch("flowers")) |+| fst(
| launch("")) |+| fst(launch("MISSILES"))
Launching the flowers
r: Option[String] = Some(Need something to launch!)
再一次,没有导弹.
这篇关于当返回类型为 Option[Error] 时处理快速失败失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!