Skip to content
UoL CS Notes

Lecture 13-2

COMP105 Lectures

Type Classes

Some functions are polymorphic, but can’t be applied to any type. + is a good example. It can work on float and integer but not on mixed types or Char. The type of + is:

(+) :: Num a => a -> a -> a

This means that a is a number in the definition: a -> a -> a.

Num

Num is a type class:

  • It restricts the type variable a to only be number types.
  • Word, Int, Integer, Float, Double are all contained in Num.
  • Char, Bool, tuples and lists are not in Num.

Num Sub-Classes

Num has two sub-classes.

Integral represents whole numbers and contains:

  • Word (un-signed integers)
  • Int
  • Integer

Fractional represents rationals and contains:

  • Float
  • Double
  • Rational

Eq

The types in the class Eq are the types which can be compared with the function ==. There are no default types which aren’t equality testable but if you make your own type then you will have to add it to this class.

Type Class Syntax

The syntax of a class type is:

[Type class 1], [Type class 2], ...) => [Type]

This results in a declaration similar to the following:

equals_two :: (Eq a, Num a) => a -> a -> Bool
equals_two a b = a + b == 2

This type declaration also means that if you use functions like == in your function then you must specify that the type is comparable with Eq a. If you don’t then the compiler will give an error.

The Most General Type Annotation

The most general type annotation is the one that is least restrictive. Ideally you want your type annotation to be the most general without giving an error:

equals_two a b = a + b == 2

-- Too restrictive
equals_two :: Int -> Int -> Bool

-- Most general
equals_two :: (Eq a, Num a) => a -> a -> Bool

-- Too general (will give error)
equals_two :: a -> a -> Bool

The most general type annotation is the one which allows the most valid types

Numbers

In Haskell numbers, such as 10 have a polymorphic type:

10 :: Num p => p

This means that, unless stated explicitly that numbers will be converted to the most suitable type in the class of Num.

You can force a number to be a particular type by using the :: operator:

1 :: Integer
> 1
1 :: Float
> 1.0

The function fromIntegral will take any Integral type and convert it into a Num type. This, for example would allow you to use the / operator on an Integer:

fromIntegral (1 :: Int) / 2
> 0.5

Converting Floats to Integers

Converting floats to integers is a lossy operation. This means that you shoul choose how to complete the rounding:

ceiling 1.6
> 2

floor 1.6
> 1

truncate 1.6
> 1

round 1.6
> 2

Other Type Classes

There are many other type classes in Haskell that won’t be covered:

length :: Foldable t => t a -> Int

This that a should be accepted if it is a list.

If you see any of the following as a types:

  • Functor
  • Foldable
  • Traversable

then think list.

Exercises

  1. square_area :: Num a => a -> a -> a
  2. triangle_area :: Fractional a => a -> a -> a
  3. equal_heads :: Eq a => [a] -> [a] -> Bool