[GHC] #14883: QuantifiedConstraints don't kick in when used in TypeApplications

GHC ghc-devs at haskell.org
Sat Mar 3 03:10:54 UTC 2018


#14883: QuantifiedConstraints don't kick in when used in TypeApplications
-------------------------------------+-------------------------------------
           Reporter:  RyanGlScott    |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.5
  (Type checker)                     |
           Keywords:                 |  Operating System:  Unknown/Multiple
  QuantifiedConstraints, wipT2893    |
       Architecture:                 |   Type of failure:  GHC rejects
  Unknown/Multiple                   |  valid program
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 Consider the following program:

 {{{#!hs
 {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE ImpredicativeTypes #-}
 {-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE QuantifiedConstraints #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 module Bug where

 import Data.Coerce
 import Data.Kind

 type Representational1 m = (forall a b. Coercible a b => Coercible (m a)
 (m b) :: Constraint)

 class Representational1 f => Functor' f where
   fmap' :: (a -> b) -> f a -> f b

 class Functor' f => Applicative' f where
   pure'  :: a -> f a
   (<*>@) :: f (a -> b) -> f a -> f b

 class Functor' t => Traversable' t where
   traverse' :: Applicative' f => (a -> f b) -> t a -> f (t b)

 -- Typechecks
 newtype T1 m a = MkT1 (m a) deriving Functor'
 instance Traversable' m => Traversable' (T1 m) where
   traverse' :: forall f a b. (Applicative' f) => (a -> f b) -> T1 m a -> f
 (T1 m b)
   traverse' = coerce @((a -> f b) ->    m a -> f    (m b))
                      @((a -> f b) -> T1 m a -> f (T1 m b))
                      traverse'

 -- Doesn't typecheck
 newtype T2 m a = MkT2 (m a) deriving Functor'
 instance Traversable' m => Traversable' (T2 m) where
   traverse' = coerce @(forall f a b. Applicative' f => (a -> f b) ->    m
 a -> f    (m b))
                      @(forall f a b. Applicative' f => (a -> f b) -> T2 m
 a -> f (T2 m b))
                      traverse'
 }}}

 This defines a variant of `Functor` that has `forall a b. Coercible a b.
 Coercible (m a) (m b)` as a superclass, and also defines versions of
 `Applicative` and `Traversable` that use this `Functor` variant. This is
 towards the ultimate goal of defining `Traversable'` à la
 `GeneralizedNewtypeDeriving`.

 This attempt (using `InstanceSigs`) typechecks:

 {{{#!hs
 newtype T1 m a = MkT1 (m a) deriving Functor'
 instance Traversable' m => Traversable' (T1 m) where
   traverse' :: forall f a b. (Applicative' f) => (a -> f b) -> T1 m a -> f
 (T1 m b)
   traverse' = coerce @((a -> f b) ->    m a -> f    (m b))
                      @((a -> f b) -> T1 m a -> f (T1 m b))
                      traverse'
 }}}

 However, this version (which is closer to what
 `GeneralizedNewtypeDeriving` would actually create) does //not//
 typecheck:

 {{{#!hs
 newtype T2 m a = MkT2 (m a) deriving Functor'
 instance Traversable' m => Traversable' (T2 m) where
   traverse' = coerce @(forall f a b. Applicative' f => (a -> f b) ->    m
 a -> f    (m b))
                      @(forall f a b. Applicative' f => (a -> f b) -> T2 m
 a -> f (T2 m b))
                      traverse'
 }}}
 {{{
 $ ghc-cq/inplace/bin/ghc-stage2 --interactive Bug.hs
 GHCi, version 8.5.20180128: http://www.haskell.org/ghc/  :? for help
 Loaded GHCi configuration from /home/rgscott/.ghci
 [1 of 1] Compiling Bug              ( Bug.hs, interpreted )

 Bug.hs:38:15: error:
     • Couldn't match representation of type ‘f1 (m b1)’
                                with that of ‘f1 (T2 m b1)’
         arising from a use of ‘coerce’
       NB: We cannot know what roles the parameters to ‘f1’ have;
         we must assume that the role is nominal
     • In the expression:
         coerce
           @(forall f a b. Applicative' f => (a -> f b) -> m a -> f (m b))
           @(forall f a b.
             Applicative' f => (a -> f b) -> T2 m a -> f (T2 m b))
           traverse'
       In an equation for ‘traverse'’:
           traverse'
             = coerce
                 @(forall f a b. Applicative' f => (a -> f b) -> m a -> f
 (m b))
                 @(forall f a b.
                   Applicative' f => (a -> f b) -> T2 m a -> f (T2 m b))
                 traverse'
       In the instance declaration for ‘Traversable' (T2 m)’
     • Relevant bindings include
         traverse' :: (a -> f b) -> T2 m a -> f (T2 m b)
           (bound at Bug.hs:38:3)
    |
 38 |   traverse' = coerce @(forall f a b. Applicative' f => (a -> f b) ->
 m a -> f    (m b))
    |
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
 }}}

 Shouldn't it, though? These instance declarations out to be equivalent
 (morally, at least).

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


More information about the ghc-tickets mailing list