Reading — step 1 of 7
Learn
Erlang has no loops. Recursion is THE iteration. Combined with multi-clause functions and pattern matching, it expresses what other languages would write as for loops. Programming Erlang treats this as foundational.
Multi-clause functions
A function definition has CLAUSES separated by ;, ending with .:
factorial(0) -> 1;
factorial(N) when N > 0 -> N * factorial(N - 1).
- Clause 1 matches factorial(0) and returns 1
- Clause 2 matches any positive N and recurses
- Erlang tries clauses TOP-DOWN; first match wins
- Final clause ends with
., others with;
No separate if/case needed — pattern matching IS the dispatch.
Recursive list operations
The canonical Erlang style:
length([]) -> 0;
length([_ | T]) -> 1 + length(T).
sum([]) -> 0;
sum([H | T]) -> H + sum(T).
The [H | T] pattern destructures a list into HEAD (first element) and TAIL (rest). Recursion walks down the tail; the empty-list base case stops it.
Tail recursion — the accumulator pattern
Naive recursion grows the stack. Tail recursion uses an accumulator:
sum(L) -> sum(L, 0).
sum([], Acc) -> Acc;
sum([H | T], Acc) -> sum(T, Acc + H). %% LAST call — tail position
The recursive call is the LAST thing the function does — Erlang's compiler turns this into a loop with no stack growth. Essential for processing large lists.
Convention: a public function (sum/1) calls a private helper (sum/2) that takes the accumulator.
Guards on recursion
classify(N) when N < 0 -> negative;
classify(0) -> zero;
classify(N) when N > 0 -> positive.
Guards (when CONDITION) refine pattern matches. They run pure expressions only — no arbitrary function calls. Common guards: comparisons, type tests (is_atom, is_list, is_integer).
When to recurse vs use lists module
For most everyday list processing, prefer the lists module:
lists:sum([1, 2, 3]) %% 6
lists:foldl(fun erlang:'+'/2, 0, [1, 2, 3]) %% 6
lists:map(fun(X) -> X * 2 end, [1, 2, 3])
lists:filter(fun(X) -> X > 2 end, [1, 2, 3])
lists:reverse([1, 2, 3])
Write hand-rolled recursion when:
- The shape doesn't fit standard library functions
- You're learning the language
- Performance demands a custom traversal
Common mistakes
- Forgetting
;between clauses,.at the end — syntax errors. Each non-final clause ends with;. The last with.. - Non-tail recursion on huge lists — stack overflow. Convert to accumulator pattern.
- Reversing accumulators — tail-recursive functions building a list often produce it reversed. Final step: lists:reverse(Acc).
- Function clause order — Erlang tries top-down; put more specific patterns first.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…