这是来自scalaz文档的代码,所以基本上,如果值是左值,它将把这个左值作为最终结果并停止评估其余的,这非常有用。
for {
e1 <- "event 1 ok".right
e2 <- "event 2 failed!".left[String]
e3 <- "event 3 failed!".left[String]
} yield (e1 |+| e2 |+| e3) // event 2 failed
但是,我有这个代码,我使用 reduceLeft 来附加值
object processor {
def evaluate(x: Int): \/[String, Int] = {
if (x <= 3) x.right[String] else ("some exception about " + x).left[Int]
}
}
val result = (1 to 6).map(processor.evaluate).reduceLeft(_ |+| _)
//\/-(-\/(some exception about 4some exception about 5some exception about 6))
累积了左边的值,这不是我想要的。我想reduceLeft引起的不同行为是“左”值已被评估,而操作(flatMap和map)则不会。
如何更改此代码以将左侧结果作为最终结果
答案 0 :(得分:2)
您可以使用遍历语法
val result = (1 to 6).toList.traverseU(processor.evaluate)
我将范围转换为List以获取范围
中的List类型答案 1 :(得分:1)
我认为可能会对以下代码中的内容产生一些疑惑
for {
e1 <- "event 1 ok".right
e2 <- "event 2 failed!".left[String]
e3 <- "event 3 failed!".left[String]
} yield (e1 |+| e2 |+| e3) // event 2 failed
在上面的代码中,for comprehension使用map和flatMap作为\/[+A, +B]
。由于\/[+A, +B]
的map / flatMap的实现,将永远不会评估yield语句定义的函数。在这种情况下,map / flatMap正在执行不同\/[String, _]
的合并。在|+|
中函数使用的yield
运算符在SemiGroup语法中定义,只是使用Semigroup[String]
将右侧的字符串组合成一个字符串。在上面的情况中,它也可以使用String.append
。我明白为什么人们可能希望在这里使用Semigroup[String]
来组合这些与简单String.append
相对立的原因,但重要的是,yield定义的函数使用的是Semigroup[String]
而不是Semigroup[A \/ B]
。 1}}。
在下面的案例中, 使用Semigroup[A \/ B]
将String \/ Int
个实例合并为一个String \/ Int
。 reduceLeft
(或foldLeft
如果你选择了那条路线)只是简单地将列表中每个元素连接到它传递的累积函数。
object processor {
def evaluate(x: Int): \/[String, Int] = {
if (x <= 3) x.right[String] else ("some exception about " + x).left[Int]
}
}
val result: String \/ Int = (1 to 6).map(processor.evaluate).reduceLeft(_ |+| _)
根据Semigroup[A \/ B]
的定义,我们可以看到它需要Semigroup[A]
和Semigroup[B]
。
如果您使用Monad[A \/ _]
或Applicative[A \/ _]
组合传递给A \/ B
的函数中的reduceLeft
,则不会合并A
。< / p>
以下使用Applicative[A \/ _]
val result: String \/ Int = (1 to 6).map(processor.evaluate).reduceLeft {
(xs, x) => (xs |@| x)(_ |+| _)
}
以下使用为A \/ B
定义的map / flatMap,与顶部的代码最相似。
val result: String \/ Int = (1 to 6).map(processor.evaluate).reduceLeft {
(xs, x) => for {
xsA <- xs
xA <- x
} yield xsA |+| xA
}
foldMapM可能会做你想要的,但是使用Foldable [List] .foldsRight,所以你的错误会与你使用foldLeft时的错误不同。不幸的是,需要一个丑陋的lambda,或者下面的类型别名。
type StringEither[B]=String \/ B
val result: String \/ Int = (1 to 6).toList.foldMapM[StringEither, Int](processor.evaluate)