Elixir para iniciantes: FizzBuzz
Neste artigo, vou mostrar como resolver o famoso problema FizzBuzz com Elixir e mostrar algumas das principais características da linguagem.
Na minha opinião, o Elixir é uma das linguagens mais interessantes desde Ruby, e eu acho que 2015 vai ser o ano dela. Neste artigo, vou mostrar como resolver o famoso problema FizzBuzz com Elixir e mostrar algumas das principais características da linguagem.
A definição do FizzBuzz é a seguinte:
- Se n é divisível por 3 e 5, substitua por “FizzBuzz”.
- Se n é divisível por 3, substitua por “Fizz”.
- Se n é divisível por 5, substitua por “Buzz”.
- Se n não é divisível nem por 3 nem por 5, apenas é dito n.
Primeiro, vamos criar um módulo com um método para chamar o valor de n que queremos calcular:
defmodule FizzBuzz do
def compute(n) do
fizzbuzz(rem(n, 3), rem(n, 5), n)
end
end
Agora, vamos criar um método fizzbuzz/3 para resolver a primeira condição do problema:
1. Se n é divisível por 3 e 5, substitua por “FizzBuzz”
defmodule FizzBuzz do
def compute(n) do
fizzbuzz(rem(n, 3), rem(n, 5), n)
end
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
end
Fácil, não? Se rem(n,3) é zero e rem(n,5) também é zero, nós queremos substituir por “FizzBuzz”. Agora, vamos implementar a segunda e a terceira condições:
2. Se n é divisível por 3, substitua por “Fizz”
3. Se n is divisível por 5, substitua por “Buzz”
defmodule FizzBuzz do
def compute(n) do
fizzbuzz(rem(n, 3), rem(n, 5), n)
end
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
defp fizzbuzz(0, _, _), do: IO.puts "Fizz"
defp fizzbuzz(_, 0, _), do: IO.puts "Buzz"
end
E precisamos de um último método para cobrir a quarta condição:
4. Se n não é divisível nem por 3 nem por 5, apenas é dito n
defmodule FizzBuzz do
def compute(n) do
fizzbuzz(rem(n, 3), rem(n, 5), n)
end
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
defp fizzbuzz(0, _, _), do: IO.puts "Fizz"
defp fizzbuzz(_, 0, _), do: IO.puts "Buzz"
defp fizzbuzz(_, _, n), do: IO.puts n
end
Com isso, podemos chamar nosso módulo e checar o valor de n, assim:
FizzBuzz.compute(15) >> FizzBuzz FizzBuzz.compute(2) >> 2 FizzBuzz.compute(5) >> Buzz FizzBuzz.compute(12) >> Fizz
Mas ainda não terminamos. Para resolver o problema FizzBuzz, nós precisamos passar o n, e o módulo retornar o valor de n para cada número (começando com 1) até que n seja atingido.
Nós precisamos de um método start/1 que vai receber n e começar a contagem com 1. E mudar o método compute/1 para receber os valores de n e a contagem além de adicionar um recurso.
defmodule FizzBuzz do
def start(n), do: compute(n, 1)
defp compute(n, count) do
fizzbuzz(rem(count, 3), rem(count, 5), count)
compute(n, count + 1)
end
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
defp fizzbuzz(0, _, _), do: IO.puts "Fizz"
defp fizzbuzz(_, 0, _), do: IO.puts "Buzz"
defp fizzbuzz(_, _, n), do: IO.puts n
end
Uma vez que o recurso nunca termina, nós precisamos de alguma coisa a mais, como uma Guard clause, no nosso método compute/2.
defmodule FizzBuzz do
def start(n), do: compute(n, 1)
defp compute(n, count) when count <= n do
fizzbuzz(rem(count, 3), rem(count, 5), count)
compute(n, count + 1)
end
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
defp fizzbuzz(0, _, _), do: IO.puts "Fizz"
defp fizzbuzz(_, 0, _), do: IO.puts "Buzz"
defp fizzbuzz(_, _, n), do: IO.puts n
end
Mas se nós só fizermos isso, receberemos um erro:
** (FunctionClauseError) no function clause matching in FizzBuzz.compute/2
Isso acontece porque precisamos de um método para terminar a chamada recursiva. Então, vamos adicionar:
defmodule FizzBuzz do
def start(n), do: compute(n, 1)
defp compute(n, count) when count <= n do
fizzbuzz(rem(count, 3), rem(count, 5), count)
compute(n, count + 1)
end
defp compute(_, _), do: IO.puts ""
defp fizzbuzz(0, 0, _), do: IO.puts "FizzBuzz"
defp fizzbuzz(0, _, _), do: IO.puts "Fizz"
defp fizzbuzz(_, 0, _), do: IO.puts "Buzz"
defp fizzbuzz(_, _, n), do: IO.puts n
end
E é isso! Uma versão elegante do FizzBuzz com Elixir.
Ficou alguma dúvida, tem alguma sugestão ou crítica? Aproveite os campos abaixo. Até a próxima!







