[GHC] #15347: QuantifiedConstraints: Implication constraints with type families don't work

GHC ghc-devs at haskell.org
Fri Jul 6 22:45:35 UTC 2018


#15347: QuantifiedConstraints: Implication constraints with type families don't
work
-------------------------------------+-------------------------------------
        Reporter:  aaronvargo        |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler (Type    |              Version:  8.5
  checker)                           |             Keywords:
      Resolution:                    |  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):

 Consider this:
 {{{
 type family F a
 type instance F Int = Bool

 instance Eq a => Eq (F a) where ...
 }}}
 Should we allow this?  Obviously not.  It's like allowing
 {{{
 map f (xs ++ ys) = map f xs ++ map f ys
 map f []         = []
 }}}
 where we have a function call in the pattern match.
 All manner of overlaps a chaos would result.
 So generally GHC does not allow type family calls in
 the head of an instance declaration.  And I've made that same
 rule apply to quantified constraints, which are really just local
 instance declarations.

 But, you say, how are these two different?
 {{{
 foo :: forall a b.   (a => F b,        a) => Dict (F b)
 qux :: forall a b c. (a => c, c ~ F b, a) => Dict (F b)
 }}}
 Very different, I say!  Suppose that quantified constraint had looked
 like this
 {{
 foo :: forall a b.   (forall t. a => F t b,  ...) => Dict (F b)
 }}
 Notice that the locally-quantified `t` is one of the arguments to `F`.
 Now, all the bad things could happen.  What is different about your
 example is that '''the function call is independent of any of the
 forall'd variables of the quantified constraint'''.  You expressed
 that by floating it out of the quantified constraint with you `c ~ F b`.
 And because it is independent of the forall'd variables, it is really
 constant so far as the instance is concerned, and doesn't lead to
 problems.

 Here's another variant:
 {{{
 foo :: forall b. (forall t. C b t => C (F b) [t],  ...) => Dict (F b)
 }}}
 Now the head of the quantified constraint does mention the forall'd `t`,
 but the call to `F` does not, so we can float thus:
 {{{
 foo :: forall b c. (c ~ F b, forall t. C b t => C c [t],  ...) => Dict (F
 b)
 }}}
 This directly expresses the fact that the first parameter to `C` in the
 head
 of the quantified constraint is independent of `t`.

 Now, you want this floating business to happen automatically, but I think
 it is much too complicated to do behind the scenes.  If that's what you
 want, you can say it.  I would be reluctant to introduce a significant
 (and unprecedented) implicit translation, based on a free-variable
 analysis,
 without plenty of evidence that it was going to have major benefit for a
 significant constituency.  I don't think we are close to that point yet.

 But it ''is'' a nice observation that, by expressing the independence with
 an equality constraint, you can say just what you mean, and get just what
 you want.  (I doubt that fundeps would be any help here.)

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


More information about the ghc-tickets mailing list