在 yield 中嵌套 for comprehension

Nesting a for comprehension inside a yield

这段代码出现编译错误。我已将其剥离以尽可能简化它。我在这里使用猫 EitherT monad 转换器。


  def foo(
    id : String
  ): EitherT[Future, Err, Either[A, B]] =
    for {
      a <- f1(id)
    } yield {
      if (a > 2)
        Left(A("Got an a"))
      else {
        for {
          b <- f2() // THIS IS THE PROBLEM
        } yield (Right(B("Got a B"))
      }
    }

编译器抱怨 f2()。它有一个 return 类型的 EitherT[Future,Err,C]。我得到的编译器错误是:

[error]  found   : cats.data.EitherT[Future,Err,scala.util.Right[Nothing,B]]
[error]  required: Either[A,B]
[error]           b <- f2()

我不确定它为什么抱怨这个。我想做 "if" 检查作为对 f2() 调用的保护,但我不能,因为 EitherT 没有 withFilter 方法。有一个更好的方法吗?基本逻辑是,调用 f1()。如果 a > 2 的值不调用 f2 但如果不是则调用 f2.

尝试使用单个 flatMap 而不是像这样的嵌套 for-comprehensions

case class A(v: String)
case class B(v: String)
case class C(v: String)

def f1(id: String): EitherT[Future, Err, Long] = EitherT.rightT(42)
def f2(): EitherT[Future, Err, C] = EitherT.rightT(C("cc"))

def foo(id : String): EitherT[Future, Err, Either[A, B]] =
  f1(id).flatMap { a =>
    if (a > 2)
      EitherT.rightT(Left(A("Got an A")))
    else
      f2().map(b => Right(B("Got a B")))
  }

foo("123").value.andThen(v => println(v))

输出

Success(Right(Left(A(Got an A))))

但是我同意 Krzysztof 的建议,即 EitherT[Future, Err, Either[A, B]] 模型似乎有点不寻常。