scala - L 型在 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]
视为“类型的广义值L
” - 它与 an 不完全相同L
,但给定 anR
它可能会产生一个L
. 因此,您的flatMap
“使用类型的广义值L
”。同时,您的方差声明声称在 中Either[+L, +R]
是协变的L
,因此, anEither[VerySpecial, R]
必须是 的特例Either[RatherGeneral, R]
。但这是不可能的,因为flatMap
只能消耗VerySpecial
值的 会阻塞RatherGeneral
输入。
- 在
Either[+L, +R]
,L
处于协变位置(它“产生”L
s,至少有时) - 在
R => Either[L, B]
,L
仍处于协变位置(因为函数产生Either[L, B]
,Either[L, B]
又产生L
s,所以整个事物产生L
s) - 在
(R => Either[L, B]) => Either[L, B]
中,第一个L
出现在contra变体位置,因为参数部分被方法消耗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]
推荐阅读
- java - Android:倒计时数据应用程序 - 如何更改硬编码的结束日期
- r - 在列之间操作并对每组 R 的值进行分类
- c# - 如何使用 c# 代码将 pdf 转换为图像?
- mysql - 如何在mysql中将列类型从文本更改为日期
- django - 如何在 wagtail 应用程序的 model.py 文件中返回当前页面 url
- python - 无法外连接两个数据框
- php - Laravel 5.2 版本 whereDate
- vb.net - 有没有办法在刷新 DataGridView 之前保存当前过滤,然后重新应用它?
- vba - 按字母顺序排序字符串,忽略括号
- azure - 用户分配的具有 azure 功能的托管标识 - 可能吗?