Skip to content

GADT example fails to typecheck because it requires injectivity of type constructors #4471

Closed
@Blaisorblade

Description

@Blaisorblade

Found on Twitter, noting it here: https://gist.github.com/TomasMikula/ecdbde18f142ffda0a02219f0118d7ba

@TomasMikula correctly points out:

Note that for the typechecker to succeed, it will have to make use of the fact that Tuple2 is an injective type constructor, i.e. be able to derive A = C from (A, B) = (C, D).

Investigation status: Still poking at this, and even if I modify everything to avoid covariant ADTs from the stdlib (for simplicity) and make case classes final, the typechecker still seems to have problems with injectivity. Still need to fire up the debugger to see what happens inside.

case class Pair[A, B](a: A, b: B)

enum Maybe[A] {
  case None()
  case Just(a: A)
}

object WithInvTuple {
  // Shorter notation for it
  type ~[A, B] = Pair[A, B]

  sealed trait Shuffle[A1, A2] {
    def andThen[A3](that: Shuffle[A2, A3]) = Shuffle.AndThen(this, that)
  }
  object Shuffle {
    final case class Id[A]() extends Shuffle[A, A]
    final case class Swap[A, B]() extends Shuffle[A ~ B, B ~ A]
    final case class AssocLR[A, B, C]() extends Shuffle[(A ~ B) ~ C, A ~ (B ~ C)]
    final case class AssocRL[A, B, C]() extends Shuffle[A ~ (B ~ C), (A ~ B) ~ C]
    final case class Par[A1, B1, A2, B2](_1: Shuffle[A1, A2], _2: Shuffle[B1, B2]) extends Shuffle[(A1, A2), (B1, B2)]
    final case class AndThen[A1, A2, A3](_1: Shuffle[A1, A2], _2: Shuffle[A2, A3]) extends Shuffle[A1, A3]

    def rewrite3[A1, A2, A3, A4](
      op1: Shuffle[A1, A2],
      op2: Shuffle[A2, A3],
      op3: Shuffle[A3, A4]
    ): Maybe[Shuffle[A1, A4]] = (op1, op2, op3) match {
      // case (Swap(), _, _) =>
      //   Maybe.Just(
      //     AssocLR[A1, A2 ~ A3, A4]()
      //     )
      // case (_: Swap[a11 ~ a12, _]) =>
      //   Maybe.Just(
      //     // ???
      //     AssocLR[a11 ~ a12, A2 ~ A3, A4]()
      //     )
      case (Swap(), AssocRL(), _) => Some(AssocLR[A1, A2 ~ A3, A4]())
      //case (Swap(), AssocRL(), Par(Swap(), Id())) =>
        //Some(AssocLR() andThen Par(Pair(Id(), Swap())) andThen AssocRL())
      case _ =>
        Maybe.None()
    }
  }
}
//output:
[info] Compiling 2 Scala sources to /Users/pgiarrusso/git/dotty-example-project/target/scala-0.8/classes ...
[error] -- [E007] Type Mismatch Error: /Users/pgiarrusso/git/dotty-example-project/src/main/scala/playground/mikulaGADT.scala:65:41
[error] 65 |      case (Swap(), AssocRL(), _) => Some(AssocLR[A1, A2 ~ A3, A4]())
[error]    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |found:    Some[mikulaGADT.WithInvTuple.Shuffle.AssocLR[A1, mikulaGADT.Pair[A2, A3], A4]]
[error]    |required: mikulaGADT.Maybe[mikulaGADT.WithInvTuple.Shuffle'[A1, A4]]
[error]    |
[error]    |where:    A1       is a type in method rewrite3 which is an alias of mikulaGADT.Pair[A$1, B$1]
[error]    |          A2       is a type in method rewrite3 with bounds >: mikulaGADT.Pair[B$1, A$1] and <: mikulaGADT.Pair[B$1, A$1] & mikulaGADT.Pair[B$1, mikulaGADT.Pair[B$2, C$1]]
[error]    |          A3       is a type in method rewrite3 which is an alias of mikulaGADT.Pair[mikulaGADT.Pair[B$1, B$2], C$1]
[error]    |          Shuffle  is a object in object WithInvTuple
[error]    |          Shuffle' is a trait in object WithInvTuple
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 2 s, completed May 6, 2018 2:56:44 PM

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions