合并两个 EitherT,return first if it succeeds else return second

Combining two EitherT, return first if it succeeds else return second

考虑以下片段:

def foo(x:String): EitherT[F, Throwable, String] = ???
def bar(x:String): EitherT[F, Throwable, String] = ???

我想要以下内容:

在某些输入 s 上,首先调用 foo(s) 如果它 "fails" return bar(s) 的输出,否则 return 输出的 foo(s) 而没有调用 bar(s)。我想出了以下内容。

def foobar(s:String) = {
  val f = foo(s)
  // if f is successful return f else return bar(s)
  f.biflatMap(_ => bar(s), _ => f)
}

有没有更好的方法来做我想做的事?

是的,recoverWith:

foo(s).recoverWith { _ =>
 bar(s)
}

许多其他错误处理 monad 有类似的约定:.recover 接受错误类型到成功类型,.recoverWith 接受错误类型到整个 monad-类型。有时它们分别被命名为 handlehandleWith。没有With的方法总是进行纯值计算,而有With的方法总是进行monad/wrapper类型的计算。

下面是一些实现

  import cats.implicits._
  import import cats.data.EitherT


  foo("").biflatMap(
    err => bar(""),
    str => EitherT.fromEither[F](str.asRight[Throwable])
  )

  foo("").biflatMap(
    err => bar(""),
    str => EitherT.liftF(str.pure[F])
  )

  foo("").leftFlatMap(
    err => bar("")
  )

  foo("").recoverWith(err => bar(""))

  for {
    err <- foo("")
    x <- bar("")
  } yield x

希望对您有所帮助