
At Sat, 29 Sep 2012 19:49:36 +0200, Gábor Lehel wrote:
I was browsing the GHC bug tracker and accidentally might have found a solution to your problem:
Thanks, this makes me feel better. What interested me is not the workarounds, that I had already partly explored, but why the limitation is there in the first place. It turns out that it's because it'd add complexity and type families do it better. Fair enough.
Basically you have to make a type family to recapitulate the functional dependencies in the instances of Foo:
type family FooFD a
-- for each instance Foo A B, you have to write: -- type instance FooFD A = B
class Foo a (FooFD a) => Bar a where foo :: a -> FooFD a -> c
Anywhere you would use 'b', you use the type family instead.
The example in the ticket also had a 'b ~ FooFD a' superclass constraint on Foo itself, which you can't add if you don't control Foo, but I'm not sure what it's necessary for - in my brief tests removing it didn't cause problems.
A weakness of this approach is that you have to manually add a type instance for every instance of Foo, which may or may not be a problem in your situation.
I think this method, while useful to show the already shown relation between fundeps and type families, is pointless in reality. The most convenient method in practice, by far, is just to add the dependent part of the fundep explicitly to Bar. Along to the awkwardness you already pointed out of having to declare the family instance for each type, I'm introducing some unfamiliar and unnecessary type family to the user. It adds nothing but confusion. Not to mention that if I stick to fundeps I might hope to use my code with something else apart from GHC. -- Francesco * Often in error, never in doubt