2015-07-23 2 views
2

Рассмотрим следующие классы:Тип вывода и тип оценки в Scala

class Type { def +(other:Type):Type = this} 
class SubType extends Type 

Теперь я хочу, чтобы создать объект-оболочку, которая принимает бинарную функцию, работающего на Type или его производных типов, давайте начнем с:

case class Fct(f:(Type,Type) => Type) 

Я могу создать экземпляр класса Fct с помощью _+_ применить метод, но я не могу передать функцию, используя Subtype класс, который, как ожидается:

val f1 = Fct(_+_) // OK 
val f2 = Fct((x:SubType,y:Type) => y) // error: found: (SubType, Type) => Type, required: (Type, Type) => Type 

Теперь мы можем определить Fct с помощью дженериков и оценки типа принимать подтипы:

case class Fct[T <: Type, U <: Type, V <: Type](f:(T,U) => V) 

Теперь f2 работает так, как ожидалось, но f1 не действует больше, и я не понимаю, почему:

val f1 = Fct(_+_) // error: missing parameter type 
val f2 = Fct((x:SubType,y:Type) => y) // OK 

есть ли синтаксис, который будет принимать как f1 и f2?

Редактировать

(ответить м-г) есть способ обойти вопросы вариантности с заводом? Что-то вроде:

class Fct(f:(Type,Type) => Type) 
object Fct { 
    def apply(f:(Type,Type) => Type): Fct = new Fct(f) 
    def apply[T <: Type, U <: Type, V <: Type](f:(T,U) => V): Fct = 
    new Fct((x:Type,y:Type) => {(x,y) match { 
     case (a:T, b:U) => f(a,b) 
     case _ => ??? 
    }}: Type) 
} 

ответ

4

Проблема с Fct((x: SubType, y: Type) => y) не синтаксис, это дисперсия. f в Fct имеет тип (Type, Type) => Type, то есть Function2[Type, Type, Type]. Function2 является контравариантным по своим первым двум параметрам.

Это означает, что (SubType, Type) => Typeне является подтипом (Type, Type) => Type. Поэтому вы не можете использовать его вместо (Type, Type) => Type. Обратите внимание, что Fct((x: Type, y: Type) => y) работает просто отлично.

С общей версии Fct, когда вы пишете Fct(_+_), нет никакого способа, чтобы вывести типы T и U. Лучшее, что вы можете надеяться в этом случае что-то вроде:

Fct[SubType, Type, Type](_ + _) 

Короче говоря, первый подход будет работать нормально, но ваши типы параметров функции будут прибиты к Type (или супер-типам, которые, которые вы, вероятно, не хочу). Это может быть все в порядке, потому что вы можете передать SubType в качестве параметров этой функции, вы просто не можете ограничить параметры до SubType, не нарушая контравариантность Function2. Второй подход будет работать, только если вы аннотируете типы где-то.

+0

Я надеялся обойти проблему отклонения с использованием заводского шаблона. Я добавил одну из моих попыток к вопросу, но синтаксис все еще не правильный. – Thibaut

+1

@Thibaut Возможно, вы сможете получить это для компиляции, но вы будете лгать компилятору. 'Fct' будет считать, что в нем есть' (Type, Type) => Type', когда это не так.Это означает, что если вы передаете 'Type' в качестве одного из параметров, но на самом деле это подтип, вы получите исключение ClassCastException во время выполнения. –

+0

Все было бы хорошо. Очевидно, что downcasts были менее грубыми, чем в моем примере, и я могу реализовать правильные проверки ошибок. Проблема убеждает систему типов, что позволяет мне это делать. – Thibaut

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