Итак, я немного поиграл, пытаясь что-то написать о экзистенциальности и дисперсии, и я наткнулся на этот интересный фрагмент кода.Почему компилятор не может определить (_>: 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, если это меняет что-нибудь))
Я знаю, как сделать код работы; Я спрашиваю * почему * он должен быть исправлен, потому что '_ <: Box [_ <: U]' * должен * соответствовать 'Box [U]'. Я знаю, что добавление '[U]' к '>> =' заставляет его скомпилировать. – HTNW
Причина: 'Box [(_>: T) => (_ <: Box [_ <: U])]' не соответствует 'Box [U]' –
Можете ли вы объяснить, где вы получаете 'Box [(_>: T) => (_ <: Box [_ <: U])] '? – HTNW