> > Is it possible to set up classes that express the following (using
> > ghc extensions)?
>
> I hoped that the following would work (with -fglasgow-exts
> -fallow-overlapping-instances -fallow-undecidable-instances)
> but it does not choose the instance of SubsetOfPoint I want.
I'm not quite sure what you are trying to do, but I can tell you
what is going on. It's a nice example of how overlapping instances
can trip you up.
> class Shape a where
> subset :: Shape b => b -> a -> Bool
>
> class SubsetOfPoint a where
> subsetOfPoint :: a -> Point -> Bool
>
> data Point = Point Double Double
>
> instance Shape Point where
> subset = subsetOfPoint
When type checking this instance declaration, the compiler
has to ensure that the RHS has type
forall b. Shape b => b -> Point -> Bool
because that is what the class Shape says it must have.
So, does the RHS have this type? We take subsetOfPoint and
instantiate its type to get the type
SubsetOfPoint => b -> Point -> Bool
Aha. So we have Shape b, but we need SubsetOfPoint b. Can we solve
this? Yes, because you also provided the instance declaration:
> instance Shape a => SubsetOfPoint a where
> subsetOfPoint _ _ = False -- Generic version if the
> -- specialized one is
> -- not defined.
So right in the instance declaration for Shape Point the
compiler is forced to choose the SubsetOfPoint a instance
in order to get a SubsetOfPoint dictionary from the
Shape dictionary it has available.
If you made the declaration for Shape like this:
> class Shape a where
> subset :: SubsetOfPoint b => b -> a -> Bool
then this premature choice wouldn't happen. Likewise,
if you said
> class SubsetOfPoint a => Shape a where
> subset :: a -> a -> Bool
you'd be ok.
Bottom line: if you have overlapping instances it matters
very much exactly when the compiler does context reduction.
That is why they are hard to reason about. See our paper "Type classes:
exploring the design space", available from
http://research.microsoft.com/~simonpj
Simon