函数的方差
Variance of function
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 处于反变量位置。
有人可以向我解释为什么会这样吗?感觉很迷茫。
我假设你真的想写:
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]
A
是 Sum
的参数,通常是协变位置。
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
处于协变位置。
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 处于反变量位置。
有人可以向我解释为什么会这样吗?感觉很迷茫。
我假设你真的想写:
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]
A
是 Sum
的参数,通常是协变位置。
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
处于协变位置。