<<

Type Classes

Slide 1 - Title

Hello, and welcome to CS 421. In a , we often want to apply an operation to more than one of thing. For example, in most programming languages, the plus operator normally works on both integers and floating point numbers, without needing to be distinguished in any way. When a function or operation is allowed to work on more than one type, it is said to be polymorphic.

Slide 2 - Objectives

When you are done with this video, you will be able to describe polymorphism and list several ways of accomplishing it. You will also be able to describe Haskell’s type classes and use them to define some polymorphic functions.

Slide 3 - Polymorphism

It is very common to want to use the same “thing”, such as a function, an operator, or a container, over many types. Different languages have developed different ways to handle this. In C++, we have , also called . Many languages support a form of objects and inheritance, which allows similar types to be grouped together. Languages like Haskell and OCaml that have Hindley Milner type systems support parameterized types such as lists, and languages like C++ and Java support templated classes, or generics. Haskell supports a construct called a , which we will talk about in great detail.

Slide 4 - Overloading

Here is an example of overloading in C++. You see here we have two functions named inc. We’ like this function to work on both integers and doubles, so we declare the function twice. This was a huge improvement over the C programming language. In C, you would have to give the functions different names so that the could distinguish between them. So, you might have a function incInteger and another function incDouble. As you can imagine, this gets tedious quickly if you have a lot of types you want to operate on. The way C++ does it is by a process called mangling. The compiler uses the types of the parameters as part of the name, which allows it to tell them apart. This is similar to what we had to do in C, but it’s all handled by the compiler for us.

Slide 5 - Inheritance

Here’s an example in Java of inheritance. We have a class Shape and another class Square that inherits from Shape. We can have a collection of objects that inherit from Shape and loop over them, knowing they all support certain fields or operations. I’m assuming you’ve worked with this before, so I am not going to go into much detail now, but we will talk about objects in more detail in a future lecture.

1 Slide 6 -

Parametric polymorphism allows your types to have a parameter of some kind, and is often used for types that are meant to be containers, though that’s not the only use for them. Java calls them generics, and C++ calls them templates. In Haskell they are called parameterized types.

Slide 7 - The Eq Type Class

Let’s talk about type classes now. A type class is a collection of types that support a of functions. Here is the Eq type class, for types that support equality. This declaration says that a type a is a member of the Eq type class if it supports == and not =. The second line of the declaration gives the types of the functions we want to support. The last two lines give default definitions. Later on, when you declare a type to be a member of this class, you have the option of giving your own definition of these functions or keepig the default definition. Notice that == and not= are defined recursively in terms of each other. This allows you to define one of the two, and as a result you will get the other one automatically.

Slide 8 - Using Eq

The reason for an Eq type class is that Haskell does not define equality for user-defined types automatically. For one thing, not all types can be compared: functions for instance. For another thing, we may have different ideas about when we want to consider two pieces of data to be equal. For example, you may have a node type that contains data and a comment field, and maybe you don’t want the comment field to be considered when you compare for equality. In this example, I’ve created a type Foo and made two variables x and y both assigned to Foo 10. If we try to compare them, we get this error message. This is an indication that we did not make Foo a member of the Eq type class. Let’s look at how to do that.

Slide 9 - Use an Instance

The instance keyword is how we declare a type to be a member of a type class. Here I’ve told Haskell that Foo is a member of Eq, and given the definition for equality. It will get the default definition of not = from the class declaration. Now == works for x and y.

Slide 10 - tl;dc

Too long! Didn’t code! There are many type classes in Haskell, and many of those are very basic. If you are thinking that the compiler should be able to make Foo an instance of Eq for us, you would be right. The Haskell implementers thought the same thing, so they put in a keyword deriving that we can use to tell the compiler to make Foo an instance of a type class for us. Let’s take a look at some of the other basic type classes.

Slide 11 - The Ord Typeclass

Ord is not just the code for Chicago’s O’Hare airport! In Haskell, the Ord typeclass indicates that a type has an ordering. The minimal definition is the compare function, though you could define the operators instead.

2 One thing that is a unusual about this type is that it makes use of another type called Ordering, which has three members: LT, GT, and EQ. You may want to pause the video and review the functions to see how it makes use of these. Resume when you are ready to see the next type class.

Slide 12 - The Show Typeclass

To convert an instance of a type into a string we have the Show typeclass. It has just one function, show. Usually we use a deriving clause to have the compiler write show for us, but sometimes it is preferable to supply our own definition.

Slide 13 - The Read Typeclass

The Read typeclass is the opposite of show. It converts a string into a member of the given type. You’ll note that if you want to use read, you have to tell Haskell the type that you expect to get back. One of the consequences of type classes is that type inferencing, in which Haskell automatically determines the types of things for us, is not always decidable. Like Show, we can derive Read to have the function created for us. Those are some of the basic type classes. You have also seen Num for numeric types, and you may have seen Integral for types that support modulus. There are many other type classes that come with Haskell, and in the next video we will go over the Functor and Applicative type classes, which allow some more advanced operations on user-defined types.

3