2017-08-08 55 views
0

考慮這個簡單的例子:協變型FParam發生在逆變位置類型的值序號[FParam]猜測

trait Optimizer[+FParam, FRes] { 
    def optimize(
    fn: (FParam) => FRes, 
    guesses: Seq[FParam] // <--- error 
) 
} 

它不編譯,因爲

協變型FParam在逆變發生在價值猜測Seq[FParam]類型的位置。

但是seq被定義爲trait Seq[+A],那麼這個反變量的來源是什麼? (問題1

相反地,考慮這個簡單的例子與-FParam:在協變位置發生

trait Optimizer[-FParam, FRes] { 
    def optimize(
    fn: (FParam) => FRes, // <--- error 
    guesses: Seq[FParam] 
) 
} 

反變型在型(FParam) => FRes

再次,相同的矛盾:在Function1[-T1, R],第一個類型參數顯然是逆變的,那麼爲什麼FParam處於協變位置? (Question2

我可以通過翻轉Lower type bounds中描述的方差來解決這個問題,但爲什麼它有必要不清楚。

trait Optimizer[+FParam, FRes] { 
    type U <: FParam 

    def optimize(
    fn: (FParam) => FRes, 
    guesses: Seq[U] 
) 
} 

回答

0

問題是FParam沒有直接使用。它的參數是optimize,因此其方差翻轉。爲了說明這一點,讓我們來看看optimize類型(見val optim):

trait Optimizer[+FParam, FRes] { 
    type U <: FParam 

    def optimize(
    fn: (FParam) => FRes, 
    guesses: Seq[U] 
) 

    val optim: Function2[ 
    Function1[ 
     FParam, 
     FRes 
    ], 
    Seq[U], 
    Unit 
    ] = optimize 
} 
2

問題1+FParam意味着FParam它從不同亞型FParam。對於guesses它期望cotravariant typeSeq。所以,你可以通過明確說明FPParam本的supertype,像這樣做:

def optimize[B >: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the super type of FParam 

或類似的SeqViewLike

爲什麼guesses它期望cotravariant typeSeq?例如:

trait Animal 

case class Dog() extends Animal 

case class Cat() extends Animal 
val o = new Optimizer2[Dog, Any] 
val f: Dog => Any = (d: Dog) => ... 
o.optimize(f, List(Dog(), Cat())) // if we don't bind B in `guesses` for supertype of `FParam`, it will fail in compile time, since the `guesses` it's expecting a `Dog` type, not the `Animal` type. when we bind it to the supertype of `Dog`, the compiler will infer it to `Animal` type, so `cotravariant type` for `Animal`, the `Cat` type is also matched. 

問題2-FParamcotravairant類型FParam和到它的亞型。對於fn: Function1[-T1, +R]//(FParam) => FRes它期待協變類型此它從超類型FParam變化。所以你可以通過問題1類型的狀態,如:

def optimize[B <: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the sub type of FParam