Question

Given a polymorphic type Distribution, I want to establish, what I would call a typeclass on this (polymorphic) type. I think this goes under the term Higer Kinded Types.

trait Distribution[A] extends Measure[A] with Random[A] {
  type Domain = A
}

Distributions instantiating this typeclass should implement a method train, which given a List of elements in the domain of the distribution, return an object this distribution.

trait ML[D <: Distribution[_] ] {
  def train( samples: List[D#Domain] ): D
}

But when I try to instantiate like this (Binomial is a Distribution[Int]):

implicit object MLBinomial extends ML[Binomial] {
  def train( samples: List[Int] ) : Binomial = ???
}

I get the following error:

Binomial.scala:181: object creation impossible, since method train in trait ML
of type (samples: List[_$1])org.lanyard.dist.disc.Binomial is not defined
(Note that List[_$1] does not match List[Int]: their type parameters differ)

I am guessing I am the victim of type erasure but I am not sure and just learning to fight with the scala type system. Is anybody able to fix this code or am I forced to use a different design?

Thank you in advance.

Était-ce utile?

La solution

When you're defining

trait ML[D <: Distribution[_]] {
  def train(samples: List[D#Domain]): D
}

then D#Domain cannot be fixed because you're saying that D is a subtype of Distribution[_] where you really don't care about what _ actually is. If instead you want to infer the inner type, you could do as follows:

trait Measure[T]
trait Random[T]

trait Distribution[A] extends Measure[A] with Random[A] {
  type Domain = A
}

trait Binomial extends Distribution[Int]

trait ML[A, D <: Distribution[A]] {
  def train(samples: List[A]): D    // could be List[D#Domain] now as well
}

object ML {
  implicit object MLBinomial extends ML[Int, Binomial] {
    def train(samples: List[Int]) : Binomial = ???
  }
}

EDIT: If you don't want to mess around with multiple type parameters, you could also restrict Domain to a subtype of A. This will type-check and (hopefully) give you what you want. You'd only have to specify Domain when defining Binomial:

trait Distribution[A] extends Measure[A] with Random[A] {
  type Domain <: A
}

trait Binomial extends Distribution[Int] { type Domain = Int }

trait ML[D <: Distribution[_]] {
  def train(samples: List[D#Domain]): D
}

object ML {
  implicit object MLBinomial extends ML[Binomial] {
    def train(samples: List[Int]): Binomial = ???
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top