So, I played a little while trying to write something about existentiality and variance, and I came across this interesting piece of code.
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
}
This will not compile:
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 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
^
which I find strange rather than a (_ >: T) => (_ <: Box[_ <: U])subtype T => Box[U]? Since it Function1is contravariant in the parameter of the first type, this is a subtype T => (_ <: Box[_ <: U]). Since it Function1is covariant in the type of result, it is a subtype T => Box[_ <: U], and since it Boxis covariant in its parameter, is this not the whole thing a subtype T => Box[U]?
Strange changing the code to
// 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, - ))