Haskell/Casamento de padrões: diferenças entre revisões

[revisão pendente][revisão pendente]
Conteúdo apagado Conteúdo adicionado
m "excessão" não existe.
m <source> -> <syntaxhighlight> (phab:T237267)
 
Linha 10:
Encontramos casamento de padrões em todos os lugares. Considere a função <code>map</code>:
 
<sourcesyntaxhighlight lang="haskell">
map _ [] = []
map f (x:xs) = f x : map f xs
</syntaxhighlight>
</source>
 
Num primeiro instante, identificamos quatro padrões envolvidos, sendo dois por expressão:
Linha 31:
Mesmo com a análise mais detalhada que acabamos de fazer, ainda parece um passe de mágica o fato de podermos desconstruir uma lista que foi unida usando a função <code>(:)</code>. Talvez você queira tentar fazer algo similar com uma lista unida por <code>(++)</code>:
 
<sourcesyntaxhighlight lang="haskell">
eliminarTres ([x,y,z] ++ xs) = xs
</syntaxhighlight>
</source>
 
Você pode testar no GHCi, mas ele retornará um erro. A função <code>(++)</code> não pode ser usada em casamento de padrões. Na verdade, a maioria das funções que não podem ser usadas.
Linha 39:
Mas então, ''quais'' funções podem ser usadas em casmento de padrões? A resposta é simples: ''construtores de tipos''. Por exemplo, considere o tipo:
 
<sourcesyntaxhighlight lang="haskell">
data Foo = Bar | Baz Int
</syntaxhighlight>
</source>
 
Temos que <code>Bar</code> e <code>Baz</code> são construtores do tipo <code>Foo</code>. Sendo assim, podemos usá-los em padrões de argumentos que devem ser do tipo <code>Foo</code>, por exemplo:
 
<sourcesyntaxhighlight lang="haskell">
f :: Foo -> Int
f Bar = 1
f (Baz x) = x - 1
</syntaxhighlight>
</source>
 
Relembrando o [[Haskell/Declaração de tipos|capítulo passado]], é exatamente assim que <code>mostrarData</code> e <code>mostrarAniversario</code> funcionam:
 
<sourcesyntaxhighlight lang="haskell">
data = Data = Data Int Int Int -- ano, mês, dia
 
mostarData :: Data -> String
mostrarData (Data a m d) = show a ++ "-" ++ show m ++ "-" ++ show d
</syntaxhighlight>
</source>
 
O argumento <code>(Data a m d)</code> casa com um tipo de dado <code>Data</code>, que é criado usando o construtor <code>Data</code>, e vincula as variáveis <code>a</code>, <code>m</code> e <code>d</code> aos valores contidos em <code>Data</code>.
Linha 66:
Isso acontece porque <code>(:)</code> é um operador de construção, assim como <code>Data</code>, <code>Bar</code> e <code>Baz</code>. Listas são definidas usando <tt>data</tt>:
 
<sourcesyntaxhighlight lang="haskell">
data [a] = [] | a : [a]
</syntaxhighlight>
</source>
 
Assim, uma lista vazia <code>[]</code>, além de ser um valor por si só, também é um construtor de tipo. A função <code>(:)</code> também é construtora de tipo. Deste modo, a restrição de que ''apenas funções construtoras de tipo podem ser usadas em casamento de padrões'' é satisfeita.
Linha 74:
A forma correta de implementar <code>eliminarTres</code> é convertendo a lista para a notação de cons:
 
<sourcesyntaxhighlight lang="haskell">
eliminarTres (_:_:_:xs) = xs
eliminarTres _ = []
</syntaxhighlight>
</source>
 
O padrão <code>(_:_:_:xs)</code> casa com qualquer lista de pelo menos três elementos. O segundo retorna uma lista vazia caso a entrada tenha dois elementos ou menos.
Linha 87:
Uma analogia semelhante é válida para n-uplas. O construtor deste tipo é o operador vírgula: para duplas, usa-se uma vírgula, <code>(,)</code>; para triplas, duas, <code>(,,)</code>; e assim por diante. Por serem construtores, podemos usar casamento de padrões:
 
<sourcesyntaxhighlight lang="haskell">
fstMaisSnd :: (Num a) => (a, a) -> a
fstMaisSnd (x, y) = x + y
Linha 93:
norma3D :: (Floating a) => (a, a, a) -> a
norma3D (x, y, z) = sqrt (x^2 + y^2 + x^2)
</syntaxhighlight>
</source>
 
Bem como cons, podemos usar <code>(,)</code> como uma função, o que pode ser útil em algumas ocasiões:
Linha 110:
Como já vimos antes, podemos casar padrões com valores literais. Por exemplo:
 
<sourcesyntaxhighlight lang="haskell">
f :: Int -> Int
f 0 = 1
Linha 116:
f 2 = 2
f _ = -1
</syntaxhighlight>
</source>
 
