views:

1289

answers:

2

In Haskell, one can define a data type like so:

    data Point1 = Point1 {
        x :: Integer
      , y :: Integer
    }

Can one use type classes for variables inside a data type? If so how? I realize it is possible to do this as an algebraic data type, with a different definition for each kind of point, but I'm wondering if there's a way to accomplish this in a more compact and flexible manner.

e.g. Something along the lines of this pseudocode which uses function declaration syntax:

    data Point2 = Point2 {
        x :: (Num a, Ord a) => a
      , y :: (Num a, Ord a) => a
    }

The goal would be to allow one to store Int, Integer, Float or Double values in the data type. Ideally, I'd like to restrict it so that x and y must be of the same type.

+5  A: 

something like this?

data (Num a, Ord a) => Point2 a = Point2 {
    x :: a
  , y :: a
}
newacct
More commonly, one leaves off the context on the data declaration and uses "(Num a, Ord a) => Point2 a" at the locations where the type actually gets used, but this works too.
ephemient
Thank you. That works perfectly and even makes sense now that I see it.
Greg
+6  A: 

You need to decide if you want an existential or universal quantification on that type. Universal quantification, ala:

data (Num a, Ord a) => Point2 a = Point2 a a

yields a proof obligation that Num and Ord instances exist for the type 'a' but doesn't actually help all that much, because all it does is give you an obligation when you go to use the Point class by constructing a value of that type or when you go to pattern match it.

In almost all cases you are better off defining

data Point2 a = Point2 a a deriving (Eq,Ord,Show,Read)

and making each of your instances contingent on the extra information you want.

instance Num a => Num (Point2 a) where
    ...

instance (Num a, Ord a) => SomeClass (Point2 a) where
    ...

This lets you pass around and construct fewer superfluous dictionaries and increases the number of scenarios in which your Point2 data type can be used.

On the other hand existential quantification can let you say that you don't care what the type is at all (closer to what you actually requested, type wise) at the expense that you can't use anything on it except for the operations provided by the constraints you specified -- a pretty poor fit here.

Edward Kmett
Woohoo, that's exactly the point I was getting at in my comment to newacct's answer but was too lazy to write up :)
ephemient
That's very informative. I did end up using ephemient's comment above in my code. And your explanation helped my understanding a great deal. (RWH hasn't covered "instance" yet but it's evident what it does from context.) Thank you very much.
Greg