[Haskell-beginners] Typeclasses and "inheritance"

Brent Yorgey byorgey at seas.upenn.edu
Thu Jul 23 11:42:42 EDT 2009


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


More information about the Beginners mailing list