Resolving ambiguous instance for multiparam type class
ghc, haskell
Solution
You can use functional dependencies to specify that "`ret` is uniquely determined by `a` and `b`".
...
{-# LANGUAGE FunctionalDependencies #-}
...
class MyNum a b ret | a b -> ret where
...
This lets the typechecker know that it can pick the correct instance definition, knowing only the `a` and `b` from the arguments in your:
myLessThan (NamedList n l) x = myLessThan l x
The compiler will now complain if you define an additional instance with the same `a` and `b` but a different `ret`, such as
instance MyNum MyList Double SomeOtherType where
Problem
I'm developing a specialized numerical data processing library, and I've come across an error that I can't figure out how to fix. I think it'll be easier to show an example first and then explain my problem. I also apologize for the strange names, I'm having to obfuscate for legal purposes. ``` {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} data MyError = MyError String deriving (Eq, Show) data MyList = MyList [Double] deriving (Eq, Show) data NamedList = NamedList String MyList deriving (Eq, Show) class MyNum a b ret where myAdd :: a -> b -> Either MyError ret myLessThan :: a -> b -> Either MyError Bool instance MyNum MyList Double MyList where myAdd (MyList xs) x = Right $ MyList $ map (+x) xs myLessThan (MyList xs) x = Right $ all (< x) xs instance MyNum NamedList Double NamedList where myAdd (NamedList n l) x = fmap (NamedList n) $ myAdd l x myLessThan (NamedList n l) x = myLessThan l x ``` If I try to compile this, I get the error ``` No instance for (MyNum MyList Double ret0) arising from a use of `myLessThan' The type variable `ret0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there is a potential instance available: instance MyNum MyList Double MyList -- Defined at testing_instances.hs:13:10 Possible fix: add an instance declaration for (MyNum MyList Double ret0) In the expression: myLessThan l x In an equation for `myLessThan': myLessThan (NamedList n l) x = myLessThan l x In the instance declaration for `MyNum NamedList Double NamedList' ``` Because the compiler can't figure out which specific instance of `MyNum` to use for `MyList`. It works for `myAdd` because the return type for `MyNum` is easily derived, but it can't figure it out for `myLessThan`. I want to use this typeclass so that I can easily add fine-grained error handling throughout, and because my actual code has the equivalent of +, -, *, /, <, <=, >, and >=, and I want to make an instance for `MyNum Double MyList MyList`, `MyNum MyList MyList MyList`, and similar ones for `NamedList`. Unless there's an easier way to do this, it's so that I can have polymorphic commutative operators. However, I can't figure out what type signature to add to `myLessThan` for the second instance so that it can know which instance to use. I know one solution would be to split the arithmetic and comparison operators into two separate type classes, but I would like to avoid doing so if at all possible.