Почему scala не может определить тип для f-связанного полиморфизма?

Простой пример, иллюстрирующий проблему:

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 типа, почему компилятор не может вывести это без подсказок от меня?

1 ответ

Решение

Case case 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)
Другие вопросы по тегам