Wen using functional dependencies, I frequently hit the Coverage Condition. It is possible to lift it with UndecidableInstances
, but I usually try to stay away from that extension.
Here is a somewhat contrived example, that works without UndecidableInstances
:
{-# Language MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
data Result = Result String
deriving (Eq, Show)
data Arguments a b = Arguments a b
class Applyable a b | a -> b where
apply :: a -> b -> Result
instance Applyable (Arguments a b) (a -> b -> Result) where
(Arguments a b) `apply` f = f a b
When I make the result type more generic, the Coverage Condition fails (hence requiring UndecidableInstances
):
{-# Language MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
data Result a = Result a
deriving (Eq, Show)
data Arguments a b = Arguments a b
class Applyable a b c | a -> b c where
apply :: a -> b -> Result c
instance Applyable (Arguments a b) (a -> b -> Result c) c where
(Arguments a b) `apply` f = f a b
I thought that because b
and c
are both determined by a
, the more generic code should not cause any problems, so my questions:
UndecidableInstances
hereUndecidableInstances
(maybe with type families?)There's no big reason to stay away from UndecidableInstances
. The worst that can happen is that the type checker starts looping (and tells you about it, I think). You can make the coverage condition more and more clever, but it will never do everything you could want since that's undecidable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With