2016-12-18 6 views
4

Итак, я немного поиграл, пытаясь что-то написать о экзистенциальности и дисперсии, и я наткнулся на этот интересный фрагмент кода.Почему компилятор не может определить (_>: T) => (_ <: V [_ <: U]) <: T => V [U] для V [+ _]?

final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

Это не может скомпилировать:

Variance.scala:3: no type parameters for method >>=: (f: T => Box[U])Box[U] exist so that it can be applied to arguments (_$1 => _$2) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[?U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                   ^
Variance.scala:3: type mismatch; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                    ^

который я нахожу странным, как это не (_ >: T) => (_ <: Box[_ <: U]) подтипом T => Box[U]? Поскольку Function1 контравариантен в параметре первого типа, это подтип T => (_ <: Box[_ <: U]). Так как Function1 является ковариантным по типу результата, это подтип T => Box[_ <: U], а так как Box является ковариантным по своему параметру, не все ли подтип T => Box[U]?

странно, изменяя код

// This change is not required ;) 
type Box[T] = `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[T] 
final case class `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= (f: T => Box[U]) 
} 

с типом отнесении к «подсказка» компилятору, что f: T => Box[U] делает его компиляции. Так как нет никакого неявного преобразования или объявления переменной здесь, не должно ли это иметь никакого значения?

Другой способ я нашел получения этой компиляции пишет

def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this.>>=[U](f) 

Это заставляет меня верить, что этот вопрос меньше с компилятором с трудом, получая, что (_ >: T) => (_ <: Box[_ <: U]) <: T => Box[U] и больше с ним не в состоянии выведите параметр типа >>=, который, как представляется, ссылается на сообщение об ошибке.

(Использование Scala 2.12.1 (с SBT, если это меняет что-нибудь))

ответ

0
final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

flatMap типа Retrun является Box[U], но использовать this >>= f.

So >>= будет автоматически заменять на f тип (_ >: T) => (_ <: Box[_ <: U]).

So Box[(_ >: T) => (_ <: Box[_ <: U])] не соответствует Box[U].

Я думаю, что вы можете изменить так:
def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>=[U] f

+0

Я знаю, как сделать код работы; Я спрашиваю * почему * он должен быть исправлен, потому что '_ <: Box [_ <: U]' * должен * соответствовать 'Box [U]'. Я знаю, что добавление '[U]' к '>> =' заставляет его скомпилировать. – HTNW

+0

Причина: 'Box [(_>: T) => (_ <: Box [_ <: U])]' не соответствует 'Box [U]' –

+0

Можете ли вы объяснить, где вы получаете 'Box [(_>: T) => (_ <: Box [_ <: U])] '? – HTNW