Manuel M T Chakravarty wrote:
Ganesh Sittampalam:
The following program doesn't compile in latest GHC HEAD, although it does if I remove the signature on foo'.

{-# LANGUAGE TypeFamilies #-}
module Test7 where

type family Id a

type instance Id Int = Int

foo :: Id a -> Id a
foo = id

foo' :: Id a -> Id a
foo' = foo
Is this expected?

Yes, unfortunately, this is expected, although it is very unintuitive. This is for the following reason.

Huh? This sounds very wrong to me, simply because foo and foo' have the very same type.

Let's alpha-rename the signatures and use explicit foralls for clarity:

  foo  :: forall a. Id a -> Id a
  foo' :: forall b. Id b -> Id b

GHC will try to match (Id a) against (Id b). As Id is a type synonym family, it would *not* be valid to derive (a ~ b) from this. After all, Id could have the same result for different argument types. (That's not the case for your one instance, but maybe in another module, there are additional instances for Id, where that is the case.)

While in general (Id a ~ Id b) -/-> (a ~ b) , parametricity makes it "true" in the case of foo . For instance, let Id a ~ Int . Then, the signature specializes to foo :: Int -> Int . But due to parametricity, foo does not care at all what a is and will be the very same function for every a with Id a ~ Int . In other words, it's as if the type variable a is not in scope in the definition of foo .

Now, as GHC cannot show that a and b are the same, it can also not show that (Id a) and (Id b) are the same. It does look odd when you use the same type variable in both signatures, especially as Haskell allows you to leave out the quantifiers, but the 'a' in the signature of foo and the 'a' in the signatures of foo' are not the same thing; they just happen to have the same name.

Since both type variables are quantified, the types as a whole are the same, alpha conversion notwithstanding.

BTW, here is the equivalent problem using FDs:

  class IdC a b | a -> b
  instance IdC Int Int

  bar :: IdC a b => b -> b
  bar = id

  bar' :: IdC a b => b -> b
  bar' = bar

Hugs rejects bar as ambiguous whereas GHC accepts bar but rejects bar' . Something is wrong here. I think that only rejecting both definitions due to ambiguity is correct, since bar has access to a from the class. For instance, consider

   class C a b | a -> b
       fromA :: a -> b
       oneA  :: a

   instance C Int Int where
       fromA = const 1
       oneA  = 1

   instance C Char Int where
       fromA = const 2
       oneA  = 'a'

   bar :: C a b => b -> b
   bar _ = fromA oneA

This definition is clearly ambiguous,  bar  could be 1 or 2.


The subtle difference in the type synonym family case is that a is "more parametric" there. At least, that's my feeling.

In full System F , neither definition would be a problem since the type a is an explicit parameter.


Regards,
apfelmus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to