Elixir :: Function, Pattern Matching, default values e when
Tags: elixir, beginners, programming, tutorial
Published: 2022-01-15 12:56:28

Em Elixir o pattern matching não está apenas associado com variáveis, mas também com function, podemos utilizar pattern matching em nossas functions, tornando nossas functions específica para cada situação.

Vamos pensar em um jogo de adivinhação, queremos criar um jogo onde podemos adivinhar um número secreto. Com base no número que você recebe como palpite, você pode ter as seguintes saídas:

| Condição | Respostas |
| --- | --- |
| Quando o palpite corresponde ao número secreto | Correto |
| Quando o palpite é um a mais ou um a menos que o número secreto | Próximo |
| Quando o palpite é maior que o número secreto | Maior |
| Quando o palpite for menor que o número secreto | Menor |
| Quando um palpite não é feito | Faça um palpite |
- Todas as suposições e números secretos são números inteiros.

O nosso programa tem as seguintes regras:

**1. Dê resposta quando o palpite corresponder ao número secreto**

Vamos implementar a função `compare/2` que recebe dois argumentos, `secret_number` e `guess`, que são ambos inteiros.

```elixir
GuessingGame.compare(5, 5)
# => "Correto"
```

**2. Dê resposta quando o palpite for maior que o número secreto**

Nesta situação queremos que a função de comparação responda com `Maior`.

```elixir
GuessingGame.compare(5, 8)
# => "Maior"
```

**3. Dê resposta quando o palpite for menor que o número secreto**

Nesta situação queremos que a função de comparação responda com `Menor`.

```elixir
GuessingGame.compare(5, 2)
# => "Menor"
```

**4. Dê respostas quando o palpite for um a mais ou um a menos que o número secreto**

Nessa situação se o valor inserido tiver diferença de 1 seja para maior ou menor queremos que a função de comparação responda com `Próximo` 

```elixir
GuessingGame.compare(5, 6)
# => "Próximo"
GuessingGame.compare(5, 4)
# => "Próximo"
```

**5. Dê resposta quando não houver palpite**

Nessa situação queremos que quando não houve palpite, a função compare responda com `Faça um palpite`

```elixir
GuessingGame.compare(5)
# => "Faça um palpite"
GuessingGame.compare(5, :no_guess)
# => "Faça um palpite"
```

E como podemos resolver este problema? Como falamos anteriormente o Elixir possui um Pattern Matching que também podemos usar em functions. Então, para iniciar nossa implementaçao vamos começar pela parte onde não enviamos palpite.

Inicialmente vamos começar com a function que recebe apenas 1 parâmetro, vamos definir a nossa function para retornar exatamente o que esperamos, que é uma string: “Faça um palpite”

```elixir
defmodule GuessingGame do
  def compare(secret_number), do: "Faça um palpite"
end
```

Ok, assim sabemos que ao chamar a function `GuessingGame.compare(1)` por exemplo, receberemos como retorno a frase "Faça um palpite”

```elixir
iex(1)> GuessingGame.compare(1)
"Faça um palpite"
```

Mas também queremos que quando executarmos `GuessingGame.compare(1, :no_guess)` também receber o mesmo resultado. Para solucionar esse problema vamos precisar utilizar do default value e também do when. 

Em Elixir, podemos definir parâmetros em nossas functions com valores defaults e com `when` podemos escolher que function executar a partir desta condição. Levando isto em consideração, nossa solução final facaria assim:

```elixir
defmodule GuessingGame do
  def compare(secret_number, guess \\ :no_guess)
  def compare(secret_number, guess) when guess == :no_guess, do: "Faça um palpite"
end
```

E o resultado seria como este:

```elixir
iex(1)> GuessingGame.compare(1)
"Faça um palpite"
iex(2)> GuessingGame.compare(1, :no_guess)
"Faça um palpite"
```

Agora, para atender as demais questões levantadas em nosso sistema, podemos utilizar o when para definir as demais funções e solucionar nosso problema.

```elixir
defmodule GuessingGame do
  def compare(secret_number, guess \\ :no_guess)
  def compare(secret_number, guess) when guess == :no_guess, do: "Faça um palpite"
  def compare(secret_number, guess) when secret_number == guess, do: "Correto"
  def compare(secret_number, guess) when secret_number - 1 == guess, do: "Próximo"
  def compare(secret_number, guess) when secret_number + 1 == guess, do: "Próximo"
  def compare(secret_number, guess) when  secret_number > guess, do: "Menor"
  def compare(secret_number, guess) when  secret_number < guess, do: "Maior"
end
```