2017-08-08 8 views
0

devine Considérons cet exemple simple:le type Covariant FPARAM se produit en position contravariant dans le type Seq [FPARAM] de la valeur

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

Il ne compile pas, parce que

Type Covariant FParam se produit dans contravariante position dans le type Seq[FParam] des estimations de valeur.

Mais seq est défini comme trait Seq[+A], alors quelle est la source de cette contravariance? (Question 1)

A l'inverse, considérez cet exemple simple avec -FParam:

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

de type contravariant se produit en position covariante dans le type (FParam) => FRes

Encore une fois, le même paradoxe: en Function1[-T1, R], le premier paramètre de type est clairement contravariant, alors pourquoi FParam est-il dans une position covariante? (Question2)

Je peux résoudre ce problème en retournant la variance comme décrit dans Lower type bounds, mais pourquoi cela n'est pas clair.

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

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

Répondre

0

Le problème est que FParam n'est pas utilisé directement. C'est dans l'argument de optimize, et en tant que telle sa variance est inversée. Pour illustrer, regardons le type de optimize (voir 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

Question 1: +FParam signifie le type covarianteFParam et varie de supertype au sous-type FParam. pour le guesses, il attend cotravariant type pour Seq. Ainsi, vous pouvez le faire en déclarant explicitement une supertype de FPParam pour cela, comme:

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

ou comme le SeqViewLike.

donc pourquoi guesses attend cotravariant type pour Seq? par exemple:

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. 

Question 2: -FParam signifie que le cotravairant le type FParam et varie de supertype FParam à sa sous-type .pour fn: Function1[-T1, +R]//(FParam) => FRes il est attendre le type covariant pour cela.Donc, vous pouvez le faire par l'inverse le Question 1 l'état de type, comme:

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