When is UndecidableInstances safe? Some general questions regarding the GHC extension
I know of the documentation for -XUndecidableInstances, but I thought I'd ask for an elaboration.
Suppose I have two multi-parameter typeclasses (allowed with -XMultiParamTypeClasses)
class Foo a b
class Goo a b
Now, suppose I have a parameterized data type
data Bar a b
which I want to make an instance of Foo
when one of its parameters is part of an instance of Goo
. I'm not sure the previous sentence uses exact terminology, so here's what I want to write:
instance (Goo c d) => Foo d (Bar a d)
I'm not allowed to without the UndecidableInstances
extension. Am I correct in thinking this is because the instance doesn't refer to the c
type?
Should I...
- Just enable the extension? Can somebody elaborate on what kinds of trouble it can get me into?
- Add another parameter to
Foo
, so that the last instance declaration becomes something likeFoo c d (Bar a d)
? A problem with this is that I might have other instances ofFoo
that never make any reference to any such "fourth type parameter" (i.e. there are instances of the forminstance开发者_开发知识库 Foo A B
in unrelated parts of my code), so these would break. I'd rather fix my instance, not my class. - Create a new class
FooGoo
with enough parameters? I would feel like I'm repeating myself in that case, but at least I wouldn't break unrelated classes.
Does anyone have any words of wisdom?
Am I correct in thinking this is because the instance doesn't refer to the c type?
Yes, your code does not adhere to (from here):
For each assertion in the context: No type variable has more occurrences in the assertion than in the head
In general, you should be safe unless you add other instances that would, together, form a loop. Things only get really hairy (and compiler-dependent) when it comes to OverlappingInstances
, and rightout evil when you go IncoherentInstances
.
Without knowing more about what you're trying to accomplish it's hard to give sound design advice, but the first thing to check is whether you really, really need to have c as a parameter to Goo. You might be able to do express what you want to accomplish like this:
class Goo d where
bar :: d c -> Int
baz :: Quux c => d c -> Int
精彩评论