[Haskell-cafe] instance deduction and phantom types

Ryan Ingram ryani.spam at gmail.com
Thu Aug 7 22:58:22 EDT 2008


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 <ryani.spam at gmail.com> 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 = ...
>
> 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 <dagit at codersbase.com>:
>> 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 at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>
>>
>


More information about the Haskell-Cafe mailing list