为什么 Scala 无法对 f 绑定多态性进行类型推断?
Why scala fails type inference for f-bound polymorphism?
说明问题的简单示例:
trait WTF[W <: WTF[W]] {
def get : Int
}
trait Zero extends WTF[Zero] {
override def get : Int = 0
}
case object Zero extends Zero
final case class Box(inner : Int) extends WTF[Box] {
override def get : Int = inner
}
def printWTF[W <: WTF[W]](w : W) = println(w.get)
printWTF(Box(-1))
printWTF(Zero)
Box
可以,但是 Zero
会产生错误:
WTF.scala:22: error: inferred type arguments [Zero.type] do not conform to method printWTF's type parameter bounds [W <: WTF[W]]
printWTF(Zero)
^
WTF.scala:22: error: type mismatch;
found : Zero.type
required: W
printWTF(Zero)
^
two errors found
如果我手动注释类型,它会编译:
printWTF[Zero](Zero)
printWTF(Zero : Zero)
第一行按预期工作。我经常遇到无法从参数中推断出类型参数的情况。例如def test[A](x : Int) : Unit
。 A
类型在参数签名中没有出现,因此您应该手动指定它。
但后者对我来说很晦涩。我刚刚添加了始终为真的类型转换,编译器奇迹般地学会了如何推断方法类型参数。但是 Zero
总是 Zero
类型,为什么没有我的提示编译器不能推断它?
案例对象 Zero
的类型为 Zero.type
,并且是 WTF[Zero]
的子类型。因此,当您调用 printWTF(Zero)
时,编译器推断 W = Zero.type
但 Zero.type <: WTF[Zero.type]
为假,因此编译失败。
另一方面,这个更复杂的签名应该可以工作:
def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]) = println(w.get)
并作为这确实正确推断类型的证明:
scala> def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]): (V, W) = ???
printWTF: [W <: WTF[W], V <: W](w: V with WTF[W])(V, W)
scala> :type printWTF(Box(1))
(Box, Box)
scala> :type printWTF(Zero)
(Zero.type, Zero)
说明问题的简单示例:
trait WTF[W <: WTF[W]] {
def get : Int
}
trait Zero extends WTF[Zero] {
override def get : Int = 0
}
case object Zero extends Zero
final case class Box(inner : Int) extends WTF[Box] {
override def get : Int = inner
}
def printWTF[W <: WTF[W]](w : W) = println(w.get)
printWTF(Box(-1))
printWTF(Zero)
Box
可以,但是 Zero
会产生错误:
WTF.scala:22: error: inferred type arguments [Zero.type] do not conform to method printWTF's type parameter bounds [W <: WTF[W]]
printWTF(Zero)
^
WTF.scala:22: error: type mismatch;
found : Zero.type
required: W
printWTF(Zero)
^
two errors found
如果我手动注释类型,它会编译:
printWTF[Zero](Zero)
printWTF(Zero : Zero)
第一行按预期工作。我经常遇到无法从参数中推断出类型参数的情况。例如def test[A](x : Int) : Unit
。 A
类型在参数签名中没有出现,因此您应该手动指定它。
但后者对我来说很晦涩。我刚刚添加了始终为真的类型转换,编译器奇迹般地学会了如何推断方法类型参数。但是 Zero
总是 Zero
类型,为什么没有我的提示编译器不能推断它?
案例对象 Zero
的类型为 Zero.type
,并且是 WTF[Zero]
的子类型。因此,当您调用 printWTF(Zero)
时,编译器推断 W = Zero.type
但 Zero.type <: WTF[Zero.type]
为假,因此编译失败。
另一方面,这个更复杂的签名应该可以工作:
def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]) = println(w.get)
并作为这确实正确推断类型的证明:
scala> def printWTF[W <: WTF[W], V <: W](w: V with WTF[W]): (V, W) = ???
printWTF: [W <: WTF[W], V <: W](w: V with WTF[W])(V, W)
scala> :type printWTF(Box(1))
(Box, Box)
scala> :type printWTF(Zero)
(Zero.type, Zero)