首页 > 解决方案 > 如何减少返回带有短路行为的函数的序列?

问题描述

以下面的例子为例(改编自猫的 Either 文档)。

三个验证函数依次应用,每个都返回一个 Either。如果任何函数的应用失败,则返回 Left 值。

object Validators {
  def isBiggerThan5(i: Int): Either[Exception, Int] =
    if (i > 5) Either.right(i)
    else Either.left(new NumberFormatException(s"${i} is smaller than 5."))

  def isSmallerThan20(i: Int): Either[Exception, Int] =
    if (i < 20) Either.right(i)
    else Either.left(new NumberFormatException(s"${i} is bigger than 20."))

  def isEven(i: Int): Either[Exception, Int] =
    if (i % 2 == 0) Either.right(i)
    else Either.left(new NumberFormatException(s"${i} is not an even number."))
}
import Validators._

def magic(i: Int): Either[Exception, Int] =
  isBiggerThan5(i).flatMap(isSmallerThan20).flatMap(isEven)

现在想象三个验证函数作为参数传递:

type Ops = Int => Either[Exception, Int]

def magic(ops: Seq[Ops])(s: String): Either[Exception, String] =
  ??? // How to apply ops in sequence with short circuit behavior?

println(magic(Seq(isBiggerThan5, isSmallerThan20, isEven)))

我们如何评估Seq[Ops]一个接一个的短路行为?我玩过Seq.foldLeftorSeq.reduce但不太明白。

我对错误累积不感兴趣。它应该在第一个返回 Left 的验证器上失败。

标签: scalascala-cats

解决方案


foldLeftM应该管用。

import cats.syntax.all._
def verify(i: Int, ops: Vector[Ops]): Either[Exception, Int] =
  ops.foldLeftM(i)((i, o) => o(i))

推荐阅读