Pattern Matching in Erlang
In Erlang, the '=' operator is not assignment — it is a match operator that compares the left side against the right side and either binds any unbound variables to make them equal, or raises a badmatch error if the shapes don't line up. This single mechanism replaces variable assignment, destructuring, and much of what other languages use if/switch statements for, because you can match directly against tuples, lists, and specific literal values.
Cricket analogy: Checking {batsman, Name, Runs} = {batsman, "Kohli", 82} is like an umpire confirming a scorecard entry matches the actual dismissal on the field, only proceeding if every detail lines up.
Matching Against Literals and Structure
A pattern can mix literal values with variables in the same expression: {ok, Value} = {ok, 42} binds Value to 42, but {ok, Value} = {error, timeout} fails immediately because the atom ok doesn't match error. This is exactly how idiomatic Erlang code checks for success — writing {ok, Result} = some_function() both extracts Result and acts as an implicit assertion that the call succeeded, crashing loudly (and safely) if it didn't.
Cricket analogy: Matching {out, Fielder} against an actual dismissal is like an umpire's decision only being confirmed if the dismissal type literally says 'out'; a 'not out' result fails the match entirely.
Pattern Matching in Function Clauses
Erlang functions are defined as an ordered set of clauses, each with its own pattern for the arguments, and the runtime tries each clause top to bottom until one matches. This is how Erlang expresses what other languages write as if/else or switch: a function like describe(0) -> "zero"; describe(N) when N > 0 -> "positive"; describe(_) -> "negative". picks the right clause purely by matching the argument's shape and value against each pattern in turn.
Cricket analogy: Selecting a bowling change based on which batsman is at the crease — spin against a left-hander, pace against a tail-ender — mirrors how Erlang tries clause patterns top to bottom until one fits.
The Underscore Wildcard and Guards
The underscore '_' is a wildcard pattern that matches anything without binding a variable, commonly used to explicitly discard a value you don't care about, as in {ok, _} = Result. Guards, introduced with the 'when' keyword after a clause head, add extra conditions beyond structural matching — like when N > 0, andalso, or is_list(X) — but guards are restricted to a safe subset of built-in functions because they must never fail or have side effects while Erlang is deciding which clause to run.
Cricket analogy: Using '_' to ignore the wicketkeeper's name while matching {out, bowled, _} on a dismissal record is like a scorer who only cares that it was a bowled dismissal, not who kept wicket.
-module(shapes).
-export([area/1]).
area({circle, Radius}) ->
3.14159 * Radius * Radius;
area({rectangle, Width, Height}) ->
Width * Height;
area({square, Side}) when Side > 0 ->
Side * Side;
area(_Other) ->
{error, unknown_shape}.
%% In the shell:
%% 1> c(shapes).
%% {ok,shapes}
%% 2> shapes:area({circle, 2.0}).
%% 12.56636
%% 3> shapes:area({square, 4}).
%% 16
%% 4> shapes:area({triangle, 3, 4}).
%% {error,unknown_shape}Pattern matching also destructures nested data in a single step: [{name, Name}, {age, Age}] = [{name, "Ada"}, {age, 36}] binds both Name and Age from a nested list-of-tuples structure in one match, something that would take several lines of indexing in most mainstream languages.
A variable can only be bound once per clause via '='. Writing {ok, X} = {ok, 1} followed later by {ok, X} = {ok, 2} in the same scope will raise a badmatch error, because the second line tries to match the already-bound X (which is 1) against 2. Use a fresh variable name if you need a new value.
- The '=' operator in Erlang is a match operator, not assignment; it binds unbound variables or fails with badmatch.
- Patterns mix literals and variables, so {ok, Value} = {error, timeout} fails immediately.
- Function clauses are tried top to bottom, and the first clause whose pattern matches the arguments runs.
- The underscore '_' is a wildcard that matches anything without binding a variable.
- Guards, introduced with 'when', add conditions beyond structural matching but must stay side-effect free.
- Pattern matching can destructure deeply nested tuples and lists in a single expression.
- Once a variable is bound in a scope, re-matching it against a different value raises a badmatch error.
Practice what you learned
1. What does the '=' operator actually do in Erlang?
2. Why does the idiom {ok, Result} = some_function() work as an implicit assertion?
3. In what order does Erlang evaluate a function's multiple clauses?
4. What is the purpose of the underscore '_' in a pattern?
5. Why are Erlang guard expressions restricted to a safe subset of built-in functions?
Was this page helpful?
You May Also Like
Atoms and Terms
Understanding Erlang's atom data type and how atoms, numbers, tuples, and lists combine to form Erlang terms.
Your First Erlang Program
Writing, compiling, and running a real Erlang module, from module declaration and exports through the shell workflow.
What Is Erlang?
An introduction to Erlang's origins, design philosophy, and the concurrent, fault-tolerant systems it was built to run.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics