
On Sat, Mar 21, 2015 at 7:31 PM, Chris Wong
[...]
check :: (Eq g, M r g) => g -> Bool check x = sca one x == x
The problem I have is that GHC is finding the "r" type variable in the "check" function ambiguous. Given my still limited Haskell knowledge I'm not surprised this is happening. What I would like to know is how experienced Haskellers handle this situation in practice: is there an idiomatic way of disambiguating "r" or is it a sign of poor type class design?
In the type signature:
check :: (Eq g, M r g) => g -> Bool
you fix the type `g`, but not the type `r`. This causes an ambiguity in the program because if you had e.g.
instance M Float Vector where ... instance M Int Vector where ...
both in the same program, and you passed a Vector to `check`, GHC won't know which instance to choose.
To solve this ambiguity, either fix `r` with an extra parameter:
check :: (Eq g, M r g) => r -> g -> Bool check one' x = sca one' x == x
Or declare that `r` is uniquely determined by `g` using a *functional dependency*:
class (R r, AG g) => M r g | g -> r where sca :: r -> g -> g
Or equivalently, using *associated types*:
class (AG g, R (Scalar g)) => M g where type Scalar g :: * sca :: Scalar g -> g -> g
check :: (Eq g, M g) => g -> Bool check x = -- as before
A Google search for these two terms should yield plenty of tutorials and examples.
Thanks for this excellent explanation.
(By the way, I'd suggest using longer names like "Ring" and "AdditiveGroup" instead, as they're easier to read.)
Yes -- I stripped the example down, including the full names of the type classes, for explaining the issue. I could well have left the full names though. Stu