Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 类型L在类型A中处于逆变位置=>;[L,B]_Scala_Types_Variance_Contravariance - Fatal编程技术网

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

Scala 类型L在类型A中处于逆变位置=>;[L,B],scala,types,variance,contravariance,Scala,Types,Variance,Contravariance,我试图为这两种方法编写简单的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,

我试图为这两种方法编写简单的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]之一,但为什么会这样?我认为当我们把变量类型作为函数的参数时,我们的类型处于反变量的位置,它与类型声明无关,你可以把
R=>或者[L,B]
看作是“类型的广义值
L
”——它与
L
不完全一样,但是给定一个
R
,它可能会产生一个
L
。因此,您的
flatMap
“使用
L
类型的广义值”。同时,您的方差声明声明
或者[+L,+R]
L
中是协变的,因此
或者[VerySpecial,R]
必须是
或者[RatherGeneral,R]
的特例。但这是不可能的,因为只能使用
VerySpecial
值的
flatMap
会被
RatherGeneral
输入阻塞

  • 中[+L,+R]
    L
    处于协变位置(至少有时是
    L
    s)
  • R=>or[L,B]
    中,
    L
    仍然处于协变位置(因为函数产生
    or[L,B]
    ,而
    or[L,B]
    反过来产生
    L
    s,所以整个过程产生
    L
    s)
  • (R=>or[L,B])=>or[L,B]
    中,第一个
    L
    以相反的位置出现,因为参数部分由方法
    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]

谢谢,很好的解释!但是为什么R类型在R=>或者[L,B]中没有突出显示,并且在逆变位置有一个错误(f消耗R,而R又被flatMap消耗)@nicksigevsky,因为
(R=>X=>Y
应该被认为是
R
类型的广义值
R
中是协变的(R=>X=>Y
@nicksigevsky假设你说“我需要一台打印机
P
”。然后我问你:你需要打印机做什么?您回答:“我有一个特殊的软件和一个PDF文件,它告诉我,给定一台打印机,
P
,我如何生成一个纸制品
a
”(也就是说,您有一个
P=>a
)。然后我对你说:“只要去一家影印店,它会拿走你的
P=>a
,如果你愿意的话,打印出一张完整的
列表[a]
”。也就是说,复印机的类型是
(P=>a)=>List[a]
。现在,请注意,您可以得到您想要的(打印工件
A
),因为复印机
(P=>A)=>List[A]
的行为类似于通用打印机
P