Type Classes

12.1 Using and Deriving Standard Classes

compare, <, max, min Convert to a String (debug representation) Parse from a String succ, pred, [a..] Min/max values minBound, maxBound

Num, Integral, Fractional, Floating Semigroup, Monoid <>, mempty Functor, Applicative, Monad Structure-preserving mapping, effects fmap, pure, <*>, >>= Foldable, Traversable Reducing and traversing containers foldr, traverse

12.2 Defining Type Classes and Instances

Laws: many classes have laws (e.g., Eq reflexivity, Ord transitivity, Monoid associativity) that instances should satisfy. The compiler doesn't check them, so test them with QuickCheck.

Coherence: at most one instance per type per class. Avoid orphan instances (instances defined in a module that owns neither the class nor the type).

class Shape a where
  area :: a -> Double
  perimeter :: a -> Double
  describe :: a -> String
  describe x = "Shape with area " ++ show (area x)     -- default implementation

data Circle = Circle Double
data Square = Square Double

instance Shape Circle where
  area (Circle r) = pi * r * r
  perimeter (Circle r) = 2 * pi * r

instance Shape Square where
  area (Square s) = s * s
  perimeter (Square s) = 4 * s
  describe s = "A square of area " ++ show (area s)    -- override the default

-- Manual instances of standard classes
data Suit = Hearts | Spades deriving (Eq)
instance Show Suit where
  show Hearts = "♥"
  show Spades = "♠"

data Version = Version Int Int deriving (Eq)
instance Ord Version where
  compare (Version a b) (Version c d) = compare (a, b) (c, d)

-- Instances with constraints
data Box a = Box a
instance Show a => Show (Box a) where
  show (Box x) = "Box(" ++ show x ++ ")"

-- Superclasses: every Entity must also be Eq and Show
class (Eq a, Show a) => Entity a where
  entityId :: a -> Int

12.3 Type Classes vs OOP Interfaces

Type classes dispatch on types (including the return type: read, mempty, pure) rather than on an object. Instances can be added to existing types after the fact, and they can be conditional (instance Show a => Show [a]).