为什么编译器无法理解(_ >: T) => (_ <: V[_ <: U]) <: T => V[U]对于V[+_]?

4

我在研究一些东西,尝试写一些有关存在性和方差的东西时,发现了这段有趣的代码。

final case class Box[+T](val value: T) {
  def >>=[U](f: T => Box[U]) = f(value)
  def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f
}

以下代码无法编译:

Variance.scala:3: no type parameters for method >>=: (f: T => Box[U])Box[U] exist so that it can be applied to arguments (_$1 => _$2)
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T
 required: T => Box[?U]
  def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f
                                                                   ^
Variance.scala:3: type mismatch;
 found   : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T
 required: T => Box[U]
  def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f
                                                                       ^

我觉得很奇怪,因为(_ >: T) => (_ <: Box[_ <: U])不是T => Box[U]的子类型吗?因为Function1在第一个类型参数上是逆变的,所以它是T => (_ <: Box[_ <: U])的子类型。由于Function1在结果类型上是协变的,这是T => Box[_ <: U]的子类型,而Box在其参数上是协变的,整个东西不是T => Box[U]的子类型吗?

奇怪的是,将代码更改为

// This change is not required ;)
type Box[T] = `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[T]
final case class `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[+T](val value: T) {
  def >>=[U](f: T => Box[U]) = f(value)
  def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= (f: T => Box[U])
}

用类型说明符号指示编译器,f: T => Box[U]是可以编译的。由于这里没有隐式转换或变量声明,这样做应该没有什么区别吧?另一种让它能够编译的方法是:
def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this.>>=[U](f)

这让我相信问题不在于编译器难以理解(_ >: T) => (_ <: Box[_ <: U]) <: T => Box[U],而是它无法推断出>>=的类型参数。这似乎是错误消息所暗示的。
(使用Scala 2.12.1(带有sbt,如果这有什么变化))
1个回答

0
final case class Box[+T](val value: T) {
  def >>=[U](f: T => Box[U]) = f(value)
  def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f
}

flatMap 的返回类型是 Box[U],但要使用 this >>= f

因此,>>= 将自动更改为 f 类型 (_ >: T) => (_ <: Box[_ <: U])

因此,Box[(_ >: T) => (_ <: Box[_ <: U])]Box[U] 不匹配。

我认为你可以这样更改:
def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>=[U] f


我知道如何让代码工作;我想知道为什么需要修复它,因为 _ <: Box[_ <: U] 应该匹配 Box[U]。我知道在 >>= 中添加 [U] 可以使其编译。 - HTNW
原因是 Box[(_ >: T) => (_ <: Box[_ <: U])] 不匹配 Box[U] - Cullen
你能解释一下 Box[(_ >: T) => (_ <: Box[_ <: U])] 是从哪里得到的吗? - HTNW
">>=" 将自动获取参数 f 类型 (_ >: T) => (_ <: Box[_ <: U]) 并将其转换为第一个泛型 U>>= - Cullen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接