Scala 协变类型FParam出现在值猜测的类型Seq[FParam]中的逆变位置

Scala 协变类型FParam出现在值猜测的类型Seq[FParam]中的逆变位置,scala,covariance,contravariance,scala-generics,Scala,Covariance,Contravariance,Scala Generics,考虑这个简单的例子: trait Optimizer[+FParam, FRes] { def optimize( fn: (FParam) => FRes, guesses: Seq[FParam] // <--- error ) } 逆变类型出现在type(FParam)=>FRes 同样,同样的悖论:在Function1[-T1,R]中,第一个类型参数显然是反变的,那么为什么FParam处于协变位置呢?(问题2) 如中所述,我可以通过翻转差异来解决此问

考虑这个简单的例子:

trait Optimizer[+FParam, FRes] {
  def optimize(
    fn: (FParam) => FRes,
    guesses: Seq[FParam] // <--- error
  )
}
逆变类型出现在type
(FParam)=>FRes

同样,同样的悖论:在
Function1[-T1,R]
中,第一个类型参数显然是反变的,那么为什么
FParam
处于协变位置呢?(问题2

如中所述,我可以通过翻转差异来解决此问题,但不清楚为什么需要这样做

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

  def optimize(
    fn: (FParam) => FRes,
    guesses: Seq[U]
  )
}
trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
}

问题在于FParam没有直接使用。它位于
optimize
的参数中,因此其方差被翻转。为了举例说明,让我们看看
optimize
的类型(请参见
val optim
):

trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
val optim:Function2[
功能1[
FParam,
壁画
],
序号[U],
单位
]=优化
}

问题在于FParam没有直接使用。它位于
optimize
的参数中,因此其方差被翻转。为了举例说明,让我们看看
optimize
的类型(请参见
val optim
):

trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
val optim:Function2[
功能1[
FParam,
壁画
],
序号[U],
单位
]=优化
}

问题1
+FParam
表示协变类型
FParam
,它从超类型到子类型
FParam
。对于
猜测
它期望
协变类型
用于
Seq
。因此,您可以为此显式声明
FPParam
超类型,如:

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

那么为什么
猜测
它期望
共变异类型
序列
?例如:

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
-FParam
指的是cotravairant类型
FParam
,它从超类型
FParam
到它的子类型。对于
fn:Function1[-T1,+R]/(FParam)=>FRes
它期望的是协变类型。因此,您可以通过反转问题1类型状态来完成,如:

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

问题1
+FParam
表示协变类型
FParam
,它从超类型到子类型
FParam
。对于
猜测
,它期望
序列
协变类型
。因此,您可以通过明确声明一个
超类为此键入
FPParam
,如:

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

那么为什么
猜测
对于
序列
,它期望的是
协变量类型
?例如:

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
-FParam
指的是COTRAVARIANT类型
FParam
,它从超类型
FParam
到其子类型。对于
fn:Function1[-T1,+R]/(FParam)=>FRes
这是一个协变的类型。所以你可以通过倒转问题1的类型状态来实现,比如:

def optimize[B <: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the sub type of FParam
def optimize[B FRes,guesses:Seq[B])//B是FParam的子类型
希望我能消除这种困惑

Seq[]不是列表,并且其中不能同时包含多个类类型。您的特征优化器具有未知但固定的类FParam或子类,但您的函数返回Seq[FParam]不绑定为与封闭对象相同的子类。因此,可能会导致运行时中不同的子类同时出现在Seq[FParam]中,因此整个代码块成为Scala编译错误

abstract class Optimizer[+FParam, FRes] {

}

object Optimizer{
   def optimize[FParam,FRes](obj: Optimizer[FParam,FRes], param : FParam) : (FParam,Seq[FParam]) = (param,(Nil)) 
}
trait(现在是一个抽象类)仍然有协方差泛型参数,但是在其参数中使用协方差泛型的函数被类型锁定为具有不变量的确切类型-强制在函数中使用相同的类或子类,现在在单例对象中。

希望我能够消除混淆

Seq[]不是列表,并且其中不能同时包含多个类类型。您的特征优化器具有未知但固定的类FParam或子类,但您的函数返回Seq[FParam]不绑定为与封闭对象相同的子类。因此,可能会导致运行时中不同的子类同时出现在Seq[FParam]中,因此整个代码块成为Scala编译错误

abstract class Optimizer[+FParam, FRes] {

}

object Optimizer{
   def optimize[FParam,FRes](obj: Optimizer[FParam,FRes], param : FParam) : (FParam,Seq[FParam]) = (param,(Nil)) 
}
trait(现在是一个抽象类)仍然具有协变泛型参数,但是在其参数中使用协变泛型的函数被类型锁定为具有不变量的确切类型-强制的,该不变量与现在在singleton对象中的函数中的同一类或子类相同