Scala,无法避免循环参数化

时间:2015-08-04 21:55:59

标签: scala types

我已将问题减少到MWE(最小(非)工作示例)。在这里:

首先,我们有一个数据类型Loss,它基本上是Function2,因此在T中是逆变的。

abstract class Loss[-T] {
    def apply(actual: T, predicted: T): Double
}

接下来,我们有一个Labeled,其中包括遗失:

abstract class Labeled[+T <: Labeled[T]] {
    def loss[Q >: T]: Loss[Q]
}

它也是自然协变的,它必须是F-有界的。到目前为止,程序编译。当我想要创建Labeled抽象类的具体案例类实现时,问题就出现了。我试过这个:

Error:(9, 12) class Numerical needs to be abstract, since method loss in class Labeled of type [Q >: Numerical]=> Loss[Q] is not defined
case class Numerical(name: Symbol, loss: Loss[_ >: Numerical]) extends Labeled[Numerical] {
           ^

但是我试着对它进行参数化,我得到了一个循环定义。怎么可能这样做,或者如果没有,告诉我我在想什么。

我如何开始工作(警告:糟糕的黑客):我已从loss中删除了Labeled的抽象规范,并将上述定义保留在所有子类中。当我需要在一般loss类上调用Labeled时,我会为每个可能的子类进行模式匹配。我希望有一天能够解决这个问题。

1 个答案:

答案 0 :(得分:3)

正如评论中所述,您无法使用值覆盖参数化方法,因此您可能需要将Q移出loss的定义:

abstract class Labeled[+T <: Labeled[T]] {
    type TT <: T
    type Q >: TT

    def loss: Loss[Q]
}

case class Numerical(name: Symbol, loss: Loss[Numerical#Q]) extends Labeled[Numerical] 

您可能想要指定Q本身(存在类型_ >: Numerical,此处用Q >: TT表示,否则将解析为Any):

 case class Numerical(name: Symbol, loss: Loss[Numerical#Q]) extends Labeled[Numerical] {
   type Q = Numerical //can only be >: than Numerical
 }

现在你可以使用它了:

 scala> :paste
 // Entering paste mode (ctrl-D to finish)

 Numerical('a, new Loss[Numerical#Q] {
   def apply(actual: Numerical#Q, predicted: Numerical#Q): Double = {
     actual.loss //check that it's available, as you put `Q = Numeric`
     0L
   }
 })

 // Exiting paste mode, now interpreting.

 res19: Numerical = Numerical('a,$anon$1@6355264c)