地图的不同逆变要求& flatmap

时间:2014-05-01 13:49:53

标签: scala

为什么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]

}

1 个答案:

答案 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]