scala - 使用EitherT来评估使用共享错误类型继承的操作结果?

标签 scala scala-cats for-comprehension

我有一个用于剥香蕉的错误类型层次结构:

sealed trait PeelBananaError
object PeelBananaError {
  case object TooRipe extends PeelBananaError
  case object NotRipeEnough extends PeelBananaError
}
我在 EitherT 中有一些结果我们知道只能以以下两种方式之一失败:
val peelBrownBananaResult: EitherT[Future, TooRipe, String] = ...
val peelGreenBananaResult: EitherT[Future, NotRipeEnough, String] = ...
现在我需要收集 String右侧的结果并将它们组合起来以获得最终结果:
val combinedResult: EitherT[Future, PeelBananaError, String] = for {
  first <- peelBrownBananaResult
  second <- peelGreenBananaResult
} yield (first + second)
但是尝试这个会给我一个编译错误:
cmd15.sc:2: inferred type arguments [PeelBananaError.NotRipeEnough.type,String] do not conform to method flatMap's type parameter bounds [AA >: PeelBananaError.TooRipe.type,D]
  first <- peelBrownBananaResult
           ^
cmd15.sc:2: type mismatch;
 found   : String => cats.data.EitherT[scala.concurrent.Future,PeelBananaError.NotRipeEnough.type,String]
 required: String => cats.data.EitherT[scala.concurrent.Future,AA,D]
  first <- peelBrownBananaResult
        ^
Compilation Failed
似乎编译器无法推断 Left类型在 PeelBananaError 中共享公共(public)继承所以 for comprension 无法编译。这里有什么解决方法吗?我可以给编译器一些提示,以便我可以运行它来理解?
我尝试了以下方法,但使用 .asInstanceOf看起来很hacky,结果代码看起来很丑,这真的是唯一的解决方案吗?
val combinedResult: EitherT[Future, PeelBananaError, String] = for {
  first <- peelBrownBananaResult.asInstanceOf[EitherT[Future,PeelBananaError,String]]
  second <- peelGreenBananaResult.asInstanceOf[EitherT[Future,PeelBananaError,String]]
} yield (first + second)

最佳答案

EitherT monad 转换器在 A 中不是协变的或 B类型参数

case class EitherT[F[_], A, B]
不像 EitherA 中是协变的和 B
sealed abstract class Either[+A, +B]
这就是为什么 Either对父类(super class)型进行类型检查
Either.left(TooRipe): Either[PeelBananaError, String] // ok
但是 EitherT才不是
EitherT.left(Future(TooRipe)): EitherT[Future, PeelBananaError, String] // error
但是我们可以安全地widen单子(monad)变压器
for {
  first <- peelBrownBananaResult.leftWiden[PeelBananaError]
  second <- peelGreenBananaResult.leftWiden[PeelBananaError]
} yield (first + second)
// : EitherT[Future, PeelBananaError, String] = ...
不像不安全的扩大asInstanceOf
type T = Either[TooRipe.type, String]
val a = Either.left[PeelBananaError, String](new PeelBananaError {})
val b: Either[TooRipe.type, String] = a.asInstanceOf[T] // run-time error
val c: Either[TooRipe.type, String] = a.widen[T]        // compile-time error

关于scala - 使用EitherT来评估使用共享错误类型继承的操作结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67642347/

相关文章:

scala - 协议(protocol)切换是否成功

scala - Monad 与 Future 的应用仿函数

scala - 在 IntelliJ 中使用猫库时的错误错误

macros - 减少 "for"理解重复

scala - Scala中的方法参数验证,用于理解和单子(monad)

scala - 在 for 理解中将选项与列表组合会导致类型不匹配,具体取决于顺序

scala - 如何从 Scala 方法创建 UDF(计算 md5)?

scala - 在 scala 中,为什么 list.flatMap(List) 不起作用?

scala - 如何用Scala中另一个Seq的值替换一个Seq中的值?

Scala Cat 使用 Ior 累积错误和成功