Haskell/Class declarations
From Wikibooks, the open-content textbooks collection
Type classes are a way of ensuring certain operations defined on inputs. For example, if you know a certain type instantiates the class Fractional, then you can find its reciprocal.
Please note: For programmers coming from C++, Java and other object-oriented languages: the concept of "class" in Haskell is not the same as in OO languages. There are just enough similarities to cause confusion, but not enough to let you reason by analogy with what you already know. When you work through this section try to forget everything you already know about classes and subtyping. It might help to mentally substitute the word "group" (or "interface") for "class" when reading this section. Java programmers in particular may find it useful to think of Haskell classes as being akin to Java interfaces. For C++ programmers, Haskell classes are similar to the informal notion of a "concept" used in specifying type requirements in the Standard Template Library (e.g. InputIterator, EqualityComparable, etc.). Haskell classes are also the same as the C++0x Concepts.
Indeed, OO languages use nominal subtyping; Haskell Classes use structural subtyping. Haskell Classes also are not types, but categories of types. They cannot be used to hold any object fulfilling the interface, but only to parametrize arguments.
[edit] Introduction
Haskell has several numeric types, including Int, Integer and Float. You can add any two numbers of the same type together, but not numbers of different types. You can also compare two numbers of the same type for equality. You can also compare two values of type Bool for equality, but you cannot add them together.
The Haskell type system expresses these rules using classes. A class is a template for types: it specifies the operations that the types must support. A type is said to be an "instance" of a class if it supports these operations.
For instance, here is the definition of the "Eq" class from the Standard Prelude. It defines the == and /= functions.
class Eq a where
(==), (/=) :: a -> a -> Bool
-- Minimal complete definition:
-- (==) or (/=)
x /= y = not (x == y)
x == y = not (x /= y)
This says that a type a is an instance of Eq if it supports these two functions. It also gives default definitions of the functions in terms of each other. This means that if an instance of Eq defines one of these functions then the other one will be defined automatically.
Here is how we declare that a type is an instance of Eq:
data Foo = Foo {x :: Integer, str :: String}
instance Eq Foo where
(Foo x1 str1) == (Foo x2 str2) =
(x1 == x2) && (str1 == str2)
There are several things to notice about this:
- The class Eq is defined in the standard prelude. This code sample defines the type Foo and then declares it to be an instance of Eq. The three definitions (class, data type and instance) are completely separate and there is no rule about how they are grouped. You could just as easily create a new class Bar and then declare the type Integer to be an instance of it.
- Types and classes are not the same thing. A class is a "template" for types. Again this is unlike most OO languages, where a class is also itself a type.
- The definition of == depends on the fact that Integer and String are also members of Eq. In fact almost all types in Haskell (the most notable exception being functions) are members of Eq.
- You can only declare types to be instances of a class if they were defined with data or newtype. Type synonyms are not allowed.
[edit] Deriving
Obviously most of the data types you create in any real program should be members of Eq, and for that matter a lot of them will also be members of other Standard Prelude classes such as Ord and Show. This would require large amounts of boilerplate for every new type, so Haskell has a convenient way to declare the "obvious" instance definitions using the keyword deriving. Using it, Foo would be written as:
data Foo = Foo {x :: Integer, str :: String}
deriving (Eq, Ord, Show)
This makes Foo an instance of Eq with exactly the same definition of == as before, and also makes it an instance of Ord and Show for good measure. If you are only deriving from one class then you can omit the parentheses around its name, e.g.:
data Foo = Foo {x :: Integer, str :: String}
deriving Eq
You can only use deriving with a limited set of built-in classes. They are:
- Eq
- Equality operators == and /=
- Ord
- Comparison operators < <= > >=. Also min and max.
- Enum
- For enumerations only. Allows the use of list syntax such as [Blue .. Green].
- Bounded
- Also for enumerations, but can also be used on types that have only one constructor. Provides minBound and maxBound, the lowest and highest values that the type can take.
- Show
- Defines the function show (note the letter case of the class and function names) which converts the type to a string. Also defines some other functions that will be described later.
- Read
- Defines the function read which parses a string into a value of the type. As with Show it also defines some other functions as well.
The precise rules for deriving the relevant functions are given in the language report. However they can generally be relied upon to be the "right thing" for most cases. The types of elements inside the data type must also be instances of the class you are deriving.
This provision of special magic for a limited set of predefined classes goes against the general Haskell philosophy that "built in things are not special". However it does save a lot of typing. Experimental work with Template Haskell is looking at how this magic, or something like it, can be extended to all classes.
[edit] Class Inheritance
Classes can inherit from other classes. For example, here is the definition of the class Ord from the Standard Prelude, for types that have comparison operators:
class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a
The actual definition is rather longer and includes default implementations for most of the functions. The point here is that Ord inherits from Eq. This is indicated by the => symbol in the first line. It says that in order for a type to be an instance of Ord it must also be an instance of Eq, and hence must also implement the == and /= operations.
A class can inherit from several other classes: just put all the ancestor classes in the parentheses before the =>. Strictly speaking those parentheses can be omitted for a single ancestor, but including them acts as a visual prompt that this is not the class being defined and hence makes for easier reading.
[edit] Standard Classes
This diagram, copied from the Haskell Report, shows the relationships between the classes and types in the Standard Prelude. The names in bold are the classes. The non-bold text are the types that are instances of each class. The (->) refers to functions and the [] refers to lists.


