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.