I’m reading Programming Elixir ≥ 1.6 right now and there are two interesting examples of coding Fizzbuzz.
defmodule Fizzbuzz do
def upto(n) when n > 0, do: _upto(1, n, [])
defp _upto(_current, 0, result), do: Enum.reverse(result)
defp _upto(current, left, result) do
next_answer =
cond do
rem(current, 3) == 0 and rem(current, 5) == 0 -> "Fizzbuzz"
rem(current, 3) == 0 -> "Fizz"
rem(current, 5) == 0 -> "Buzz"
true -> current
end
_upto(current+1, left-1, [next_answer | result])
end
end
This is the output:
iex> Fizzbuzz.upto(20)
[1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz","Buzz", 11, "Fizz", 13, 14, "Fizzbuzz", 16, 17,
"Fizz", 19, "Buzz"]
Here the function upto is the trampoline for the function. It calls the private function _upto as long as the input n is greater than 0._upto is the recursive function with accumulator. When n reaches 0, it spits out the accumulator result. We need Enum.reverse because the main function builds up the list in the wrong order.
The second case is the workhorse function. It sets up a binding for next_answer which determines whether a number satisfies one of the Fizzbuzz conditions. Then it recurses until done.[next_answer | result] builds the list with next_answer as the head and result as the tail.
The book also has an interesting second example which uses Enum.map and pattern matching.
defmodule Fizzbuzz do
def upto(n) when n > 0, do: 1..n |> Enum.map(&fizzbuzz/1)
defp fizzbuzz(n), do: _fizzword(n, rem(n, 3), rem(n, 5))
defp _fizzword(_n, 0, 0), do: "Fizzbuzz"
defp _fizzword(_n, 0, _), do: "Fizz"
defp _fizzword(_n, _, 0), do: "Buzz"
defp _fizzword(n, _, _), do: n
end
Here, upto maps over the range of 1 to the input number with the private function fizzbuzz.
And fizzbuzz uses _fizzword and pattern matching to determine the output result.
I find Elixir’s pattern-matching novel, as I haven’t encountered a language that does things this way.