My mental model of instance heads is they're type-level pattern matching, with binding of tyvars like binding of variables. With FlexibleInstances
you can repeat tyvars in instance heads. But you can't do that at term level. Consider
class (Eq a, Eq b) => C a b where
foo :: a -> b -> String
instance C a a where -- repeated `a'
-- the args are same type so we can compare them
foo ... = "equal" -- see below
foo _x _y = "not equal"
instance {-# OVERLAPPABLE #-} C a b where
foo _ _ = "not comparable"
For that "equal"
case, I'd like to write
foo x x = "equal"
But repeated variables aren't allowed in patterns: rejected Conflicting definitions for 'x'
. And that's because each variable must get uniquely bound to the arguments to foo
then we can reference them. Instead go
foo x y | x == y = "equal"
So how come the repeated tyvar business works for instances? In instance C a a
, which of the a
s is the binding site, which the referencing site? Is the compiler under the covers doing something equivalent to binding to differently named tyvars then applying a guard?