我在研究一些东西,尝试写一些有关存在性和方差的东西时,发现了这段有趣的代码。
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,如果这有什么变化))
_ <: Box[_ <: U]
应该匹配Box[U]
。我知道在>>=
中添加[U]
可以使其编译。 - HTNWBox[(_ >: T) => (_ <: Box[_ <: U])]
不匹配Box[U]
。 - CullenBox[(_ >: T) => (_ <: Box[_ <: U])]
是从哪里得到的吗? - HTNWf
类型(_ >: T) => (_ <: Box[_ <: U])
并将其转换为第一个泛型U
的>>=
。 - Cullen