-
Notifications
You must be signed in to change notification settings - Fork 1.1k
GADT example fails to typecheck because it requires injectivity of type constructors #4471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
A whole bunch of object i4471 {
sealed trait Shuffle[A1, A2] {
def andThen[A3](that: Shuffle[A2, A3]): Shuffle[A1, A3] = AndThen(this, that)
}
case class Id[A]() extends Shuffle[A, A]
case class Swap[A, B]() extends Shuffle[(A, B), (B, A)]
case class AssocLR[A, B, C]() extends Shuffle[((A, B), C), (A, (B, C))]
case class AssocRL[A, B, C]() extends Shuffle[(A, (B, C)), ((A, B), C)]
case class Par[A1, B1, A2, B2](_1: Shuffle[A1, B1], _2: Shuffle[A2, B2]) extends Shuffle[(A1, A2), (B1, B2)]
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]
): Option[Shuffle[A1, A4]] = (op1, op2, op3) match {
case (
_: Swap[x, y],
_: AssocRL[u, v, w],
op3_ : Par[p1, q1, p2, q2]
) => op3_ match {
case Par(_: Swap[r, s], _: Id[p2_]) =>
Some(
AssocLR[v, w, u]() andThen Par(Id[v](), Swap[w, u]()) andThen AssocRL[v, u, w]()
)
case _ => None
}
case _ => None
}
} The GADT constraints that should be inferred are equiv to the following: (using parameter names from the above) A1 := (x, y)
A2 := (y, x)
A2 := (u, (v, w))
A3 := ((u, v), w)
A3 := (p1, p2)
A4 := (q1, q2)
p1 := (r, s)
q1 := (s, r)
p2 := p2_
q2 := p2_ Gist can be further inspected to see how constraints which would allow the code to compile are derivable from the above. |
@TomasMikula any similar examples would be very welcome. The examples in this issue were the only ones to properly stress #5258. Haskell is OK, so is linking to a project which heavily uses GADTs. |
I'm glad that GADTs are being taken seriously. Here is a more complex pattern on the same data type: {-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
module Shuffle where
data Shuffle a1 a2 where
Id :: forall a. Shuffle a a
Swap :: forall a b. Shuffle (a,b) (b,a)
AssocLR :: forall a b c. Shuffle ((a,b),c) (a,(b,c))
AssocRL :: forall a b c. Shuffle (a,(b,c)) ((a,b),c)
Par :: forall a1 b1 a2 b2. Shuffle a1 b1 -> Shuffle a2 b2 -> Shuffle (a1,a2) (b1,b2)
AndThen :: forall a1 a2 a3. Shuffle a1 a2 -> Shuffle a2 a3 -> Shuffle a1 a3
rewrite :: Shuffle a b -> Maybe (Shuffle a b)
rewrite ( -- ((X, Y), (U, V))
AssocLR
`AndThen` -- (X, (Y, (U, V)))
(Par Id ( AssocRL
`AndThen` -- (X, ((Y, U), V))
(Par Swap Id)
`AndThen` -- (X, ((U, Y), V))
AssocLR
`AndThen` -- (X, (U, (Y, V)))
(Par Id Swap) ))
`AndThen` -- (X, (U, (V, Y)))
AssocRL
`AndThen` -- ((X, U), (V, Y))
(Par Swap Id)
`AndThen` -- ((U, X), (V, Y))
AssocLR
`AndThen` -- (U, (X, (V, Y)))
(Par Id ( AssocRL
`AndThen` -- (U, ((X, V), Y))
(Par Swap Id)
`AndThen` -- (U, ((V, X), Y))
AssocLR ))
`AndThen` -- (U, (V, (X, Y)))
AssocRL
) = -- ((U, V), (X, Y))
Just Swap
rewrite _ = Nothing Here, the data type is extended with {-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
module FreeCCC where
data FreeCCC a1 a2 where
Id :: forall a. FreeCCC a a
Swap :: forall a b. FreeCCC (a,b) (b,a)
AssocLR :: forall a b c. FreeCCC ((a,b),c) (a,(b,c))
AssocRL :: forall a b c. FreeCCC (a,(b,c)) ((a,b),c)
Par :: forall a1 b1 a2 b2. FreeCCC a1 b1 -> FreeCCC a2 b2 -> FreeCCC (a1,a2) (b1,b2)
AndThen :: forall a1 a2 a3. FreeCCC a1 a2 -> FreeCCC a2 a3 -> FreeCCC a1 a3
Curry :: forall a b c. FreeCCC (a,b) c -> FreeCCC a (b->c)
Eval :: forall a b. FreeCCC (a->b, a) b
rewrite :: FreeCCC a b -> Maybe (FreeCCC a b)
rewrite ((Par (g `AndThen` (Curry h)) Id) `AndThen` Eval) = Just ((Par g Id) `AndThen` h)
rewrite _ = Nothing Finally, I would like if such inferences worked not only for concrete types ( sealed trait Shuffle[x[_,_], A1, A2] // abstract over Tuple2 with a generic product `x`
case class Swap[x[_,_], A, B]() extends Shuffle[x, A x B, B x A]
case class Par[x[_,_], A1, B1, A2, B2](_1: Shuffle[x, A1, B1], _2: Shuffle[x, A2, B2]) extends Shuffle[x, A1 x A2, B1 x B2]
// ...
def rewrite[x[_,_]: BiInjective, A, B](f: Shuffle[x, A, B]): Option[Shuffle[x, A, B]] =
f match {
// injectivity of `x` in both variables is taken into account by pattern matching
case AndThen(Swap(), AndThen(Par(g, f), Swap())) => Par(f, g)
case _ => None
} I don't know how to do this in Haskell, either. |
@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. |
Found on Twitter, noting it here: https://gist.github.com/TomasMikula/ecdbde18f142ffda0a02219f0118d7ba
@TomasMikula correctly points out:
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.
The text was updated successfully, but these errors were encountered: