Proof of equivalence of nested elements of path-dependent elements

This is a simplified case, and I'm completely open to another / better way to achieve this.

trait Container {
  type T
  def data: List[T]
}

trait Transform {
  val from: Container
  val to: Container
  def xform: from.T => to.T
}

case class Identity(c: Container) extends Transform {
  val from = c
  val to = c
  def xform = { t: from.T => t }
}

This gives a predictable error:

<console>:12: error: type mismatch;
 found   : t.type (with underlying type Identity.this.from.T)
 required: Identity.this.to.T
         def xform = { t: from.T => t }

The goal is basically a conversion that transforms the objects that lie at the base of the container, but in order to convince the type check (without horrible horrible castings all over the place) that the types are the same.

What is the best way to show equivalences and type relationships in this way?

As I said, it is completely open for code restructuring, and I promise in a real example that this is for a real purpose :)

+4
source share
3 answers

I think that general options may be an easier way to describe this pattern.

, T Container:

case class Identity(c: Container) extends Transform {
  val from: Container { type T = c.T } = c
  val to: Container { type T = c.T } = c
  def xform = { t: from.T => t }
}

:

case class Identity(c: Container) extends Transform {
  val from: c.type = c
  val to: c.type = c
  def xform = { t: from.T => t }
}

, Container Transform, , :

case class Identity[U](c: Container { type T = U }) extends Transform {
  val from = c
  val to = c
  def xform = { t: c.T => t }
}

U , T Container, , !

, , . , . , (, , ).

+4

Container , Identity. , , , xform , , Identity. , xform, , :

def xform = { t: from.T => to.data.head }

, , - from.data.head.

:

  trait Container[T] {
    def data: List[T]
  }

  trait Transform[A, B] {
    val from: Container[A]
    val to: Container[B]
    def xform: A => B
  }

  case class Identity[A](c: Container[A]) extends Transform[A, A] {
    val from = c
    val to = c
    def xform = { t: A => t }
  }
0

If someone is stuck with dependent types, structural refinement is an ugly but effective salvation.

abstract class ContainerRefiner {
  val container: Container
}

trait Container {
  type T
  def data: List[T]
}

trait Transform {
  val from: Container
  val to: Container
  def xform: from.T => to.T
}

case class Identity(c: Container) extends Transform {
  val refiner = new {val container: c.type = c} with ContainerRefiner
  val from = refiner.container
  val to = refiner.container
  def xform = { t: from.T => t }
}

Can I comment on the pros and cons between this approach and higher types?

0
source

All Articles