Scala map&;平面图

Scala map&;平面图,scala,Scala,为什么映射函数是正确的而平面映射是错误的?唯一的区别是map有一个参数(f:a=>B),而flatmap有一个参数(f:a=>E,B中的任意一个),编译器认为E是一个逆变位置。既然f:A=>B也是一个参数,为什么编译器不抱怨A是一个相反的位置。map和flatmap都需要一个参数,我记得一个参数是一个逆变位置,我只是不明白为什么map工作而flatmap不工作 object test { import scala.{Option=>_,Either=>_,_} sealed

为什么映射函数是正确的而平面映射是错误的?唯一的区别是map有一个参数(f:a=>B),而flatmap有一个参数(f:a=>E,B中的任意一个),编译器认为E是一个逆变位置。既然f:A=>B也是一个参数,为什么编译器不抱怨A是一个相反的位置。map和flatmap都需要一个参数,我记得一个参数是一个逆变位置,我只是不明白为什么map工作而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]

}

A=>B
具有类型
函数[-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
的超类型

让我们用我们的函数=>尝试一下

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]