Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [62]

By Root 495 0
and keywords here!

class Eq a where means a new type class called Eq is being defined. The a is the type variable, so a will play the role of the type that will soon be made an instance of Eq. (It doesn’t need to be called a, and it doesn’t even need to be one letter—it just must be in all lowercase.)

Next, several functions are defined. Note that it’s not mandatory to implement the function bodies themselves; just their type declarations are required. Here, the function bodies for the functions that Eq defines are implemented—defined in terms of mutual recursion. It says that two values whose types are instances of Eq are equal if they are not different, and they are different if they are not equal. You’ll see how this helps us soon.

The final type of the functions that we define in a type class is also worth noting. If we have, say, class Eq a where, and then define a type declaration within that class like (==) :: a -> a -> Bool, when we examine the type of that function later, it will have the type of (Eq a) => a -> a -> Bool.

A Traffic Light Data Type


So once we have a class, what can we do with it? We can make type instances of that class and get some nice functionality. Check out this type, for instance:

data TrafficLight = Red | Yellow | Green

It defines the states of a traffic light. Notice how we didn’t derive any class instances for it. That’s because we’re going to write some instances by hand. Here’s how we make it an instance of Eq:

instance Eq TrafficLight where

Red == Red = True

Green == Green = True

Yellow == Yellow = True

_ == _ = False

We did it by using the instance keyword. So class is for defining new type classes, and instance is for making our types instances of type classes. When we were defining Eq, we wrote class Eq a where, and we said that a plays the role of whichever type will be made an instance later. We can see that clearly here, because when we’re making an instance, we write instance Eq TrafficLight where. We replace the a with the actual type.

Because == was defined in terms of /= and vice versa in the class declaration, we needed to overwrite only one of them in the instance declaration. That’s called the minimal complete definition for the type class—the minimum of functions that we must implement so that our type can behave as the class advertises. To fulfill the minimal complete definition for Eq, we need to overwrite either == or /=. If Eq were defined simply like this:

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a -> Bool

we would need to implement both of these functions when making a type an instance of Eq, because Haskell wouldn’t know how these two functions are related. The minimal complete definition would then be both == and /=.

You can see that we implemented == simply by doing pattern matching. Since there are many more cases where two lights aren’t equal, we specified the ones that are equal, and then just did a catchall pattern saying that if it’s none of the previous combinations, then two lights aren’t equal.

Let’s make this an instance of Show by hand, too. To satisfy the minimal complete definition for Show, we just need to implement its show function, which takes a value and turns it into a string:

instance Show TrafficLight where

show Red = "Red light"

show Yellow = "Yellow light"

show Green = "Green light"

Once again, we used pattern matching to achieve our goals. Let’s see how it works in action:

ghci> Red == Red

True

ghci> Red == Yellow

False

ghci> Red `elem` [Red, Yellow, Green]

True

ghci> [Red, Yellow, Green]

[Red light,Yellow light,Green light]

We could have just derived Eq, and it would have had the same effect (but we didn’t for educational purposes). However, deriving Show would have just directly translated the value constructors to strings. If we want our lights to appear as Red light, we need to make the instance declaration by hand.

Subclassing


You can also make type classes that are subclasses of other type classes. The class declaration for Num is a bit long, but here’s the first part:

class

Return Main Page Previous Page Next Page

®Online Book Reader