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

时间:2018-08-27 13:23:24

标签: scala types variance contravariance

我试图为Ether编写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 =>值f的[L,B]都可以,为什么呢?我以为当我们将变量类型作为函数的参数时,我们的类型就处于反变的位置,与类型声明无关

1 个答案:

答案 0 :(得分:3)

您可以将R => Either[L, B]视为“类型为L的通用值”-它与L并不完全相同,但是给定R可能会产生一个L。因此,您的flatMap“使用类型L的广义值”。同时,您的差异声明声称Either[+L, +R]L是协变的,因此,Either[VerySpecial, R]必须是Either[RatherGeneral, R]的特例。但这是不可能的,因为仅消耗flatMap值的VerySpecial会阻塞RatherGeneral输入。

  • Either[+L, +R]中,L处于协变位置(至少在"produces" L s个位置中
  • R => Either[L, B]中,L仍处于协变位置(因为该函数产生Either[L, B],而Either[L, B]又产生L,因此整个事物产生L s)
  • (R => Either[L, B]) => Either[L, B]中,第一个L出现在 contra 变体位置,因为自变量部分被方法{{1}消耗了 }。

这可以通过标准的lower-type-bounds技巧轻松解决:

flatMap