[Haskell-beginners] instances of different kinds

Greg greglists at me.com
Sun Aug 29 06:23:29 EDT 2010

On Aug 28, 2010, at 8:04 AM, Brandon S Allbery KF8NH wrote:

>> 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.  
> 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".

On Aug 28, 2010, at 5:11 AM, Jürgen Doser wrote:
> I would say it like this: div2pi does not return a type of Floating
> value of its own choosing, it is able to return every type of Floating
> value (the concrete type is then chosen by the context in each case
> where div2pi is used).

And here is the "a-ha" moment!  I've been looking at return types as values "pushed" from the functions, but they are in fact "pulled" by the caller.  That makes a lot of sense in the functional paradigm of Haskell, but it didn't click how this relates to the type system.  In an imperative language like C, the function declares what it is going to return, and the caller is responsible for dealing with it.  In Haskell, the function is more of a transformation applied to its inputs and the caller requests that a value of a certain type be returned.  The class definition gives the range of choices available.

Thank you both.  

Also, Jürgen, thank you for the worked example you provided.  It runs just fine on my side as well and gives me something to toy with:

On Aug 28, 2010, at 5:11 AM, Jürgen Doser wrote:

> This works:
> data Foo a = Foo a deriving Show
> x :: Float
> x= 5.6
> y :: Foo Double
> y= Foo 9.8
> class TwoPi a where
>  div2pi :: (Floating b) => a -> b
> instance (Real a, Floating a) => TwoPi (Foo a) where
>   div2pi (Foo a) = realToFrac a / (2*pi)
> instance TwoPi Float where
>   div2pi a = realToFrac a / (2*pi)
> main = print ((x,y),(div2pi x, div2pi y))
> *Main> main
> ((5.6,Foo 9.8),(0.8912676661364157,1.5597184423005745))
> The (Real a) restriction in the instance definition for Foo a is
> necessary. If a would be Complex Double, for example, there is no way
> you can sensibly expect a Float return value.
> 	Jürgen

More information about the Beginners mailing list