[Haskell-beginners] [Haskell-cafe] Multi-parameter type classes and ambiguous type variables...
Stuart Hungerford
stuart.hungerford at gmail.com
Sat Mar 21 20:15:52 UTC 2015
On Sat, Mar 21, 2015 at 7:31 PM, Chris Wong <lambda.fairy at gmail.com> wrote:
> [...]
>>> 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
More information about the Beginners
mailing list