Neste caso, a definição de <code>f</code> esta casando seus argumentos com valores pré-definidos (0, 1 e 2), mais um caso geral (ou de exceção) (<code>_</code>). Em geral, valores específicos podem ser casados individualmente bem como juntos a construtores. Veja:
 
<sourcesyntaxhighlight lang="haskell">
g :: [Int] -> Bool
g (0:[]) = False
g (0:xs) = True
g _ = False
</syntaxhighlight>
</source>
 
A função <code>g</code> retorna False se a entrada for uma lista de um único elemento que seja igual a 0; True se a lista tiver mais que um elemento e a cabeça for igual 0; e False para todos os outros casos. Listas com tamanhos fixos também podem ser usadas para definir um padrão, como <code>[a,b,c]</code>, <code>[1,2,3]</code> ou <code>"abc"</code>.
Linha 131:
Devemos saber, entretanto, que o uso de nomes de variáveis tem contexto limitado. Por exemplo, não podemos definir uma variável fora da função e usá-la no casamento de padrões:
 
<sourcesyntaxhighlight lang="haskell">
k = 1
 
Linha 137:
h k = True
h _ = False
</syntaxhighlight>
</source>
 
O compilador pode aceitar a definição, mas ele não casará o argumento <code>k</code> com a variável global <code>k</code>. Podemos, entretanto, comparar os dois valores dentro da função, desde que eles possuam nomes diferentes:
 
<sourcesyntaxhighlight lang="haskell">
k = 1
 
h :: Int -> Bool
h x = (x == k)
</syntaxhighlight>
</source>
 
{{Exercícios|1=
Linha 158:
 
Por exemplo:
<sourcesyntaxhighlight lang="haskell">
primeiroEsomar :: [Int] -> String
primeiroEsomar lista@[] =
Linha 164:
primeiroEsomar lista@(x:xs) =
"O primeiro elemento é " ++ (show x) ++ " e a soma da lista é " ++ show (sum lista)
</syntaxhighlight>
</source>
 
Aqui usamos <code>lista</code> para nos referirmos ao argumento de entrada de <code>primeiroEsomar</code> e passá-lo para a função <code>sum</code>. No segundo padrão, além disso, temos <code>x</code> casado com a cabeça de <code>lista</code>, e <code>xs</code> com sua cauda.
Linha 172:
Suponha o seguinte tipo definido usando a sintaxe de registros:
 
<sourcesyntaxhighlight lang="haskell">
data Foo = Bar | Baz {numero :: Int, nome :: String}
</syntaxhighlight>
</source>
 
Podemos casar padrões com registros usando apenas os construtores (<code>Bar</code> ou <code>Baz</code>), ou também os campos:
 
<sourcesyntaxhighlight lang="haskell">
f :: Foo -> String
f Bar = "Temos um Bar"
Linha 187:
g Baz {nome = "João"} = 100
g Baz {numero = n} = n * 2
</syntaxhighlight>
</source>
 
Em <code>f</code>, comparamos apenas os construtores. Para casar apenas os construtores de um registro, deve-se acrescenter um par de chaves à esquerda, como em <code>Baz {}</code>. Já em <code>g</code>, os padrões envolvem construres e valores específicos:
Linha 206:
Tanto <code>let</code> quando <code>where</code> são métodos distintos para vincular variáveis de forma local, sem envoler os argumentos de entrada de uma função, por exemplo. Veja:
 
<sourcesyntaxhighlight lang="haskell">
y = let (x:_) = map (*2) [1..3]
in x + 5
Linha 212:
y' = x + 5
where (x:_) = map (*2) [1..3]
</syntaxhighlight>
</source>
 
Tanto <code>y</code> quando <code>y'</code> retornam o mesmo resultado. Em ambos os casos vinculamos a variável <code>x</code> ao primeiro elemento de <code>map (*2) [1..3]</code>.
Linha 219:
 
Também podemos usar casamento de padrões em funções anônimas:
<sourcesyntaxhighlight lang="haskell">
permutar = map (\(x,y) -> (y,x))
</syntaxhighlight>
</source>
 
É claro, entretanto, que a sintaxe das expressões lambdas permitem apenas um padrão por argumento da expressão.
Linha 238:
Dentro de blocos <code>do</code> como os que usamos em [[Haskell/Entradas e saídas simples|Entradas e saídas simples]], podemos usar casamento de padrões do lado esquerdo de vinculações <code><-</code>:
 
<sourcesyntaxhighlight lang="haskell">
putChar = do
(c:_) <- getLine
putStrLn [c]
</syntaxhighlight>
</source>
 
Além disso, ainda podemos usar casamento de padrões dentro expressões <code>let</code> situadas dentro de <code>do</code> da mesma forma que expressões <code>let</code> comuns.