为什么map funciton是正确的但是flatmap是错误的?唯一的区别是map具有(f:A => B)的参数,而flatmap具有参数(f:A => Either [E,B]),编译器抱怨E是逆变位置。由于f:A => B也是一个参数,为什么编译器不会抱怨A是一个逆变位置。地图,flatmap都需要一个参数,我记得一个参数是一个逆变位置,我只是不明白为什么地图有效而flatmap没有。
object test {
import scala.{Option=>_,Either=>_,_}
sealed trait Either[+E,+A]{
def map[B](f:A=>B):Either[E,B]= this match {
case Left(e)=>Left(e)
case Right(a)=>Right(f(a))
}
def flatMap[B](f: A=>Either[E,B]):Either[E,B] = this match {
case Left(e)=>Left(e)
case Right(a)=>f(a)
}
}
case class Right[+A](a:A) extends Either[Nothing,A]
case class Left[+E](e:E) extends Either[E,Nothing]
}
答案 0 :(得分:3)
A=>B
的类型为Function[-A,+B]
因此对于所有函数,参数都是逆变的,返回类型是协变的。所以我们可以做到以下几点:
N extends M
Y extends X
val a : M=>Y = ...
val b : N=>X = a
val x:X = b(new N)
但是当我们嵌套我们的函数时呢。
(A=>B)=>(C=>D)
现在A=>B
处于逆变位置,A
处于逆变位置内的控制位置。这是什么意思?在它意味着A
的预期之前,我们可以使用超级类型A
。在我们的示例中,我们有一个以N
为参数的函数,但我们给它一个函数M
,超N
类型。
让我们使用Function => Function
进行尝试def f(g: (M=>Y)=>(N=>X)) {...}
val x:(N=>X)=>(M=>Y) = ...
f(x) // this works
所以在逆变位置我们可以给出一个超类型。但在反对变异的位置,我们可以使用子类型。因此,反对方差等于协方差。
在您的示例map
中,您在反对变体位置使用协变类型A
,因此变为协变,因此编译正常。
在flatMap
中,您以相同的方式使用A
,但协变的B
用于逆变位置。这是错的。
要解决此问题:
def flatMap[F>:E,B](f:A=>Either[F,B]):Either[F,B]