master amadaluzia/rosetta-collatz / elixir / lib / collatz_conjecture.ex
 1defmodule CollatzConjecture do
 2  @moduledoc """
 3  Documentation for `CollatzConjecture`.
 4  """
 5
 6  require Integer
 7
 8  @doc """
 9    Returns the next collatz term of the given `n`.
10
11    If `n` is even, return `n` divided by 2.
12    Otherwise, return 3 multiplied by `n`, plus 1.
13  """
14  @spec collatz(integer) :: integer
15  def collatz(n) when Integer.is_even(n) do
16    div(n, 2)
17  end
18
19  def collatz(n) do
20    3 * n + 1
21  end
22
23  @doc """
24    Returns a string containing the sequence of Collatz terms starting
25    from `n`.
26
27    During the :first iteration, there will be result in `n: ...`.
28    However, :continuing iterations will result in `n, ...`.
29    If `n` is 1 during :continuing iterations, the result will be
30    "1".
31  """
32  @spec collatz_sequence(integer, :first | :continuing) :: String.t()
33  def collatz_sequence(n, :first) do
34    "#{n}: " <> collatz_sequence(collatz(n), :continuing)
35  end
36
37  def collatz_sequence(n, :continuing) when n == 1 do
38    "1"
39  end
40
41  def collatz_sequence(n, :continuing) do
42    "#{n}, " <> collatz_sequence(collatz(n), :continuing)
43  end
44
45  @doc """
46    Returns a string containing the sequence of Collatz terms starting
47    from `n`.
48
49    This is an abstraction for collatz_sequence/2 which always starts
50    with `:first`.
51  """
52  @spec collatz_sequence(integer) :: String.t()
53  def collatz_sequence(n) do
54    collatz_sequence(n, :first)
55  end
56end