[Haskell-cafe] Type family signatures
Thomas van Noort
thomas at cs.ru.nl
Wed Aug 19 05:08:34 EDT 2009
Thank your for this elaborate explanation, you made my day!
Thomas
Ryan Ingram wrote:
> On Mon, Aug 17, 2009 at 12:12 AM, Thomas van Noort<thomas at cs.ru.nl> wrote:
>> Somehow I didn't receive David's mail, but his explanation makes a lot of
>> sense. I'm still wondering how this results in a type error involving rigid
>> type variables.
>
> "rigid" type means the type has been specified by the programmer somehow.
>
> Desugaring your code a bit, we get:
>
> GADT :: forall a b. (b ~ Fam a) => a -> b -> GADT b
>
> Notice that this is an existential type that partially hides "a"; all
> we know about "a" after unwrapping this type is that (Fam a ~ b).
>
> unwrap :: forall a b. (b ~ Fam a) => GADT b -> (a,b)
> unwrap (GADT x y) = (x,y)
>
> So, the type signature of unwrap fixes "a" and "b" to be supplied by
> the caller. Then the pattern match on GADT needs a type variable for
> the existential, so a new "a1" is invented. These are rigid because
> they cannot be further refined by the typechecker; the typechecker
> cannot unify them with other types, like "a1 ~ Int", or "a1 ~ a".
>
> An example of a non-rigid variable occurs type-checking this expression:
>
> foo x = x + (1 :: Int)
>
> During type-checking/inference, there is a point where the type environment is:
>
> (+) :: forall a. Num a => a -> a -> a
>
> b :: *, non-rigid
> x :: b
>
> c :: *, non-rigid
> foo :: b -> c
>
> Then (+) gets instantiated at Int and forces "b" and "c" to be Int.
>
> In your case, during the typechecking of unwrap, we have:
>
> unwrap :: forall a b. (b ~ Fam a) => GADT b -> (a,b)
> a :: *, rigid
> b :: *, rigid
> (b ~ Fam a)
>
> -- From the pattern match on GADT:
> a1 :: *, rigid
> x :: a1
> y :: b
> (b ~ Fam a1)
>
> Now the typechecker wants to unify "a" and "a1", and it cannot,
> because they are rigid. If one of them was still open, we could unify
> it with the other.
>
> The type equalities give us (Fam a ~ Fam a1), but that does not give
> us (a ~ a1). If Fam was a data type or data family, we would know it
> is injective and be able to derive (a ~ a1), but it is a type family,
> so we are stuck.
>
> -- ryan
More information about the Haskell-Cafe
mailing list