[GHC] #14860: QuantifiedConstraints: Can't quantify constraint involving type family

GHC ghc-devs at haskell.org
Fri Nov 23 21:49:20 UTC 2018


#14860: QuantifiedConstraints: Can't quantify constraint involving type family
-------------------------------------+-------------------------------------
        Reporter:  RyanGlScott       |                Owner:  (none)
            Type:  bug               |               Status:  closed
        Priority:  normal            |            Milestone:
       Component:  Compiler (Type    |              Version:  8.5
  checker)                           |             Keywords:
      Resolution:  wontfix           |  QuantifiedConstraints
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  GHC rejects       |  Unknown/Multiple
  valid program                      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 This is tricky in an interesting way.

 What is the problem with quantified constraints with a type-function in
 the head?
 Consider
 {{{
 f :: (forall a. C a => C (F a)) => ...
 }}}
 where `F` is a type family.   We really, really can't handle this.
 Suppose we have
 {{{
 type instance F [b] = (b,b)
 }}}
 and we are trying to solve `C (t,t)` in `f`'s RHS.  Well that's the same
 as `C (F [t])` and lo,
 now the quantified constraint matches.

 It would be utterly different if we had
 {{{
 f :: C (F a) => ...
 f = ...needs (C (F a))...
 }}}
 where the two constraints are patently equal; and it'd be equally fine if
 we
 had an enclosing constraint (from a GADT, say) telling us `a ~ [b]`.  Then
 we'd rewrite both the "given" and the "wanted" to `C (F [b])`, and if that
 in turn rewrites to `C (b,b)` then both will so rewrite. It's all fine.

 The trouble in the earlier example comes because `F` is applied to a
 quantified variable.  Here's another example it is, by comparison, fine:
 {{{
 type family F2 a :: * -> *
 f2 :: (forall b. C b => C (F2 x b)) => blah
 }}}
 Notice that `F2` has arity 1. And notice that the saturated application
 `(F2 x)` does not mention the quantified variable `b`.  So we could
 rewrite
 the signature thus:
 {{{
 f2a :: (y ~ F2 x, forall b. C b => C (y b)) => blah
 }}}
 This is fine, and it is accepted today.  By binding `F2 x` to `y`
 ''outside'' the
 quantification we have shown that the problems described above (about F)
 can't happen.

 Alas, `f2` is ''not'' accepted today.  Until today I thought that once
 could
 always rewrite in the `f2a` style, and that it would be positively good to
 do so.
 That's what comment:1 says.

 But today you have shown me a counter example.  I cannot apply that trick
 to
 {{{
 class (forall b. Show b => Show (T a b)) => C a where
   type family T a :: * -> *
 }}}
 I might try
 {{{
 class (y ~ T a, forall b. Show b => Show (y b)) => C a where
   type family T a :: * -> *
 }}}
 But now `y` is not bound in the class head, and we just don't allow that.
 (Why not?  Because a class turns into a data type declaration
 {{{
 data C a = MkC (..superclass1..)
                (..superclass2..)  etc
                (..method1..)
                (..method2..)  etc
 }}}
 so the superclass types can't mention variables not bound on the left.
 No we do not want existentials here.)

 So I am driven to the conclusion:

 * Perhaps we should allow type-family applications in the head of a
 quantified constraint, provided that the saturated application of the
 family does not mention any of the quantified variables.

 The flattener would have to work a bit harder.  Richard, what do you
 think?

 Thanks for the example.

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


More information about the ghc-tickets mailing list