Skip to content

GADT Constraint breaks type inference

The following code compiles:

{-# LANGUAGE TypeFamilies,
             MultiParamTypeClasses, GADTs #-}

module Foo () where

class (Num src, Num tgt) => Bar src tgt where
  bar :: (tgt, src)

type family Type a

data CT :: (* -> * -> *) where
  CT :: --(Type rp ~ Type rq) =>
        rp -> rq -> CT rp rq

foo :: (Bar rp rq) => CT rp rq -> CT rp rq
foo = let (b', a') = bar
      in \(CT a b) -> CT (a * a') (b * b')

But when I add the [totally irrelevant] constraint to the GADT, foo no longer compiles:

Foo.hs:16:22:
    Could not deduce (Bar t1 t0) arising from a use of ‘bar’
    from the context (Bar rp rq)
      bound by the type signature for
                 foo :: Bar rp rq => CT rp rq -> CT rp rq
      at testsuite/Foo.hs:15:8-42
    The type variables ‘t0’, ‘t1’ are ambiguous
    Relevant bindings include
      b' :: t0 (bound at Foo.hs:16:12)
      a' :: t1 (bound at Foo.hs:16:16)
    In the expression: bar
    In a pattern binding: (b', a') = bar
    In the expression:
      let (b', a') = bar in \ (CT a b) -> CT (a * a') (b * b')

Foo.hs:17:31:
    Couldn't match expected type ‘rp’ with actual type ‘t1’
      ‘t1’ is untouchable
        inside the constraints (Type rp ~ Type rq)
        bound by a pattern with constructor
                   CT :: forall rp rq. Type rp ~ Type rq => rp -> rq -> CT rp rq,
                 in a lambda abstraction
        at Foo.hs:17:12-17
      ‘rp’ is a rigid type variable bound by
           the type signature for foo :: Bar rp rq => CT rp rq -> CT rp rq
           at testsuite/Foo.hs:15:8
    Relevant bindings include
      a :: rp (bound at Foo.hs:17:15)
      a' :: t1 (bound at Foo.hs:16:16)
      foo :: CT rp rq -> CT rp rq (bound at Foo.hs:16:1)
    In the second argument of ‘(*)’, namely ‘a'’
    In the first argument of ‘CT’, namely ‘(a * a')’

Foo.hs:17:40:
    Couldn't match expected type ‘rq’ with actual type ‘t0’
      ‘t0’ is untouchable
        inside the constraints (Type rp ~ Type rq)
        bound by a pattern with constructor
                   CT :: forall rp rq. Type rp ~ Type rq => rp -> rq -> CT rp rq,
                 in a lambda abstraction
        at Foo.hs:17:12-17
      ‘rq’ is a rigid type variable bound by
           the type signature for foo :: Bar rp rq => CT rp rq -> CT rp rq
           at Foo.hs:15:8
    Relevant bindings include
      b :: rq (bound at Foo.hs:17:17)
      b' :: t0 (bound at Foo.hs:16:12)
      foo :: CT rp rq -> CT rp rq (bound at Foo.hs:16:1)
    In the second argument of ‘(*)’, namely ‘b'’
    In the second argument of ‘CT’, namely ‘(b * b')’

The errors can be fixed using -XScopedTypeVariables and changing foo to:

foo :: forall rp rq . (Bar rp rq) => CT rp rq -> CT rp rq
foo = let (b' :: rq, a' :: rp) = bar
      in \(CT a b) -> CT (a * a') (b * b')

Why should I need an explicit type on bar, when the type can be inferred from its use in foo (as it was before the GADT constraint was added)? Is that expected behavior for GADTs?

Trac metadata
Trac field Value
Version 7.8.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information