Подтвердить что ты не робот

Почему Scala полностью не вводит параметры типа при вложенности параметров типа?

Рассмотрим следующий код Scala:

abstract class A
abstract class B[T <: A]
class ConcreteA extends A
class ConcreteB extends B[ConcreteA]

class Example[U <: B[T], T <: A]( resolver: U )
object Test {
    new Example( new ConcreteB )
}

Последняя строка new Example( new ConcreteB ) не скомпилируется со следующей ошибкой:

error: аргументы inferred type [ConcreteB, Nothing] не соответствуют классу. Ограничения параметра типа типа [U <: B [T], T <: A]

Но ConcreteB имеет все необходимые данные для разрешения как U, так и T. Что мне здесь не хватает?

4b9b3361

Ответ 1

Киптон вплотную приблизился к своему высокопоставленному решению. К сожалению, он споткнулся о том, что кажется ошибкой в ​​ Scala < 2.9.1.RC1. Следующее работает как ожидается с 2.9.1.RC1 и туловищем,

Welcome to Scala version 2.9.1.RC1 (Java HotSpot(TM) Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> abstract class A
defined class A

scala> abstract class B[T <: A]
defined class B

scala> class ConcreteA extends A
defined class ConcreteA

scala> class ConcreteB[T <: A] extends B[T]
defined class ConcreteB

scala> class Example[T <: A, U[X <: A] <: B[X]](resolver: U[T])
defined class Example

scala> new Example(new ConcreteB[ConcreteA])
res0: Example[ConcreteA,ConcreteB] = [email protected]

Ответ 2

(См. также два связанных вопроса: Scala не выводит правильные аргументы типа и Тип, посланный к Nothing в Scala)

Похоже на ограничение вывода типа Scala, которое намеренно не указано. В процессе работы вы можете получить вывод, сделав T членом типа B, а не параметром,

abstract class A
abstract class B { type T <: A }
class ConcreteA extends A
class ConcreteB extends B { type T = ConcreteA }
class Example[U <: B]( resolver: U )
object Test {
    new Example( new ConcreteB )
}

При использовании членов типа полезно знать, что они могут отображаться как параметры типа, используя уточнение, как в Miles Sabin: Почему эта циклическая ссылка с типом нелегальной?

В ответ Jean-Philippe Pellet на связанный вопрос, типу вывода помогли сделать параметр типа более высоким. Если вы вводите дополнительный параметр типа в ConcreteB, тогда может быть введен тип вывода,

abstract class A
abstract class B[T <: A]
class ConcreteA extends A
class ConcreteB[T <: A] extends B[T]
class Example[T <: A, U[T0 <: A] <: B[T0]]( resolver: U[T] )
object Test {
  new Example( new ConcreteB[ConcreteA] )
}

Scala 2.9 дает загадочное сообщение об ошибке ниже, но Майлз Сабин указывает, что это ошибка, которая будет исправлена ​​для 2.9.1

<console>:15: error: kinds of the type arguments (ConcreteA,ConcreteB[T0]) do not conform to the expected kinds of the type parameters (type T,type U) in class Example.
ConcreteB[T0] type parameters do not match type U expected parameters: class ConcreteB has one type parameter, but type U has one
         new Example( new ConcreteB[ConcreteA] )
             ^

Ответ 3

Я написал документ обходных методов вывода типа в GitHub для моего собственного обучения.

Несколько простых правил, которые я считаю полезными, следующие:

  • Параметры типа параметров типа не могут быть выведены: Scala вывод типа видит только типы, указанные в списке параметров (не путать с списком параметров типа).

  • Предыдущие параметры не используются для определения будущих параметров: Информация типа распространяется только через списки параметров, а не параметры.


Однако в этом конкретном примере члены типа - это путь вперед (спасибо @Kipton Barros!)