Recursion
There are no for/while loops — use recursion, Enum, or comprehensions.
There are no for/while loops — use recursion, Enum, or comprehensions.
10.1 Basic recursion
defmodule Rec do
def sum([]), do: 0
def sum([h | t]), do: h + sum(t)
def factorial(0), do: 1
def factorial(n) when n > 0, do: n * factorial(n - 1)
def print_n(0), do: :ok
def print_n(n) do
IO.puts(n)
print_n(n - 1)
end
end10.2 Tail-call optimisation with accumulators
A call in tail position doesn't grow the stack. (On the BEAM, body recursion is also quite efficient; prefer clarity, but use tail recursion for infinite loops like process loops.)
defmodule Tail do
def sum(list), do: do_sum(list, 0)
defp do_sum([], acc), do: acc
defp do_sum([h | t], acc), do: do_sum(t, acc + h)
def reverse(list), do: do_reverse(list, [])
defp do_reverse([], acc), do: acc
defp do_reverse([h | t], acc), do: do_reverse(t, [h | acc])
end10.3 Map & reduce by hand
defmodule MyList do
def map([], _f), do: []
def map([h | t], f), do: [f.(h) | map(t, f)]
def reduce([], acc, _f), do: acc
def reduce([h | t], acc, f), do: reduce(t, f.(h, acc), f)
def filter([], _p), do: []
def filter([h | t], p), do: if(p.(h), do: [h | filter(t, p)], else: filter(t, p))
end🧪 Part I Exercises
Write Math.power(x, n) using tail recursion.
Write MyList.length/1, MyList.max/1, and MyList.flatten/1.
Implement FizzBuzz using case on {rem(n, 3), rem(n, 5)}.
Write fib/1 both naively and with an accumulator.
Implement range(a, b) returning a list, without using Range.
Write a function that removes consecutive duplicates: [1,1,2,3,3,1] -> [1,2,3,1].
Write Greeter.greet/2 with a default :en language and clauses for :es, :fr.
Write a with pipeline that parses two strings to integers and divides them, returning {:error, reason} on any failure.
Write a custom guard is_positive_integer/1 and use it.
Implement palindrome?/1 for strings, ignoring case and spaces.