ADTs, Pattern Matching, Tuples, Guards

Class: CSCE-314


Notes:

1. Motivation: Why Data Modeling Matters

Up to now, we’ve been writing functions — recursion, higher-order operations, purity. Functions are powerful, but they don’t exist in isolation. They need data to work on.

In real-world software, you don’t just pass around single integers and strings. You model things: a Student in a university system, a Transaction in banking, a Shape in a drawing tool.

Haskell gives us algebraic data types (ADTs) to create these models in a way that’s expressive, safe, and composable.

By the end of today, you’ll see how ADTs combined with pattern matching let you model concepts directly in code, almost like writing down the definition in plain English.

2. Tuples: Quick Grouping of Values

A tuple is a quick way to group values without creating a brand-new type. Think of it like throwing two or three things into a basket just to carry them around together.

Example:

pair :: (Int, String)
pair = (42, "Answer")

Here, (42, "Answer") might be familiar as the joke from The Hitchhiker’s Guide to the Galaxy — the number 42 as the answer to life, the universe, and everything. But in Haskell, it’s just an Int and a String paired together.

Limitation: tuples don’t carry meaning (not descriptive). A (Double, Double) could be a coordinate (x, y), or a vector, or a fraction. Without context, you can’t tell.

Pattern matching lets us pull tuples apart easily:

fst (x, _) = x
snd (_, y) = y

Here, (x, _) means 'take the first element and ignore the second.' The underscore _ is a wildcard pattern — a placeholder that says 'I don’t care about this part.'

3. Pattern Matching Basics

Pattern matching describes the shape of data directly in the function definition.

Example with tuples:

addPair :: (Int, Int) -> Int
addPair (x, y) = x + y

This function says: to add a pair, break it into x and y, then return their sum.

Lists use pattern matching too:

head' [] = error "empty list"
head' (x:_) = x

The first case [] matches the empty list. The second case (x:_) matches a non-empty list: x is the first element, _ ignores the rest.

The ':' symbol is called the cons operator (short for construct). It builds lists: 1:2:3:[] is [1,2,3].

4. Guards for More Expressive Logic

Sometimes you want to match conditions, not just structure. Guards let you do this.

Example:

sign :: Int -> String
sign n
| n > 0 = "positive"
| n < 0 = "negative"
| otherwise = "zero"

Guards read like English: if n > 0, then 'positive'; if n < 0, then 'negative'; otherwise 'zero'.

They are cleaner than nested if/else chains when you have multiple cases.

5. Algebraic Data Types (ADTs): Custom Data Modeling

Tuples are useful, but ADTs let you define your own descriptive types with multiple forms.

Example:

data Shape = Circle Float | Rectangle Float Float | Square Float

This says: a Shape can be a Circle with a radius, a Rectangle with width and height, or a Square with side length.

Pattern matching pairs naturally with ADTs:

area :: Shape -> Float
area (Circle r) = pi * r * r
area (Rectangle w h) = w * h
area (Square s) = s * s

Each constructor is handled separately, and the code is self-documenting.

6. Recursive ADTs

ADTs can also be recursive, meaning they contain themselves.

Example:

data IntList = Empty | Cons Int IntList

This means an IntList is either Empty, or it’s Cons (an integer plus another IntList).

Cons means construct. For example, [1,2,3] is shorthand for 1 : (2 : (3 : [])), where : is the cons operator.

Functions follow the recursive structure:

sumList Empty = 0
sumList (Cons x xs) = x + sumList xs

Recursive ADTs underpin many structures: trees, graphs, and beyond.

7. Connecting to Learn You a Haskell

Learn You a Haskell for Great Good! is a beginner-friendly resource with humor and cartoons.

Relevant chapters:

Encourage students to try the examples in ghci as they read. Learning is strongest when they experiment.

8. Wrap-up and Connection to Next Steps

Today we moved from tuples → pattern matching → guards → ADTs → recursive ADTs.

Students should now be able to:

This week:

Big takeaway: you’re learning to model problems in code, not just solve them. That’s a key step toward thinking like a software engineer.