功能的差异

时间:2016-12-25 14:54:49

标签: scala covariance

sealed trait Sum[+A, +B] {
  def flatMap[A, C](f: B => Sum[A, C]): Sum[A, C] =
    this match {
      case Failure(v) => Failure(v)
      case Success(v) => f(v)
    }
} 

是不是说功能参数是反变量的,结果是共变的?为什么编译器说A处于反变量位置?我期待编译器抱怨B处于反变体位置。

有人可以向我解释为什么会这样吗?感到困惑。

1 个答案:

答案 0 :(得分:4)

我认为你真的打算写:

sealed trait Sum[+A, +B] {
  def flatMap[C](f: B => Sum[A, C]): Sum[A, C] = // No shadowing of A
    this match {
      case Failure(v) => Failure(v)
      case Success(v) => f(v)
    }
}

再次查看flatMap

def flatMap[C](f: B => Sum[A, C]): Sum[A, C]

让我们重写一下:

def flatMap[C]: (B => Sum[A, C]) => Sum[A, C]

让我们从内到外构建类型。

Sum[A, C]

ASum的参数,通常是协变位置。

B => Sum[A, C]

Sum[A, C]是函数的结果,通常是协变位置。这两个结合起来,你仍然处于协变位置A

(B => Sum[A, C]) => Sum[A, C]

B => Sum[A, C]也是函数的参数,因此整个事物处于逆变位置。由于A之前处于协变位置,因此方差合并且A现在处于逆变位置。

查看B

B => Sum[A, C]

函数的参数,通常是逆变位置。

(B => Sum[A, C]) => Sum[B, C]

整个函数也是另一个函数的参数,因此抵消了逆变,B处于协变位置。

你也可以画出一个漂亮的比喻。查看协变和逆变类型参数的定义:

trait Co[+A]; trait Con[-A]

他们看起来像正面和负面的数字,只是一点点。现在,请记住你在小学中学到的乘法和符号的规则:

  • (+) * (+) = (+)
  • (+) * (-) = (-)
  • (-) * (+) = (-)
  • (-) * (-) = (+)

这类似于(如果你斜视一下)

  • Co[Co[A]] => A处于协变位置
  • Co[Con[A]] => A处于逆境中
  • Con[Co[A]] => A处于逆境中
  • Con[Con[A]] => A处于协变状态。