liveBook · Manning

Pattern matching

As explained in Functional Programming in Scala, Second Edition

Pattern matching is a language feature that selects a case by comparing a target expression with structural patterns and evaluates the corresponding result.

Pattern matching selects a result by inspecting the structure of a target expression. A match expression places the target before `match`, then tries cases in order. A case pairs a pattern with a result using `=>`; when a pattern matches, its result becomes the value of the whole expression. section 3.2

Unlike a simple switch, a pattern can descend into an algebraic data type and bind its parts. For a `List`, `Nil` recognizes the empty constructor, while `Cons(x, xs)` recognizes a nonempty list and names its head and tail. Those bindings make structural recursion direct: handle the base constructor, then combine or recur on the remaining structure. section 3.2 section 3.6

object List:
 
  def sum(ints: List[Int]): Int = ints match
    case Nil => 0
    case Cons(x, xs) => x + sum(xs)
 
  def product(doubles: List[Double]): Double = doubles match
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x, xs) => x * product(xs)

Compare `sum` and `product`: each assigns a result to `Nil`, decomposes `Cons`, and uses a more specific `Cons(0.0, _)` case before the general product case. section 3.2

Order, literals, and wildcards

Matching `List(1,2,3,4,5)` against nested `Cons` patterns first rejects a pattern requiring `4` where the list has `3`. It skips `Nil`, then matches a later pattern that binds `x = 1` and `y = 2`, ignores the final tail with `_`, and yields `3`. Later matching cases are not evaluated. section 3.6

Patterns support small, explicit decisions while preserving the list structure:

  • Use `_` when a matched component is irrelevant, as in returning a list tail without naming its head. section 3.6
  • Add a guard such as `if f(hd)` to make a recursive case conditional. section 3.6
  • Match tuples such as `(a, b)` to decompose two lists together for pairwise operations. section 3.6
  • Cover every constructor when possible: non-exhaustive matches can throw `MatchError`, and Scala often warns about them. section 3.6

Pattern matching is a practical interface to algebraic data types: constructors both build values and provide the patterns used to take them apart. Repeated structural recursion can later be factored into folds, maps, filters, and related higher-order functions. section 3.6 section 3.5

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Explains case order, nested destructuring, bindings, wildcards, guards, and exhaustiveness through recursive list functions.
Examples
Works through `sum`, `product`, nested `Cons` matching, `tail`, `dropWhile`, and pairwise list operations.
What it assumes
Builds from algebraic data types and `List` constructors while deferring variance details.
What you can do after
Apply it via Scala match expressions to destructure lists and write recursive pure functions.
How it connects
Connects algebraic data types, recursion, structural sharing, folds, and higher-order list functions.

Also explained in

Compare how 12 books explain pattern matching →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.