
On Thu, Jul 23, 2009 at 10:55:59AM -0400, Patrick LeBoutillier wrote:
Hi,
I'm playing around with typeclasses and trying to a feel on how you implement "inheritance" (not sure if that's the good word here) in Haskell. I have the following code that doesn't compile:
class (Show a) => IPHost a where
class (Show a) => IPMask a where
class IPAddr a where host :: (IPHost b) => a -> b mask :: (IPMask b) => a -> b
showIPAddr :: (IPAddr a) => a -> String showIPAddr a = (show . host $ a) ++ "/" ++ (show . mask $ a)
ghci says:
Net/IP.hs:23:23: Ambiguous type variable `b' in the constraint: `IPHost b' arising from a use of `host' at Net/IP.hs:23:23-26 Probable fix: add a type signature that fixes these type variable(s)
Net/IP.hs:23:51: Ambiguous type variable `b1' in the constraint: `IPMask b1' arising from a use of `mask' at Net/IP.hs:23:51-54 Probable fix: add a type signature that fixes these type variable(s)
Think about what (show . host $ a) does. It takes 'a', converts it to... any type which is an instance of IPHost, and then shows that, turning it into a String. But there can be multiple types which are instances of IPHost, and each of them could have a *different* Show instance. So the exact String you get out depends on what type you pick... but there's no way for Haskell to infer which type to use. This is why it suggests to add a type signature. But I think there is probably some confusion that needs to be cleared up, the code you have doesn't quite make sense. Here are some questions to ask yourself: 1. Do you really want to be able to have multiple instances for IPHost and IPMask? (The answer might legitimately be 'yes', I'm just making sure.) What sorts of types do you have in mind that will be instances of these classes? 2. Do you really intend for the 'host' and 'mask' methods of the IPAddr class to be able to return *any* types which are instances of IPHost and IPMask, respectively? (This is what the code says right now.) This is actually impossible given that IPHost and IPMask have no methods. Or do you mean that for a given instance of IPAddr, the 'host' method (say) will return some *particular* type which happens to be an instance of IPHost, but which type is returned may differ between instances of IPAddr? If that's really what you mean, I would suggest either using a multi-parameter type class, like so: class (IPHost h, IPMask m) => IPAddr a h m where host :: a -> h mask :: a -> m OR using existential quantification to hide the particular types returned by 'host' and 'mask'. -Brent