Ir para o conteúdo

Casamento de Padrões

Quando especificamos uma função, definimos sua lista de parâmetros formais, isto é, dizemos ao compilador a quais variáveis os parâmetros passados na invocação da função devem ser associados. Por exemplo, considere a seguinte definição de uma função que soma dois números.

soma2n x y = x + y

Quando a seguinte invocação acontece, o valor 3 é associado a x e 4 a y.

> soma2n 3 4
7

Em Haskell, contudo, é possível especificar mais do que uma lista de variáveis como parâmetros formais; é possível especificar padrões a serem casados com os parâmetros passados na invocação. Veremos mais adiante como esse casamento de padrões é poderoso; por enquanto o usaremos apenas como forma de testar a igualdade dos parâmetros a constantes, como uma alternativa à definição de funções usando guardas.

Neste caso, a função é definida como uma sequência de equações em que são feitas tentativas sucessivas de casar (igualar) os argumentos passados com os parâmetros formais, na ordem das definições. O resultado da invocação da função é dado pela primeira equação em que houver um casamento bem sucedido e todas as guardas forem satisfeitas. Se ao final não houver casamento ou se as guardas não forem satisfeitas, ocorre um erro de execução.

Para começar, revisitemos a função nomeMes. Usando casamento de padrões, ela ficaria assim:

nomeMes 1 = "JAN"
nomeMes 2 = "FEB"
nomeMes 3 = "ABR"
nomeMes 4 = "MAR"
nomeMes 5 = "MAI"
nomeMes 6 = "JUN"
nomeMes 7 = "JUL"
nomeMes 8 = "AGO"
nomeMes 9 = "SET"
nomeMes 10 = "OUT"
nomeMes 11 = "NOV"
nomeMes 12 = "DEZ"

Esta função funciona para exatamente os valores na faixa [1,12] e retornará um erro para qualquer valor fora da mesma.

> nomeMes 13
"*** Exception: scratch.hs:(112,1)-(123,18): Non-exhaustive patterns in function nomeMes

Para evitar o erro caso não haja um casamento, é possível usar uma definição genérica catch-all para casar com valores não específicos. Por exemplo, a seguinte definição da função fatorial tem um tratamento especial para 0 e um caso genérico para qualquer outro número.

fatorial 0 = 1
fatorial n = n * fatorial (n-1)

Esta retornará imediatamente o valor 1 caso seja invocada como fatorial 0 e recursivamente calculará o valor do fatorial caso invocada com algum valor maior que 0, por exemplo fatorial 1.

Mas esta definição de fatorial tem um problema, que aparece ao se tentar calcular o fatorial de números negativos, que são indefinidos. Neste caso, precisamos impedir que números negativos sejam aceitos pela função, e podemos fazer isso combinando o casamento de padrões com outra forma de testar os valores dos parâmetros, como if then else e guardas, por exemplo.

fatorial 0 = 1
fatorial n 
    |n > 0 = n * fatorial (n-1)
    |otherwise = error "Indefinido"

Na execução, temos os seguintes resultados.

> fatorial 1
1

> fatorial (-1)
*** Exception: Indefinido