GADTs and functional dependencies

David Menendez dave at zednenem.com
Tue Sep 23 14:35:38 EDT 2008


On Tue, Sep 23, 2008 at 1:44 PM, Chris Kuklewicz
<haskell at list.mightyreason.com> wrote:
> You cannot create a normal function "fun".  You can make a type class
> function
>
> fun :: Class a b => GADT a -> b
>
>> data GADT a where
>>     GADT :: GADT ()
>>     GADT2 :: GADT String
>>
>> -- fun1 :: GADT () -> () -- infers type
>> fun1 g = case g of
>>           (GADT :: GADT ()) -> ()
>>
>> -- fun2 :: GADT String -> Bool -- infers type
>> fun2 g = case g of
>>           (GADT2 :: GADT String) -> True
>>
>> -- "fun" cannot type check.  The type of 'g' cannot be both "GADT ()" and
>> "GADT String"
>> -- This is because "fun" is not a member of type class.
>> {- fun g = case g of
>>           (GADT :: GADT ()) -> ()
>>           (GADT2 :: GADT String) -> True
>> -}

It may be that fun cannot type check, but surely it isn't for the
reason you've given.

data Rep a where
    Unit :: Rep ()
    Int :: Rep Int

zero :: Rep a -> a
zero r = case r of
    Unit -> ()
    Int -> 0

The type of r is "both" Rep () and Rep Int. No type class needed.

If I had to guess, I'd say the original problem is that any
specialization triggered by the functional dependency happens before
the specialization triggered by pattern matching on the GADT. If I
recall correctly, it is known that GADTs and fundeps don't always work
nicely together.

The example does seem to work if translated to use type families.

type family Fam t :: *
type instance Fam () = ()

data GADT a where
    GADT :: GADT ()

fun :: GADT a -> Fam a
fun GADT = ()

-- 
Dave Menendez <dave at zednenem.com>
<http://www.eyrie.org/~zednenem/>


More information about the Glasgow-haskell-users mailing list