Scala, cannot avoid cyclic parameterization

I have reduced my problem to MWE (minimal (not) working example). Here it is:

First, we have a datatype Loss

which is essentially a Function2

and therefore contravariant in T.

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

      

Then we have a label whose loss is a property:

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

      

It is also naturally covariant and must be F-restricted. Up to this point, the program is compiled. The problem arises when I want to make a concrete implementation of the case class of an abstract class Labeled

. I've tried this:

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] {
           ^

      

However, I try to parameterize it, I get a circular definition. How can this be done, or if not, tell me what I think is wrong.

How I got it working (warning: bad hack): I removed the abstract spec Loss

from Labeled

and just kept the above definition across all subclasses. When I need to call Loss

on a generic class Labeled

, I match templates for every possible subclass. Hope it gets resolved someday.

+3


source to share


1 answer


As said in the comments, you cannot override a parameterized method with a value, so you probably have to move Q

from the definition 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] 

      

You can specify Q yourself (the existential type _ >: Numerical

presented Q >: TT

here will resolve to Any

otherwise):



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

      

So now you can use it:

 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 available, as you put `Q = Numeric`
     0L
   }
 })

 // Exiting paste mode, now interpreting.

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

      

+3


source







All Articles