[GHC] #15557: Reduce type families in equations' RHS when testing equation compatibility

GHC ghc-devs at haskell.org
Fri Aug 24 18:37:43 UTC 2018


#15557: Reduce type families in equations' RHS when testing equation compatibility
-------------------------------------+-------------------------------------
        Reporter:  mniip             |                Owner:  (none)
            Type:  feature request   |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  Compiler (Type    |              Version:  8.4.3
  checker)                           |
      Resolution:                    |             Keywords:  TypeFamilies
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  GHC rejects       |  Unknown/Multiple
  valid program                      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #8423 #15546      |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by mniip):

 After giving it a little thought:

 Equation compatibility check can be regarded as a quantified implicational
 constraint:

 {{{
 [p] forall ps. TF lhs_p = rhs_p
 [q] forall qs. TF lhs_q = rhs_q
 }}}

 {{{
 compat(TF, p, q) = forall ps qs. (lhs_p ~ lhs_q) => (rhs_p ~ rhs_q)
 }}}

 Since `lhs_k` in Haskell are always a simple tycon/tyvar superposition,
 one can, as the CTFwOE paper implies, just run unification on `lhs_p ~
 lhs_q`. If the unification fails the implication holds vacuously,
 otherwise we have a substitution to apply to `rhs_p`/`rhs_q`. In such case
 we are left with:

 {{{
 compat(TF, p, q) = forall as. Omega(rhs_p) ~ Omega(rhs_q)
 }}}

 This constraint is still quantified but at least not implicational.

 Now we can kind-of express compatibility checking in the language of
 constraint solving: we have implicational axioms:

 {{{
 (apart(lhs_1, lhs_i), ..., apart(lhs_i-1, lhs_i)) => TF lhs_i ~ rhs_i
 (compat(TF, 1, i), ..., compat(TF, i-1, i)) => TF lhs_i ~ rhs_i
 }}}

 ...But also every other combination of `apart` and `compat` constraints,
 provided either is given for each j in [0 .. i-1]. Again `lhs_k` are
 simple enough that `apart` constraints can be easily immediately
 discharged to either trivially false or trivially true constraints. We are
 then left with, really, one implication constraint for each equation:

 {{{
 (compat(TF, c_1, i), ..., compat(TF, c_k, i)) => TF lhs_i ~ rhs_i
 }}}

 Where c_1,...,c_k are exactly the indices of equations that come before
 ith but whose lhs are not apart from ith equation's.

 This is where @goldfire's comment comes in: if we are left with a system
 of constraint implications that has multiple solutions, e.g:

 {{{
 compat(A, 0, 1) => compat(B, 0, 1)
 compat(B, 0, 1) => compat(A, 0, 1)
 }}}

 Here the two either simultaneously hold or simultaneously don't hold. Here
 it is actually type-safe to pick the most truthy solution: the greatest
 fixed point rather than the least.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15557#comment:3>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list