所以我玩了一会儿,试图写出关于存在感和方差的东西,我偶然发现了这段有趣的代码。
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
在其参数中是协变的,因此整个事物不是{{1}的子类型}?
奇怪的是,将代码更改为
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,如果改变了什么))
答案 0 :(得分: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
retrun类型为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