Recursion
The BEAM has no mutable loops, so recursion is the control structure for iteration. The idiom to learn is tail recursion with an accumulator: each call passes the running total forward so the compiler can reuse the stack frame, turning recursion into a constant-space loop. Watch how every language splits the work into a base case (empty list) and a recursive case (head plus the recursion on the tail), whether via multiple function clauses, case, or match.
-module(recur).
-export([sum/1]).
sum(List) -> sum(List, 0).
%% base case: empty list returns the accumulator
sum([], Acc) -> Acc;
%% recursive case: add the head, recurse on the tail
sum([H | T], Acc) -> sum(T, Acc + H).
%% sum([1,2,3,4,5]) =:= 15
%% (lists:sum/1 does the same thing in the standard library)Erlang leans on multiple function clauses with head/tail pattern matching; the two-argument helper carries the accumulator, and the [H | T] clause makes the tail call in last position.
defmodule Recur do
# public entry point seeds the accumulator
def sum(list), do: sum(list, 0)
# base case: empty list returns the accumulator
defp sum([], acc), do: acc
# recursive case: add the head, recurse on the tail
defp sum([head | tail], acc), do: sum(tail, acc + head)
end
# Recur.sum([1, 2, 3, 4, 5]) == 15
# Idiomatic Elixir would just write: Enum.sum([1, 2, 3, 4, 5])
# or reduce it: Enum.reduce([1, 2, 3, 4, 5], 0, &+/2)Elixir mirrors Erlang's clause-based approach with a private helper, but everyday code reaches for Enum.reduce/3 or Enum.sum/1 instead of hand-rolling the recursion.
import gleam/int
import gleam/io
// public entry point seeds the accumulator
pub fn sum(list: List(Int)) -> Int {
do_sum(list, from: 0)
}
// labelled accumulator argument; `case` splits the two shapes
fn do_sum(list: List(Int), from acc: Int) -> Int {
case list {
[] -> acc
[head, ..tail] -> do_sum(tail, from: acc + head)
}
}
pub fn main() {
io.println(int.to_string(sum([1, 2, 3, 4, 5])))
// prints "15"; gleam/list also offers list.fold([1,2,3,4,5], 0, int.add)
}Gleam is statically typed, so the List(Int) -> Int signature is checked at compile time; case exhaustively matches the empty and [head, ..tail] shapes, and the labelled from: argument keeps the accumulator call readable.
(defmodule recur
(export (sum 1)))
;; public entry point seeds the accumulator
(defun sum (list)
(sum list 0))
;; two clauses: base case, then the recursive case
(defun sum
(('() acc) acc)
(((cons head tail) acc) (sum tail (+ acc head))))
;; (recur:sum '(1 2 3 4 5)) => 15
;; (lists:sum '(1 2 3 4 5)) works too via Erlang interopLFE writes Erlang's multi-clause recursion as S-expressions: the second defun lists one (pattern body) clause per line, using '() for the empty list and (cons head tail) to destructure the head and tail.
-- Lua's only compound type is the table, used here as a 1-indexed array.
-- `i` plays the role of "the rest of the list" instead of head/tail.
local function sum(list, i, acc)
i = i or 1
acc = acc or 0
-- base case: walked past the last element
if list[i] == nil then
return acc
end
-- recursive case: add this element, advance the index (tail call)
return sum(list, i + 1, acc + list[i])
end
print(sum({1, 2, 3, 4, 5})) --> 15
-- Lua guarantees proper tail calls, so this runs in constant stack space.Luerl runs Lua, which lacks head/tail pattern matching, so recursion advances an integer index over a table; Lua's guaranteed proper tail calls make return sum(...) loop in constant stack space.