The key issue at play here is a principle in haskell that writing additional instances should not change the operation of existing code. This increases the robustness of haskell code, as code won't break or have different behaviour if a module it depends on adds a new instance.
For this reason, when choosing possible instances to use for a type, Haskell does not consider the context of the instances. For example, when matching checking if a type will match the instance instance (Monad m, Num a) => Num (m a)
for the class Num
, it will only check if it can match m a
. This is because any type may later be made an instance of a class, and if instance choice used context information adding that instance would change the operation of existing programs.
For example, there is nothing stopping the following code being added either in your module, or in a module you depend on:
instance Monad Ratio where
return = undefined
(>>=) = undefined
Sure, such an instance is useless, but haskell has no way of judging that. It also is possible that there is a useful definition of Monad
for Ratio
(I haven't looked into that).
In summary, what you are trying to do isn't a good idea. You can stop these limitations using OverlappingInstances
and IncoherentInstances
, however for the reasons described above these flags are not recommended for mainstream use by most haskell programmers.