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 22, 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.
Motivate overloading and type classes
Introduce type class laws
Extend concepts to inheritance and multiple constraints
Compare Haskell to other languages
Parametric polymorphism — same name, same function definition for all types of arguments/results — “polymorphism”
Overloading — same name, same functionality, but different function definitions depending upon type
(+) function takes two numbers of same type
elemBool :: Bool -> [Bool] -> Bool
elemBool x []     = False
elemBool x (y:ys) = eqBool x y || elemBool x ysHow can define eqBool?
eqBool :: Bool -> Bool -> Bool
eqBool True  False = False
eqBool False True  = False
eqBool _     _     = TrueNot general!
eqBoolelemGen :: (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 eqBoolBut elemGen too general! any a -> a -> Bool
Equality meaningless for some types (functions?)
Overload == operator for set of types
Restrict polymorphism in elem to types with (==) defined
Introduce type class for equality, then constrain polymorphism to that context (used before)
Define class Eq as set of types with (==) defined
Make type Bool instance of class (also others like Int, Char)
Make list in Eq if element is also
Left side of equation defined by right side
Right side must be previously defined operation
(e..g. x == y) or terminating recursion (e.g. xs == ys)
class Eq a where  -- from Prelude library
    (==), (/=) :: a -> a -> Bool
    -- Minimal complete definition: (==) or (/=)
    x /= y  = not (x == y)
    x == y  = not (x /= y)Equality is equivalence relation in math. For all x, y, and z in type’s set:
x == x is True.x == y if and only if y == x.x == y and y == z, then x == z.x /= y equivalent to not (x == y)
Type class laws — must hold for all Eq instances
Reality intervenes! x == x for infinite? floating?
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 sizeVisibleNo constraints on the conversion to strings
size must return Int, finite and bounded
Ord is subclass of Eqclass 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   = yOrdFor <= and all x, y,z in type’s set (total order)
Reflexivity: x <= x is True
Antisymmetry: x <= y and y <= x, then x == y
Transitivity: if x <= y and y <= z, then x <= z
Trichotomy (comparability, totality): x <= y or y <= x
== (and /=) satisfy Eq type class laws
<, >, >=, max, and min satisfy definition in declaration
isortinstance== overloaded from different instancesclassOrdVis has multiple inheritance — reuse methods of both
Must satisfy type class laws for Ord and Visible
Prelude classes in Section 6.3 of the Haskell 2010 Language
Typeclassopedia by Brent Yorgey
Haskell class is collection of types; Java class similar to type
Haskell class similar to Java abstract class except Haskell has no data, Java only single inheritance
Haskell class similar to Java interface except Haskell has default method definitions (in Java from Java 8)
Haskell instance is type, not object — like concrete Java class that extends abstract classes or implements interface
Haskell separates type definition from method definition; Java mixes type and method definition
Haskell class methods correspond to Java instance methods
Each instance provides own definition for methods; class defaults correspond to default definitions in parent class
Haskell has no receiver object or mutable fields
Haskell class methods bound statically at compile time; Java bound dynamically at runtime
Java attaches identifying information to runtime object; Haskell only attaches logically
Haskell does not support Java/C++ overloading where functions have different types, same name
Haskell objects cannot be implicitly coerced, types have no default parent — Java has universal base class Object (reference types)
Haskell class separates type from access control, uses modules for access control — Java mixes
First appeared in Haskell, but adopted in newer languages
Rust supports traits, limited form of type classes
Scala’s implicit classes/parameters enable similar type enrichment idiom
PureScript supports Haskell-like type classes
Idris supports interfaces, generalization of Haskell type classes
JavaScript has functional libraries such as Ramda
Overloading function giving same name, “same functionality” but different definitions for different types
Type classes and instances
Type class laws to define “same functionality”
Multiple constraints, inheritance
Comparison to classes in other languages
The Haskell code for this chapter is file TypeClassMod.hs.