/ / Kowariant typu FParam występuje w pozycji przeciwstawnej w typie Seq [FParam] domysłów wartości - scala, kowariancja, kontrawariancja, scala-generics

Typ kowariantowy FParam występuje w pozycji przeciwwariantowej w Seq [FParam] wartości domysłów - scala, kowariancja, contrawariancja, scala-generics

Rozważ ten prosty przykład:

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

Nie kompiluje się, ponieważ

Typ kowariantny FParam występuje w pozycji sprzecznej z typem Seq[FParam] domysłów wartości.

Ale sekwencja jest zdefiniowana jako trait Seq[+A], więc jakie jest źródło tej sprzeczności? (Pytanie 1)

I odwrotnie, rozważ ten prosty przykład z -FParam:

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

Typ przeciwstawny występuje w pozycji kowariantnej w typie (FParam) => FRes

Ponownie ten sam paradoks: w Function1[-T1, R], parametr pierwszego typu jest wyraźnie sprzeczny, więc dlaczego FParam w pozycji kowariantnej? (Pytanie 2)

Mogę rozwiązać ten problem, odwracając wariancję zgodnie z opisem w Dolne granice typów, ale dlaczego jest to konieczne, nie jest jasne.

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

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

Odpowiedzi:

2 dla odpowiedzi № 1

Pytanie 1: +FParam oznacza kowariant rodzaj FParam i różni się od supertype podtyp FParam. dla guesses to się spodziewa cotravariant type dla Seq. Możesz to zrobić, wyraźnie zaznaczając supertype z FPParam w tym:

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

lub jak SeqViewLike.

więc po co guesses to się spodziewa cotravariant type dla Seq? na przykład:

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.

pytanie 2: -FParam oznacza kotravairant rodzaj FParam i różni się od nadtypu FParam do tego podtyp.dla fn: Function1[-T1, +R]//(FParam) => FRes to się spodziewa kowariant wpisz do tego. Możesz to zrobić odwrotnie Pytanie 1 wpisz stan, np .:

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

0 dla odpowiedzi nr 2

Problem polega na tym, że FParam nie jest używany bezpośrednio. Jest to argumentem optimizei jako taka zmienia się jego wariancja. Aby to zilustrować, spójrzmy na typ optimize (widzieć 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
}