[Haskell-beginners] instances of different kinds

Brandon S Allbery KF8NH allbery at ece.cmu.edu
Sat Aug 28 11:04:40 EDT 2010

Hash: SHA1

On 8/28/10 06:44 , Greg wrote:
> On Aug 27, 2010, at 8:15 PM, Brandon S Allbery KF8NH wrote:
>> The instance doesn't conform to the class definition; it includes a
>> constraint that the class does not, as the class insists that the type of
>> the result must be independent of the type of the argument, while the
>> instance insists that they must be identical.
> I think what you're saying is that not only can an instance do no less than
> the class has guaranteed, it can do no *more*-- meaning the instance can't
> further restrict the return type even if that return type still conforms to
> the class definition.  In this case returning a Float breaks the class
> contract because I've gone and said what type of Floating type will be
> returned.  

Right.  You're not the only one vexed by this; one of the advanced Haskell
tricks is "restricted monads", which are an attempt to deal with the fact
that (for example) a Set is a monad but can't be a Monad because Monad
doesn't have an Ord constraint.

Another way of thinking about this, btw, is that when you use a typeclass
function the only things "visible" about the type are the things defined by
the class; so if the instance wants to do something different, there's no
way to enforce it.  Think of it as a mechanical translator that can
faithfully translate specific phrases that it knows about but garbles
anything else.

> The class definition doesn't mean "div2pi can return any type of Floating
> value", it means "div2pi *will* return any type of floating value".

More precisely, it means that when something invokes div2pi, it has the
right to request any type of floating value at its sole discretion.  But the
instance says "nuh-uh, you get the same type you feed it, nothing else".

>> class TwoPi a where
>>  div2pi :: (Floating b) => a -> b
> is essentially impossible to conform to because b is completely untethered
> to anything else in the code and not all "(Floating b)"'s are created equal.

It's possible, but you need to use a polymorphic function to produce it.
Problem is, there is no standard function that does so for Floating.  There
are ways to do so for Fractional and for RealFloat (the latter being fairly
horrid in practice) but not for Floating which sits in between them in the
numeric typeclass hierarchy.

(This may be another instance of "the Haskell numeric typeclass hierarchy is
woefully misdesigned".  You might want to take a look at
http://www.haskell.org/haskellwiki/Numeric_Prelude.  Warning:  "well
designed" for Haskellers means "conforms to mathematical theory", so expect
to get lost in a soup of groups, rings, fields, and the like :)

>  I think the intent of the functional dependency in the suggestion you
> provided in your second email is essentially to tether b to something.
>  Unfortunately if chokes in the second, non-Foo, instance.

Probably; when I write code late at night it's likely to be buggy :)

> I think I've mistakenly been thinking of instances as more like subclasses,
> but that's apparently not quite right (thus the "instance" keyword, I suppose).

The OO terminology is somewhat unfortunate; they don't actually follow any
standard OO rules fully, only just enough to cause confusion.

- -- 
brandon s. allbery     [linux,solaris,freebsd,perl]      allbery at kf8nh.com
system administrator  [openafs,heimdal,too many hats]  allbery at ece.cmu.edu
electrical and computer engineering, carnegie mellon university      KF8NH
Version: GnuPG v2.0.10 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/


More information about the Beginners mailing list