question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
abgruszeckicommented, Dec 23, 2018

@TomasMikula - thank you for the examples. I’ve added some very similar examples on #5611, taken from Haskell test suite.

The exact examples from this issue do typecheck, so I’m closing the issue. We still have #5658 to deal with.

1reaction
TomasMikulacommented, May 6, 2018

You copied the old version with a mistake in the Par constructor:

screen shot 2018-05-06 at 3 57 48 pm

Also, your snippet mixes Pair and Tuple2 (your Par constructor uses Tuple2, whereas the other ones use Pair).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unsoundness due to GADT bounds ignoring type (un)injectivity
abgruszecki mentioned this issue on Dec 23, 2018. GADT example fails to typecheck because it requires injectivity of type constructors #4471.
Read more >
Injective type families with GADTs - haskell - Stack Overflow
I tried a very simple example involving injective type families, but ... 'b' is a rigid type variable bound by a pattern with...
Read more >
Injective type families (#6018) · Issues - GHC - GitLab
Add the constructor InjFamilyTyCon to TyConRhs and the family flavour InjectiveFamily to HsSyn . Again, I've opted to encode injectivity as a ...
Read more >
Partial Type Constructors in Practice
For example : • The UArray type constructor describes arrays of unbox- able elements; type UArray Int (Int → Int) does not make...
Read more >
Haskell/GADT - Wikibooks, open books for an open world
Generalised algebraic data-types (GADT) 75% developed ... a safe list type for which the equivalent of head [] fails to typecheck and thus...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found