scala: Referencing Trait with F-Bound Parameters

前提是你 提交于 2019-12-11 17:26:18

问题


I am designing a F-Bound data type, and have a working companion object. I would like to reference this companion object from the trait itself, but I can't get the types right.

trait A[AA <: A[AA]] {
  self =>
  val data: String
}
case class A1(data : String) extends A[A1]

trait B[BB <: B[BB, AA], AA <: A[AA]] {
  self: BB =>
  val content: AA
  def companion: BComp[BB, AA]  // What is the correct type?
  def companion2: BComp2[BB, AA] // What is the correct type?
}
trait BComp[BB[X <: BB[X, AA], Y <: AA[Y]], AA[Y <: AA[Y]]]

trait BComp2[BB[X <: AA[X]], AA[X <: AA[X]]]

case class BInst[AA <: A[AA]](content: AA) extends B[BInst[AA], AA] {
  def companion = BInst
  def companion2 = BInst2
}

object BInst extends BComp[B, A]
object BInst2 extends BComp2[BInst, A]

A working solution for either companion or companion2 would suffice, although a general hint on how to construct these type signatures would be useful.

edit

I want to use the companion object to store canBuildFrom style implicits as well as Builders, but as the content type A has an upper bound, all generating functions need to be aware of this bounding, so hence the parametrization of the companion object trait. The inspiration for this design comes from GenericCompanion.scala, of course, adding the type bounds makes everything more difficult :P


回答1:


The obstacle to any clear definition of types for companion is that BComp is parametrized by two parametrized types - while the first one is compatible with B, the second one AA[Y <: AA[Y]] is impossible to construct. So quite simply, we need to add this type to the parametrization of B:

trait B[BB <: B[BB, AA, X],
        AA[T <: AA[T]] <: A[T], 
        X <: AA[X]]  {
    self: BB =>
    val content: X
    def companion: BComp[B, AA]
}

now we have a compatible type AA for our companion object (which needs only a small expansion):

trait BComp[BHere[BB <: BHere[BB, AAA, Z],
                  AAA[Y <: AAA[Y]],
                  Z <: AAA[Z]],
            AA[Y <: AA[Y]]]

Isn't that pretty?

case class BInst[X <: A[X]](content: X) extends B[BInst[X], A, X] {
    def companion: BComp[B, A] = BInst5
  }
object BInst extends BComp[B, A]

companion2

For companion2, we just need to change the first part of the parametrization of B, so that trait B and the companion trait become:

trait B[BB[TS <: AA[TS]] <: B[BB, AA, TS],
        AA[T <: AA[T]] <: A[T], 
        X <: AA[X]] {
    self: BB[X] =>
    val content: X
    def companion2: BComp[BB, AA]
  }

trait BComp[BHere[TS <: AA[TS]],
            AA[Y <: AA[Y]]]

This is slightly more manageable. The case class and case objects are:

case class BInst[X <: A[X]](content: X) extends B[BInst, A, X] {
  def companion2: BComp[BInst, A] = BInst5
}
object BInst extends BComp[BInst, A]

If this is useful to anybody the rethink. I have changed my own design approach and I suggest you do too. Coming up with a solution to these types has now been a purely academic exercise!



来源:https://stackoverflow.com/questions/29750518/scala-referencing-trait-with-f-bound-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!