Polimorfismo, classes e inferência de tipos
Deduzir tipos gerais pelas aplicações, padrões e operações usadas, sem confundir classes com tipos.
Polimorfismo e restrições
- Uma variável de tipo representa qualquer tipo compatível.
trocar (x,y) = (y,x)tem tipo(a,b) -> (b,a);duplicar x = (x,x)tem tipoa -> (a,a). - Uma lista exige elementos do mesmo tipo; um par pode combinar tipos. A assinatura
[a] -> anão garante que a função trate[]: generalidade não é cobertura de casos. - Uma classe declara operações disponíveis num tipo. A restrição
Eq a =>permite comparar valores de tipoa; não cria uma classe de objetos.
| Operação | Restrição |
|---|---|
==, /=, elem | Eq |
<, >=, compare | Ord, que exige Eq |
show, read | Show, Read; read pode falhar com texto inválido. |
+, -, *, literais inteiros | Num |
div, mod, quot, rem | Integral |
/, literais fracionários | Fractional |
sqrt, sin, exp | Floating |
Nos GHC atuais, Num não exige Eq. Somar e eliminar repetidos pode exigir (Num a, Eq a); retira restrições redundantes quando uma classe já implica a outra.
Inferir o tipo mais geral
- Dá variáveis de tipo aos argumentos.
- Iguala os tipos impostos por padrões, listas e aplicações.
- Acrescenta as classes pedidas pelas operações e retira as redundantes.
Em duas f x = f (f x), com x :: a, o resultado de f x volta a entrar em f. Logo f :: a -> a e duas :: (a -> a) -> a -> a, sem restrições: nenhuma operação específica é usada.
contem :: Eq a => a -> [a] -> Bool
contem x xs = x `elem` xs
media :: Fractional a => a -> a -> a
media x y = (x+y)/2
Ordenar três valores por comparações e escolher o central exige apenas Ord a. A fórmula x+y+z-minimum [x,y,z]-maximum [x,y,z] exige também Num a e pode perder precisão em vírgula flutuante: o tipo regista as operações, não a equivalência matemática.
Setas, aplicação e conversões
a -> b -> csignificaa -> (b -> c): recebeae devolve uma função. A aplicação associa ao contrário:f x yé(f x) y. Os parênteses em(a -> b) -> a -> bmarcam uma função como argumento.(.) :: (b -> c) -> (a -> b) -> a -> c. A saída da função da direita tem de entrar na função da esquerda.length xs :: Intnão divide com/. UsafromIntegral (length xs); a conversão nunca é automática.- Com divisor não nulo,
div/modarredondam para baixo equot/remtruncam para zero. Para-7e3dão(-3,2)e(-2,-1). Não mistures o quociente de um par com o resto do outro.