Haskell Algebraic Data Types and Type Classes

Haskell's type system is one of its greatest strengths — types describe exactly what a function does, and the compiler enforces those contracts.

Sum types (OR)

HASKELL
data Color = Red | Green | Blue | Yellow

-- Pattern matching on custom types
describe :: Color -> String
describe Red    = "Red as the sun"
describe Green  = "Green as the hills"
describe Blue   = "Blue as the sky"
describe Yellow = "Yellow as the marigold"

Product types (AND)

HASKELL
data Point = Point Double Double

origin :: Point
origin = Point 0 0

distance :: Point -> Point -> Double
distance (Point x1 y1) (Point x2 y2) =
    sqrt ((x2 - x1)^2 + (y2 - y1)^2)

Combined (most useful)

HASKELL
data Shape
    = Circle Double              -- radius
    | Rectangle Double Double    -- width, height
    | Triangle Double Double Double  -- sides

area :: Shape -> Double
area (Circle r)          = pi * r * r
area (Rectangle w h)     = w * h
area (Triangle a b c)    =
    let s = (a + b + c) / 2
    in sqrt (s * (s-a) * (s-b) * (s-c))

Maybe — Replacing null

HASKELL
data Maybe a = Just a | Nothing

safeDivide :: Double -> Double -> Maybe Double
safeDivide _ 0 = Nothing
safeDivide a b = Just (a / b)

-- Using Maybe
case safeDivide 10 0 of
    Nothing  -> putStrLn "Cannot divide by zero"
    Just res -> putStrLn ("Result: " ++ show res)

Type classes

Type classes are Haskell's mechanism for ad-hoc polymorphism (like interfaces):

HASKELL
-- The Eq type class requires ==
class Eq a where
    (==) :: a -> a -> Bool

-- The Show type class requires a string representation
class Show a where
    show :: a -> String

-- Deriving common type classes
data Student = Student
    { name  :: String
    , grade :: Char
    } deriving (Show, Eq)

-- Now you can use:
-- show (Student "Ram" 'A') == "Student {name = \"Ram\", grade = 'A'}"
-- Student "Ram" 'A' == Student "Sita" 'B'  -- False

Parameterized types

HASKELL
data Result a = Success a | Error String

resultToString :: Result Int -> String
resultToString (Success n) = "Got: " ++ show n
resultToString (Error msg) = "Error: " ++ msg

Tips

  • Use sum types for things that can be one of several variants.
  • Use Maybe instead of null — the compiler forces you to handle the Nothing case.
  • Use deriving to auto-generate common type class instances.
  • Types are your documentation — make them expressive.

Next: fp.