Dev (Back & Front)ARTIGO

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:

  1. Se n é divisível por 3 e 5, substitua por “FizzBuzz”.
  2. Se n é divisível por 3, substitua por “Fizz”.
  3. Se n é divisível por 5, substitua por “Buzz”.
  4. 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!

É desenvolvedor de software na Concrete Solutions. Apaixonado por Ruby, AngularJS e Elixir, fez Computação na UFF, lê um livro por semana e segue a dieta à risca.

Ver perfil