scalatype-systemshigher-kinded-typestype-projection

Scala: higher-kinded types, type projections and type mismatch error


I have the following code:

trait M[Type[_]]{
  type T[X] = Type[X]
  def from[A](f: T[A]): A
}
class ListM extends M[List]{ def from[A](f: T[A]) = f.head }

class Trans[A, X[_], B <: M[X]](val r: X[Option[A]])
trait CurriedTrans[X[_], B <: M[X]]{ type Type[A] = Trans[A, X, B] }
class TransM[X[_], B <: M[X]](val b: B) extends M[CurriedTrans[X, B]#Type]{
  def from[A] = (f: T[A]) => b.from(f.r).get
}

and I can instantiate variables of type TransM in two ways:

val x1 = new TransM[List, ListM](new ListM)
val x2 = new TransM[ListM#T, ListM](new ListM)

I think ListM#T is redundant type parameter, so I'm trying to eliminate it:

trait M{
  type T[X]
  def from[A](f: T[A]): A
}
class ListM extends M {
  type T[X] = List[X]
  def from[A](f: T[A]) = f.head
}

class Trans[A, B <: M](val r: B#T[Option[A]])
class TransM[B <: M](val b: B) extends M {
  type T[X] = Trans[X, B]
  def from[Y] = (f: T[Y]) => b.from(f.r).get
}

to instantiate variable as

val x = new TransM[ListM](new ListM)

Unfortunately, the second implementation can't be compiled because of a type mismatch error:

type mismatch;
 found   : f.r.type (with underlying type B#T[Option[Y]])
 required: TransM.this.b.T[?]
      def from[Y] = (f: T[Y]) => b.from(f.r).get
                                          ^

Can I fix this issue and simplify my code or should I write boilerplate ListM#T everywhere?


Solution

  • @ziggystar says it: Drop the bound B and use M[X] directly:

    class TransM[X[_]](val b: M[X]) extends M[CurriedTrans[X, M[X]]#Type] {
      def from[A](f: T[A]) = b.from(f.r).get
    }
    
    val x1 = new TransM(new ListM)
    

    You could consider to do the same for Trans and CurriedTrans. If you need the inner type of M, you can always expose it through a type member of Trans and CurriedTrans.