A typical consequence of combining FunDeps + Overlapping instances is that you have to make the result parameter more general than it needs be, then use a TypeCast constraint to improve it.
... TypeCast, which does use FunDeps to mutually improve/unify its two parameters. Nowadays in GHC you'd use the (~) constraint.
I got so fed up writing out TypeCast constraints; and I'm so used to writing infix (~) in GHC, I implemented (~) in Hugs. This is hard-coded syntax in constraints; I've not implemented type operators. (Mark you, it's also hard-coded in GHC, because (~) is a reserved symbol.)
This needed only changes to the yacc syntax. From that I insisted that "~" is a legitimate name for a class. There is a downside that equality constraints are printed with the '~' prefix -- because all class names are prefix.
To be clear: this is not as powerful or well-integrated as (~) in GHC. You still need at the term level to explicitly cast.
Then I got so fed up writing out explicit typeCast calls ..., I picked up the postfix operators idea
and invented a postfix operator (~::) to do the job.
Trailing double-colon says I'm doing something typeful; tilde connects it to the equality constraint.
Then here's the classic, compiled in Hugs, also exhibiting the FunDeps + Overlaps combo
class TypeEq t t' r | t t' -> r where
typeEq :: t -> t' -> r
instance TypeEq t t TTrue where
typeEq _ _ = TTrue
instance (TFalse ~ f) => TypeEq t t' f where
typeEq _ _ = (TFalse ~::) -- without explicit cast, complains type is not general enough
AntC