I’m overthinking FizzBuzz in Elixir, refactoring everything possible Elixir way.
Now I’m trying to find a recursive way to put an IO list together so it will result in ["Fizz", ["Buzz"]]
. But I’m quite stuck, recursion is difficult to grasp. So I’ve decided to ask smarter people.
defmodule FizzBuzz do
...
def change(num) do
# Recurse in with an integer in closure
# Recurse out leaving string each step
end
defp name_multiple(num) when rem(num, 3) == 0, do: "Fizz"
defp name_multiple(num) when rem(num, 5) == 0, do: "Buzz"
defp name_multiple(_), do: ""
end
I’m not asking for the simpler solutions of FizzBuzz. I want to join FizzBuzz instead of returning them separately, so it’s more extensible. I also tried to use multi-clause functions and guards as much as I can.
My previous solution is
defmodule FizzBuzz do
@moduledoc """
Name multiples.
* Multiples of 3 => "Fizz"
* Multiples of 5 => "Buzz"
Concatenates when many are applicable.
* Multiples of 3 and 5 => "FizzBuzz"
Unapplicable numbers remain intact.
"""
@spec list(integer) :: list
def list(max) when is_integer(max), do: list(1..max)
@spec list(Enumerable.t()) :: list
def list(enum), do: Enum.map(enum, &change/1)
@spec change(integer) :: integer | String.t()
def change(num) do
num
|> prefer(fizz(num))
|> prefer(buzz(num))
end
defp prefer(old, new) when not new, do: old
defp prefer(old, new) when not is_binary(old), do: new
defp prefer(old, new), do: old <> new
defp fizz(num) when rem(num, 3) == 0, do: "Fizz"
defp fizz(_), do: false
defp buzz(num) when rem(num, 5) == 0, do: "Buzz"
defp buzz(_), do: false
end