Exploring Languages
with Interpreters
and Functional Programming

Chapter 23
Overloading and Type Classes

H. Conrad Cunningham

5 November 2018

Copyright (C) 2017, 2018, H. Conrad Cunningham

Acknowledgements: I originally created these slides in Fall 2017 to accompany what is now Chapter 23, Overloading and Type Classes, in the 2018 version of the textbook Exploring Languages with Interpreters and Functional Programming.

Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of November 2018 is a recent version of Firefox from Mozilla.

Source Code: The Haskell module for this chapter is in file TypeClassMod.hs.

Overloading and Type Classes

Lecture Goals

Polymorphism in Haskell

  1. Parametric polymorphism — same name, same function definition for all types of arguments/results — “polymorphism”

    length: [a] -> Int
  2. Overloading — same name, same functionality, but different function definitions depending upon type

    (+) function takes two numbers of same type

Why Overloading?

elemBool :: Bool -> [Bool] -> Bool
elemBool x []     = False
elemBool x (y:ys) = eqBool x y || elemBool x ys

How can define eqBool?

eqBool :: Bool -> Bool -> Bool
eqBool True  False = False
eqBool False True  = False
eqBool _     _     = True

Not general!

Generalizing eqBool

elemGen :: (a -> a -> Bool) -> a -> [a] -> Bool
elemGen eqFun x []     = False
elemGen eqFun x (y:ys) = eqFun x y || elemGen eqFun x ys

elemBool :: Bool -> [Bool] -> Bool
elemBool = elemGen eqBool

Solution?

Defining Equality Class

Instances

Classes with Default Methods

class Eq a where  -- from Prelude library
    (==), (/=) :: a -> a -> Bool
    -- Minimal complete definition: (==) or (/=)
    x /= y  = not (x == y)
    x == y  = not (x /= y)

What is Equality?

Example Class Visible

class Visible a where
    toString :: a -> String
    size     :: a -> Int

instance Visible Char where
    toString ch  = [ch]
    size _       = 1

instance Visible Bool where
    toString True  = "True"
    toString False = "False"
    size _         = 1

instance Visible a => Visible [a] where
    toString = concat . map toString
    size     = foldr (+) 1 . map size

Class Laws for Visible

Class Extension (Inheritance)

class Eq a => Ord a where -- from Prelude
    (<), (<=), (>), (>=) :: a -> a -> Bool
    max, min             :: a -> a -> a
    -- Minimal complete definition: (<) or (>)
    -- Must break circular definition
    x <= y                  = x < y || x == y
    x <  y                  = y > x
    x >= y                  = x > y || x == y
    x >  y                  = y < x
    max x y   | x >= y      = x
              | otherwise   = y
    min x y   | x <= y      = x
              | otherwise   = y

Class Laws for Ord

Example Use isort

    isort' :: Ord a => [a] -> [a]
    isort' []     = []
    isort' (x:xs) = insert' x (isort' xs)

    insert' :: Ord a => a -> [a] -> [a]
    insert' x []    = [x]
    insert' x (y:ys)
        | x <= y    = x:y:ys   -- overloaded <=
        | otherwise = y : insert' x ys

Multiple Constraints on Functions

vSort :: (Ord a,Visible a) => [a] -> String
vSort = toString . isort' 

vLookupFirst :: (Eq a,Visible b) => [(a,b)] -> a -> String
vLookupFirst xs x = toString (lookupFirst xs x)

lookupFirst :: Eq a => [ (a,b) ] -> a -> [b]
lookupFirst ws x  = [ z | (y,z) <- ws, y == x ]

Multiple Constraints on instance

instance (Eq a, Eq b) => Eq (a,b) where
    (x,y) == (z,w) =  x == z && y == w 

Multiple Constraints on class

class (Ord a,Visible a) => OrdVis a
    
vSort :: OrdVis a => [a] -> String

Built-In Haskell Classes

Comparison to Java (1)

Comparison to Java (2)

Comparison to Java (3)

Type Classes Spreading

First appeared in Haskell, but adopted in newer languages

Key Ideas

Source Code

The Haskell code for this chapter is file TypeClassMod.hs.