2016-03-12 4 views
1

Иногда у Scala возникают проблемы с выбором типов. Цель здесь - понять, почему и попытаться помочь Scala сделать лучший вывод.Как помочь Scala в выводе типа?

Проблема лучше объяснить на простом примере:

trait A 
trait B 

class G[Ao <: A, Bo <: B](a: Ao, b: Bo) 

// This is my "complex" class with 3 type parameters 
class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: Bo, g: Go) 

val a = new A{} 
val b = new B{} 
val g = new G(a,b) 

Здесь тип ОО ниже является совершенно Inferred:

class OO extends X(a,b,g) // Type of X[A,B,G[A,B]] 

Однако, если мы изменим один из аргументов быть опцией (или любой коллекцией, которая есть), и мы предоставляем пустую коллекцию (или None), после чего вывод не работает.

case class X[Ao <: A, Bo <: B, Go <: G[Ao,Bo]](a: Ao, b: List[Bo], g: Go) 

class OO extends X(a,List(),g) 

<console>:XX: error: inferred type arguments [A,Nothing,G[A,B]] do not conform to class X's type parameter bounds [Ao <: A,Bo <: B,Go <: G[Ao,Bo]] 
     class OO extends X(a,List(),g) 
         ^
<console>:XX: error: type mismatch; 
found : A 
required: Ao 
     class OO extends X(a,List(),g) 
         ^
<console>:XX: error: type mismatch; 
found : G[A,B] 
required: Go 
     class OO extends X(a,List(),g) 

Это может быть исправлено путем явной передачи всех параметров OO, как это:

class OO extends X[A,B,G[A,B]](a,List(),g) 

Дело в том, G уже имеет свои виды, и из определения X, мы видим, что G принимает первые два параметра X, поэтому, если мы знаем G, у нас есть все необходимое, чтобы вывести параметры X. Могу ли я сделать что-то другое, чтобы помочь Scala с выводом? У меня есть класс, который имеет гораздо больше параметров, чем X, и теперь я всегда должен их явно определять. Я пытаюсь понять, есть ли что-то, что я могу сделать, чтобы помочь Scala успешно вывести типы.

ответ

3

Я думаю, вы могли бы использовать более kinded типов:

case class X[Ao <: A, Bo <: B, Go[GAo <: Ao, GBo <: Bo] <: G[GAo, GBo]](a: Ao, b: List[Bo], g: Go[Ao, Bo]) 
class OO extends X(a,List(),g) 

или, если ваши параметры типа ковариантны:

case class G[+Ao <: A, +Bo <: B](a: Ao, b: Bo) 
case class X[Ao <: A, Bo <: B, Go[_ <: Ao, _ <: Bo] <: G[Ao, Bo]](a: Ao, b: List[Bo], g: Go[Ao, Bo]) 

я знаю из опыта, что компилятор Scala не может выводить типы из параметры той же группы, когда они зависят друг от друга на «разных уровнях», как в этом примере. Более высокий тип типа позволяет мне явно объявлять границы типов и помогать компилятору выводить правильные типы.

+1

Это выглядит многообещающе! Позвольте мне проверить это, и я вернусь к вам. – marios

+0

Можете ли вы немного рассказать о своих рассуждениях? Что заставило вас думать о высших единомышленниках? – marios

+1

Я добавил (вроде) объяснение ответа. Я думаю, что кто-то более опытный с типами систем и функциональным программированием мог бы объяснить, почему он работает лучше меня. Я знаю только по опыту, что компилятор не может вывести параметры типа в этих случаях, и вам нужно «помочь», указав границы, как я. Извините, я не мог больше помочь :) –

Смежные вопросы