类型 L 在类型 A 中处于逆变位置 => Either[L, B]

Type L is in contravariant position in type A => Either[L, B]

我尝试为 Either

编写简单的 flatMap 实现
sealed trait Either[+L, +R] {
  def flatMap[B](f: R => Either[L, B]): Either[L, B] = this match {
    case Left(e) => Left(e)
    case Right(e) => f(e)
  }
}

final case class Right[+A, +B](right: B) extends Either[A, B]
final case class Left[+A, +B](left: A) extends Either[A, B]

并面临以下问题: 协变类型L在类型f中处于逆变位置:R => Either[L, B] of value f,但为什么会这样呢?当我们将变体类型作为函数的参数时,我认为我们的类型处于逆变位置,它与类型声明无关

您可以将 R => Either[L, B] 视为 "generalized value of type L" - 它与 L 并不完全相同,但给定 R 它可能 生产一个L。所以,你的 flatMap "consumes generalized values of type L"。同时,您的方差声明声称 Either[+L, +R]L 中是协变的,因此,Either[VerySpecial, R] 必须是 Either[RatherGeneral, R] 的特例。但这是不可能的,因为只能消耗 VerySpecial 值的 flatMap 会在 RatherGeneral 输入时阻塞。

  • Either[+L, +R]中,L处于协变位置(它 Ls,至少有时)
  • R => Either[L, B]中,L仍然处于协变位置(因为函数产生Either[L, B],而Either[L, B]又产生L,所以整个过程产生 Ls)
  • (R => Either[L, B]) => Either[L, B]中,第一个L出现在contra变体位置,因为参数部分是consumed 通过方法 flatMap.

这很容易用标准的下限类型技巧解决:

sealed trait Either[+L, +R] {
  def flatMap[B, M >: L](f: R => Either[M, B]): Either[M, B] = this match {
    case Left(e) => Left(e)
    case Right(e) => f(e)
  }
}

final case class Right[+A, +B](right: B) extends Either[A, B]
final case class Left[+A, +B](left: A) extends Either[A, B]