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

GHC ghc-devs at haskell.org
Sat Feb 16 17:55:05 UTC 2019


#14860: QuantifiedConstraints: Can't quantify constraint involving type family
-------------------------------------+-------------------------------------
        Reporter:  RyanGlScott       |                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:  #16123            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by RyanGlScott):

 Out of all the workarounds documented on this issue, I somehow overlooked
 the best one: Iceland_jack's solution in comment:16 involving `Dict`s.
 This offers a general blueprint to how to sneak type families into
 quantified constraints in the event that the trick in comment:1 doesn't
 work.

 In the particular example of comment:18, we wish to use `Show (T a b)` in
 the head of a quantified constraint. While this isn't directly possible,
 we can define a "class newtype" around `Show (T a b)` and use //that// in
 the head of a quantified constraint:

 {{{#!hs
 class    Show (T a b) => ShowT a b
 instance Show (T a b) => ShowT a b

 class (forall b. Show b => ShowT a b) => C a where
   type family T a :: * -> *
 }}}

 If we try to define a `Show` instance for `D`, it first appears as though
 we are stuck:

 {{{#!hs
 data D a = MkD (T a Int)

 instance C a => Show (D a) where
   showsPrec p (MkD x)
     = showParen (p > 10) $ showString "MkD " . showsPrec 11 x
 }}}
 {{{
 Bug.hs:35:48: error:
     • Could not deduce (Show (T a Int))
         arising from a use of ‘showsPrec’
       from the context: C a
         bound by the instance declaration at Bug.hs:33:10-26
     • In the second argument of ‘(.)’, namely ‘showsPrec 11 x’
       In the second argument of ‘($)’, namely
         ‘showString "MkD " . showsPrec 11 x’
       In the expression:
         showParen (p > 10) $ showString "MkD " . showsPrec 11 x
    |
 35 |     = showParen (p > 10) $ showString "MkD " . showsPrec 11 x
    |                                                ^^^^^^^^^^^^^^
 }}}

 GHC appears to be unable to conclude `Show (T a Int)` from `ShowT a Int`.
 But we can help guide GHC along manually by taking advantage of the ever-
 helpful `Dict` data type:

 {{{
 data Dict c =
   c => Dict

 showTDict :: forall a b. Dict (ShowT a b) -> Dict (Show (T a b))
 showTDict Dict = Dict
 }}}

 Using `showTDict`, we can make our `Show` instance for `D` compile with a
 pinch of pattern guards:

 {{{#!hs
 instance C a => Show (D a) where
   showsPrec p (MkD x)
     | Dict <- showTDict @a @Int Dict
     = showParen (p > 10) $ showString "MkD " . showsPrec 11 x
 }}}

 That's it! With enough persistence, we were able to finally realize
 edsko's dream in comment:18. Having to explicitly match on `Dict`s is a
 bit crude, granted, but this appears to be the best that we can do here at
 the moment.

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


More information about the ghc-tickets mailing list