Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Typeclasses and "inheritance" (Patrick LeBoutillier)
2. Re: Typeclasses and "inheritance" (Brent Yorgey)
3. Re: Typeclasses and "inheritance" (Chadda? Fouch?)
4. Re: Typeclasses and "inheritance" (Patrick LeBoutillier)
5. Re: Typeclasses and "inheritance" (Chadda? Fouch?)
----------------------------------------------------------------------
Message: 1
Date: Thu, 23 Jul 2009 10:55:59 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: [Haskell-beginners] Typeclasses and "inheritance"
To: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
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)
What exactly does this error mean in this case? It's no tclear to me what
needs to be made more specific. Am I approaching the problem in the wrong
way?
Any help is appreciated.
Thanks,
Patrick
--
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090723/c8c254d4/attachment-0001.html
------------------------------
Message: 2
Date: Thu, 23 Jul 2009 11:42:42 -0400
From: Brent Yorgey <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses and "inheritance"
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
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
------------------------------
Message: 3
Date: Thu, 23 Jul 2009 17:52:18 +0200
From: Chadda? Fouch? <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses and "inheritance"
To: Patrick LeBoutillier <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=UTF-8
On Thu, Jul 23, 2009 at 4:55 PM, Patrick
LeBoutillier<[email protected]> 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.
We don't do "inheritance" in Haskell (though you can simulate it
thanks to the power of the type system you generally don't need to as
there is often a more natural solution with the other features of the
type system). It would be more usefull if you could describe what you
want to do in general and why you think you need inheritance for it.
>
> class (Show a) => IPHost a where
>
> class (Show a) => IPMask a where
>
Those class are basically synonyms of Show, is that intentional (and
really useful ?) or do you think you'll add some other functions in
there ?
> class IPAddr a where
> Â host :: (IPHost b) => a -> b
> Â mask :: (IPMask b) => a -> b
This definition basically say that for a given instance a of IPAddr
host can return any type that is an instance of IPHost, it so happen
that with what we saw from your code so far this means that you can't
write instances of IPAddr (since there are no function in IPHost and a
typeclass is open)... so I somehow doubt that was what you wanted to
say.
Probably you wanted something like :
> class (IPHost (Host a), IPMask (Mask a)) => IPAddr a where
> type Host a
> type Mask a
> host :: a -> Host a
> mask :: a -> Mask a
Now each instance of IPAddr will associate two type to the instancied
type, one that will be an instance of IPHost and one of IPMask.
And this function will compile :
>
> showIPAddr :: (IPAddr a) => a -> String
> showIPAddr a = (show . host $ a) ++ "/" ++ (show . mask $ a)
>
I'm equally pretty sure that's not really what you want, but without
more details I can't help much more.
--
Jedaï
------------------------------
Message: 4
Date: Thu, 23 Jul 2009 12:34:18 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses and "inheritance"
To: Brent Yorgey <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
Hi Brent,
> 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?
Yes. Basically my goal was to have something like:
data IPv4Host = IPv4Host Word32
deriving (Show)
instance IPHost IPv4Host where
data IPv4Mask = IPv4Mask Word32
deriving (Show)
instance IPMask IPv4Mask where
data IPv4Addr = IPv4Addr IPv4Host IPv4Mask
instance IPAddr IPv4Addr where
and the equivalent for IPv6 (to be implemented later when I fugre out how to
do it...)
>
>
> 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?
Yes! That's exactly what I want (and yes there will be methods eventually in
those classes)
> 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
Ok... So I guess the instance declaration for IPv4Addr will then become
this:
instance IPAddr IPv4Addr IPv4Host IPv4Mask where
but how do I adjust the showIPAddr function to deal with that? I tried this:
showIPAddr :: (IPAddr a h m) => a -> String
but something is still missing, I get:
Could not deduce (IPAddr a b m) from the context (IPAddr a h1 m1)
arising from a use of `host' at IP.hs:23:23-26
Possible fix:
add (IPAddr a b m) to the context of
the type signature for `showIPAddr'
In the second argument of `(.)', namely `host'
In the first argument of `($)', namely `show . host'
In the first argument of `(++)', namely `(show . host $ a)'
Thanks a lot,
Patrick
>
>
> OR using existential quantification to hide the particular types
> returned by 'host' and 'mask'.
>
> -Brent
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
--
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090723/119d66fc/attachment-0001.html
------------------------------
Message: 5
Date: Thu, 23 Jul 2009 22:18:12 +0200
From: Chadda? Fouch? <[email protected]>
Subject: Re: [Haskell-beginners] Typeclasses and "inheritance"
To: Patrick LeBoutillier <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=UTF-8
On Thu, Jul 23, 2009 at 6:34 PM, Patrick
LeBoutillier<[email protected]> wrote:
> Â Â showIPAddr :: (IPAddr a h m) => a -> String
>
> but something is still missing, I get:
>
> Â Â Â Could not deduce (IPAddr a b m) from the context (IPAddr a h1 m1)
> Â Â Â Â Â arising from a use of `host' at IP.hs:23:23-26
> Â Â Â Possible fix:
> Â Â Â Â Â add (IPAddr a b m) to the context of
> Â Â Â Â Â Â Â the type signature for `showIPAddr'
> Â Â Â In the second argument of `(.)', namely `host'
> Â Â Â In the first argument of `($)', namely `show . host'
> Â Â Â In the first argument of `(++)', namely `(show . host $ a)'
It's more or less the same problem as before : there may be several
instance of IPAddr for the same a (typeclass are open, so the fact
that there is only one such instance in your module is not relevant)
and only a appears in the context of your function, so h and m aren't
sufficiently determined, it's still ambiguous (if there are several
instance for the a you passed, Haskell has no idea how to choose one,
and this choice could change the output).
There are several solutions to this problem, one was called functional
dependencies :
> class (IPHost h, IPMask m) => IPAddr a h m | a -> h m where
> host :: a -> h
> mask :: a -> m
That basically say that for a given a, there is only one instance :
the choice of a determine h and m. So you guarantee to Haskell you
won't write several instance with the same a (it would protest if you
tried to).
The other, recently added in GHC, is called type family, it's an open
type function (from a type to a type), that's the solution I showed
you :
> class (IPHost (Host a), IPMask (Mask a)) => IPAddr a where
> type Host a
> type Mask a
> host :: a -> Host a
> mask :: a -> Mask a
Host and Mask are type families, type functions.
In your case I believe this solution is probably more natural since
your class really has only one parameter, a, adding others to make it
compile is pretty much a hack. There are other situations where
functional dependencies are still more natural, or work better (both
solution are deemed equivalent but there are subtle implementation
differences and their semantics is often more adapted to some case,
besides type (or data) families are pretty recent, though they works
pretty well in 6.10, they're still evolving and being refined).
Your instance would look like that :
> instance IPAddr IPv4Addr IPv4Host IPv4Mask where
> type Host IPv4Addr = IPv4Host
> type Mask IPv4Addr = IPv4Mask
> host (IPv4Addr h _) = h
> mask (IPv4Addr _ m) = m
--
Jedaï
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 13, Issue 13
*****************************************