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

This might be better answered at the haskell-cafe. Sending to cafe.
On 21 March 2015 at 03:09, Stuart Hungerford
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?
Thanks,
Stu _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
-- Regards Sumit Sahrawat

On Sat, Mar 21, 2015 at 8:37 PM, Sumit Sahrawat, Maths & Computing,
IIT (BHU)
This might be better answered at the haskell-cafe. Sending to cafe.
On 21 March 2015 at 03:09, Stuart Hungerford
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
-- Regards
Sumit Sahrawat
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

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

On Sat, Mar 21, 2015 at 7:31 PM, Chris Wong
[...] 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 [...]
If I also planned to have M instances like instance M Float Float where ... instance M Int Float where ... instance (M r g) => M r [g] where ... instance (M s u, M s v) => M s (u, v) where ... Which of the three approaches would make for the most idiomatic Haskell (add extra 'r' parameter, functional dependencies or associated types)? Is it common to require a range of language extension pragmas to make this kind of thing work or am I just going about this in a non-idiomatic way? Thanks, Stu
participants (3)
-
Chris Wong
-
Stuart Hungerford
-
Sumit Sahrawat, Maths & Computing, IIT (BHU)