[Haskell-cafe] [Haskell-beginners] Multi-parameter type classes and ambiguous type variables...

Chris Wong lambda.fairy at gmail.com
Sat Mar 21 08:31:23 UTC 2015


On Sat, Mar 21, 2015 at 8:37 PM, Sumit Sahrawat, Maths & Computing,
IIT (BHU) <sumit.sahrawat.apm13 at iitbhu.ac.in> wrote:
> This might be better answered at the haskell-cafe. Sending to cafe.
>
> On 21 March 2015 at 03:09, Stuart Hungerford <stuart.hungerford at gmail.com>
> wrote:
>>
>> Hi,
>>
>> As a learning exercise I'm modelling some algebraic structures as
>> Haskell typeclasses. Some of these are multi-parameter type classes.
>> Here's a very simplified version of the type class relationships:
>>
>> class MM a where
>>   one :: a
>>
>> class AM a where
>>   zero :: a
>>
>> class (AM a, MM a) => SR a
>>
>> class (AM a) => AG a where
>>   inv :: a -> a
>>
>> class (SR a) => R a where
>>   neg :: a -> a
>>
>> class (R r, AG g) => M r g where
>>   sca :: r -> g -> g
>>
>> 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.

(By the way, I'd suggest using longer names like "Ring" and
"AdditiveGroup" instead, as they're easier to read.)

Chris

>> Thanks,
>>
>> Stu
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
>
>
>
> --
> Regards
>
> Sumit Sahrawat
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>



-- 
https://lambda.xyz


More information about the Haskell-Cafe mailing list