instance deduction and phantom types

Hello, I recently had a problem where GHC couldn't deduce some type classes from my constraints. I would get error messages like: Could not deduce (Conflict (PatchInfoAnd p), Patchy (PatchInfoAnd p)) from the context (RepoPatch p) But, I had some instances like this (minus the function definitions): class (Patchy p, Effect p, FromPrims p, Conflict p) => RepoPatch p instance Effect p => Effect (PatchInfoAnd p) instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y)) instance RepoPatch (p x y) => Patchy (PatchInfoAnd (p x y)) The x and y in the last two are just phantom types on p. When I noticed that the phantom types were missing from the instance definition of Effect (PatchInfoAnd p), I removed them from the last two definitions. This made the "Could not deduce..." error message disappear. Why do the phantom types not belong in the instance definition? I'd like to understand the problem more fully, but I'm not sure what the problem is or how to get started researching it, so if someone could point me in the right direction I'd be very happy! Thanks! Jason

I'm just guessing from this email; I can't see your code. Let me know if I go wrong anywhere. It looks like you expect your patches to be some type (p :: * -> * -> *); that is, a type like
data Patch x y = ...
So I suspect you defined your classes like so:
class Conflict p where hasConflict :: p x y -> Bool
However, the instance declaration:
instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y))
is referring to ANY types p :: * -> * -> * -> * -> * x :: * y :: * so that (p x y :: * -> * -> *); that is, a type like this:
data PatchBroken a b x y = ...
in this case an instance for Conflict (PatchBroken Int Bool) would
give instances for Conflict (PatchInfoAnd (PatchBroken Int Bool)).
You see, there's no way for the instance declaration for Conflict to
apply from your context (RepoPatch p); in fact, it can't possibly
match, because the "p" in RepoPatch p has kind * -> * -> *, whereas
the "p" in the instance declaration has kind * -> * -> * -> * -> *.
You just had useless instance declarations that would never trigger.
By removing the extra "x y" that were not expected to be there, you
fixed the code to match your actual intent, and the compiler was able
to derive the proper typeclass memberships.
-- ryan
2008/8/7 Jason Dagit
Hello,
I recently had a problem where GHC couldn't deduce some type classes from my constraints. I would get error messages like: Could not deduce (Conflict (PatchInfoAnd p), Patchy (PatchInfoAnd p)) from the context (RepoPatch p)
But, I had some instances like this (minus the function definitions): class (Patchy p, Effect p, FromPrims p, Conflict p) => RepoPatch p
instance Effect p => Effect (PatchInfoAnd p)
instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y))
instance RepoPatch (p x y) => Patchy (PatchInfoAnd (p x y))
The x and y in the last two are just phantom types on p. When I noticed that the phantom types were missing from the instance definition of Effect (PatchInfoAnd p), I removed them from the last two definitions. This made the "Could not deduce..." error message disappear.
Why do the phantom types not belong in the instance definition? I'd like to understand the problem more fully, but I'm not sure what the problem is or how to get started researching it, so if someone could point me in the right direction I'd be very happy!
Thanks! Jason
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Also, you may find it helpful to add
{-# LANGUAGE KindSignatures #-}
to the top of your program, and start annotating your class and instance declarations for clarity:
class Conflict (p :: * -> * -> *) where hasConflict :: p x y -> Bool
The compiler has been doing kind inference where necessary to figure this out; for example, the declaration I just gave shows that p must have kind (* -> * -> *) because "p x y" is a function argument and only concrete types of kind * can be used as function arguments. If you don't specify and the compiler can't determine otherwise, it assumes you mean kind "*"; so if you had a typeclass with no functions:
class Demo a
"a :: *" is assumed. The KindSignatures extension allows you to explicitly override this when needed:
class Demo2 (a :: (* -> *) -> * -> *) instance Demo2 (ReaderT r)
-- ryan
On Thu, Aug 7, 2008 at 7:51 PM, Ryan Ingram
I'm just guessing from this email; I can't see your code. Let me know if I go wrong anywhere.
It looks like you expect your patches to be some type (p :: * -> * -> *); that is, a type like
data Patch x y = ...
So I suspect you defined your classes like so:
class Conflict p where hasConflict :: p x y -> Bool
However, the instance declaration:
instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y))
is referring to ANY types p :: * -> * -> * -> * -> * x :: * y :: * so that (p x y :: * -> * -> *); that is, a type like this:
data PatchBroken a b x y = ...
in this case an instance for Conflict (PatchBroken Int Bool) would give instances for Conflict (PatchInfoAnd (PatchBroken Int Bool)).
You see, there's no way for the instance declaration for Conflict to apply from your context (RepoPatch p); in fact, it can't possibly match, because the "p" in RepoPatch p has kind * -> * -> *, whereas the "p" in the instance declaration has kind * -> * -> * -> * -> *.
You just had useless instance declarations that would never trigger. By removing the extra "x y" that were not expected to be there, you fixed the code to match your actual intent, and the compiler was able to derive the proper typeclass memberships.
-- ryan
2008/8/7 Jason Dagit
: Hello,
I recently had a problem where GHC couldn't deduce some type classes from my constraints. I would get error messages like: Could not deduce (Conflict (PatchInfoAnd p), Patchy (PatchInfoAnd p)) from the context (RepoPatch p)
But, I had some instances like this (minus the function definitions): class (Patchy p, Effect p, FromPrims p, Conflict p) => RepoPatch p
instance Effect p => Effect (PatchInfoAnd p)
instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y))
instance RepoPatch (p x y) => Patchy (PatchInfoAnd (p x y))
The x and y in the last two are just phantom types on p. When I noticed that the phantom types were missing from the instance definition of Effect (PatchInfoAnd p), I removed them from the last two definitions. This made the "Could not deduce..." error message disappear.
Why do the phantom types not belong in the instance definition? I'd like to understand the problem more fully, but I'm not sure what the problem is or how to get started researching it, so if someone could point me in the right direction I'd be very happy!
Thanks! Jason
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thank you for the quick response. It's very helpful and makes perfect sense
now.
On Thu, Aug 7, 2008 at 7:58 PM, Ryan Ingram
Also, you may find it helpful to add
{-# LANGUAGE KindSignatures #-}
to the top of your program, and start annotating your class and instance declarations for clarity:
class Conflict (p :: * -> * -> *) where hasConflict :: p x y -> Bool
Ah, yes we do that sometimes, but not with consistency.
On Thu, Aug 7, 2008 at 7:51 PM, Ryan Ingram
wrote: I'm just guessing from this email; I can't see your code. Let me know if I go wrong anywhere.
It looks like you expect your patches to be some type (p :: * -> * -> *); that is, a type like
data Patch x y = ...
Yes, that's right and sorry for not including Patch.
However, the instance declaration:
instance Conflict (p x y) => Conflict (PatchInfoAnd (p x y))
is referring to ANY types p :: * -> * -> * -> * -> * x :: * y :: * so that (p x y :: * -> * -> *); that is, a type like this:
data PatchBroken a b x y = ...
in this case an instance for Conflict (PatchBroken Int Bool) would give instances for Conflict (PatchInfoAnd (PatchBroken Int Bool)).
That makes perfect sense. So, by including x and y in the instance I was dramatically changing the kind inference. That didn't occur to me earlier, but it does make sense. Thanks! Jason
participants (2)
-
Jason Dagit
-
Ryan Ingram