Uma das linguagens de programação que mais tem me animado ultimamente é a Elixir. Ela possui muitas features legais, e uma delas é o pattern matching.
Patter maching é uma feature, assim como muitas outras, herdada da Erlang, que é a linguagem em que Elixir se basea. Em uma tradução livre, pattern maching quer dizer “casamento de padrão”. O termo é meio exquisito em português, mas vamos a um exemplo:
1
|
|
Nesse exemplo, estamos “casando” o que está do lado direito com um padrão do lado esquerdo. Explico: do lado esquerdo temos uma tupla com o primeiro elemento :ok
e o segundo elemento como uma variável name
.
A linguagem vai tentar fazer bater o tipo e o conteúdo dos dois lados. No caso, o tipo bate:
– é uma tupla;
– o primeiro elemento da tupla bate: :ok
é :ok
;
– o segundo argumento também bate: do lado esquerdo temos uma variável a ser “preenchida”, do lado direito temos um valor para ela.
Agora um exemplo onde o pattern não bate:
1 2 |
|
Por mais que o tipo do segundo elemento seja o mesmo, não há casamento porque os conteúdos das strings são diferentes.
Usando pattern matching em funções
Um dos usos mais poderosos para o pattern maching é na declaração de funções.
Em Elixir, as funções são definidas por três combinações: o seu nome, o número de argumentos, e o “padrão” desses argumentos. Em suma, são definidas pelo nome e argumentos.
Isso quer dizer que uma função somar(numero1, numero2)
é diferente da função somar(numero1, numero2, numero3)
. E as funções check({200, body})
e check({404, body})
são diferentes por conta do padrão de seus argumentos (a diferença do primeiro elemento da tupla).
Uma aplicação muito legal pra isso é na construção de funções recursivas.
O exemplo a seguir mostra como somar números de uma lista através de recursividade. Ele é bem parecido com o encontrado no guia Getting started do site oficial da linguagem, mas considero o meu (IMHO) um pouco mais simples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Como você pode perceber, os nomes das funções são idênticos, mas o que muda são seus argumentos. Todas as três recebem listas, porém cada uma com um padrão diferente:
- A primeira definição recebe uma lista vazia, e como uma lista vazia não tem números, retorna zero;
- A terceira função recebe uma lista e divide ela em duas partes: cabeça e “calda”.
- A cabeça (head) é composta por um único elemento, que é o primeiro elemento da lista;
- A “calda” é o restante da lista. Então uma lista
[2, 3, 4]
será dividida emhead = 2
etail = [3, 4]
. Feito isso, a função ira somar recursivamente o primeiro elemento da lista com o resultado da próxima chamada da função recebendo a lista da calda.
Quando há somente um item na lista, head
é igual a esse elemento, e tail
é vazia ([]).
As chamadas recursivas de “sum_list” serão processadas levando em conta o “padrão” dos argumentos passados. A “condição de parada” da terceira função é quando tail
for uma lista com somente um elemento. Neste caso a função que será utilizada é a segunda, que recebe uma lista com um elemento.
Para onde ir agora?
Nos exemplos usados aqui vimos um pouco do que é possível fazer com o uso de pattern matching. Essa não é uma característica exclusiva da Elixir, mas para mim ficou muito mais fácil de entender com essa linguagem (já havia tentado com Haskell).
Experimente implementar os exemplos e deixe suas dúvidas e sugestões nos comentários.
Recomendo esses links para mais detalhes da linguagem: