Re: [GHC] #12102: “Constraints in kinds” illegal family application in instance (+ documentation issues?)

GHC ghc-devs at haskell.org
Tue Jul 18 20:28:52 UTC 2017


#12102: “Constraints in kinds” illegal family application in instance (+
documentation issues?)
-------------------------------------+-------------------------------------
        Reporter:  Iceland_jack      |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.0.1
      Resolution:                    |             Keywords:  TypeInType
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #13780            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by goldfire):

 I was just about to do this. But then I had second thoughts. Right now, we
 take it as a general rule that the following two declarations are the
 same:

 {{{#!hs
 data G1 a where
   MkG1 :: G1 Bool

 data G2 a = (a ~ Bool) => MkG2
 }}}

 and indeed this is true today. But if we throw out `~` in kinds, as
 proposed here, then only `'MkG1` would be usable in a type. `'MkG2` would
 be an error, violating our general rule.

 About Givens: GADT pattern-matching in terms must be very fancy, because
 the GADT pattern-match relates a runtime thing to a compile-time thing.
 Figuring out how to do this time travel required several PhDs to be
 earned. On the other hand, GADT pattern-matching in types need not be
 nearly so advanced, because everything is compile-time. Indeed, GHC's
 current implementation of type-level GADT pattern-matching is somewhat
 simplistic, not using Givens at all. (More below, as I'm sure you'll be
 curious.) So, even though a `~` in a kind never gives rise to a Given,
 they are still useful and can be matched against in a type family.

 How type-level GADT pattern matching works: Let's look at an example.

 {{{#!hs
 type family F1 (a :: G k) :: k where
   F1 MkG1 = True
 }}}

 This would seem to require fancy GADT pattern matching. After all, we
 declare that the return kind be `k` for some unknown `k`, and yet we
 return `True :: Bool`. However, this really works by doing ''kind-
 matching''. That is, the definition is elaborated to make its kind
 variables explicit:

 {{{#!hs
 type family F1 (k :: Type) (a :: G k) :: k where
   F1 Bool MkG1 = True
 }}}

 Because type families can pattern-match on kinds, this is hunky dory. The
 ''caller'' is responsible for showing that `k` is really `Bool`. This
 sounds terrible, though: what has happened to the expressiveness of GADTs?
 Nothing bad. Of course the caller can figure out what `k` should be,
 because it has the same information this function does. (This is very
 different in terms, where a GADT parameter is learned by a ''runtime''
 pattern match. No phase distinction in type families!)

 This trick has its limits, of course: you can't usefully use a constraint
 of the form `F a ~ G a` in a kind. I do want to fix that some day. But not
 today. And, in the meantime, it's unclear if I should fix this ticket and
 violate the general rule at the top of this comment.

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


More information about the ghc-tickets mailing list