Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type classes in Haskell data types

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.

like image 716
Gregyski Avatar asked Jul 05 '09 05:07

Gregyski


People also ask

What are type classes in Haskell?

Type Classes are a language mechanism in Haskell designed to support general overloading in a principled way. They address each of the concerns raised above. They provide concise types to describe overloaded functions, so there is no expo- nential blow-up in the number of versions of an overloaded function.

Are there classes in Haskell?

The classes used by Haskell are similar to those used in other object-oriented languages such as C++ and Java. However, there are some significant differences: Haskell separates the definition of a type from the definition of the methods associated with that type.

What do you mean by type class?

In computer science, a type class is a type system construct that supports ad hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types.


2 Answers

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.

like image 108
Edward Kmett Avatar answered Sep 24 '22 08:09

Edward Kmett


something like this?

data (Num a, Ord a) => Point2 a = Point2 {
    x :: a
  , y :: a
}
like image 41
newacct Avatar answered Sep 24 '22 08:09

newacct