TypeFamilies vs. FunctionalDependencies & type-level recursion

Dan Doel dan.doel at gmail.com
Tue Jun 14 18:31:47 CEST 2011

Sorry about the double send, David. I forgot to switch to reply-all in
the gmail interface.

On Tue, Jun 14, 2011 at 11:49 AM,
<dm-list-haskell-prime at scs.stanford.edu> wrote:
> You absolutely still can use FunctionalDependencies to determine type
> equality in GHC 7.  For example, I just verified the code below with
> GHC 7.02:
> *Main> typeEq True False
> HTrue
> *Main> typeEq (1 :: Int) (2 :: Int)
> HTrue
> *Main> typeEq (1 :: Int) False
> HFalse
> As always, you have to make sure one of the overlapping instances is
> more specific than the other, which you can do by substituting a
> parameter c for HFalse in the false case and fixing c to HFalse using
> another class like TypeCast in the context.  (As contexts play no role
> in instance selection, they don't make the instance any more
> specific.)
> While I don't have convenient access to GHC 6 right this second, I'm
> pretty sure there has been no change for a while, as the HList paper
> discussed this topic in 2004.

Okay. I don't really write a lot of code like this, so maybe I missed
the quirks.

In that case, HList has been relying on broken behavior of fundeps for
7 years. :) Because the instance:

   instance TypeEq a b c

violates the functional dependency, by declaring:

   instance TypeEq Int Int Int
   instance TypeEq Int Int Char
   instance TypeEq Int Int Double
   instance TypeEq Int Char Int
   instance TypeEq Int Char Char

and adding the constraint doesn't actually affect which instances are
being declared, it just adds a constraint requirement for when any of
the instances are used. It appears I was wrong, though. GHC doesn't
actually fix the instance for such fundeps, and the following compiles
and runs fine:

   class C a b | a -> b where
     foo :: a -> b
     foo = error "Yo dawg."

   instance C a b where

   bar :: Int
   bar = foo "x"

   baz :: Char
   baz = foo "x"

so we're using an instance C String Int and an instance C String Char
despite the fact that there's a functional dependency from the first
argument to the second.

-- Dan

More information about the Haskell-prime mailing list