Tipos
Seja diasMes
a função que calcula a quantidade de dias em um mês, dado o número do mês, definida assim:
diasMes m
| m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12 = 31
| m == 2 = 28
| otherwise = 30
O que acontece se você passar 7.2 como argumento para a função? O resultado está correto? Isso nos leva a perguntar como definir que uma função só é aplicável a números inteiros, do tipo inteiro.
Em linguagens de programação, um tipo é um nome dado a uma coleção de valores que tem um mesmo comportamento na linguagem.
Em C, por exemplo, temos os tipos int
e short
, ambos associados a valores inteiros mas com número de bits diferentes usados para representá-los.
Algumas linguagens são denominadas fracamente tipadas, o que quer dizer que o uso de tipos é relaxado e pode até ser alterado em tempo de execução.
Por exemplo, no seguinte código em Python a variável x
assume três tipos diferentes, em momentos diferentes.
x = "lala"
print(type(x))
x = 10
print(type(x))
x = 10.0
print(type(x))
<class 'str'>
<class 'int'>
<class 'float'>
Já a linguagem Haskell é o que chamamos de fortemente tipada, o que quer dizer que toda variável, constante, e função tem apenas um tipo e este sempre pode ser determinado. Além disso, Haskell é estaticamente tipada, ou seja, os tipos são determinados em tempo de compilação, em oposição às linguagens dinamicamente tipadas, que determinam o tipo durante a execução do programa.
Para definir o tipo de uma expressão, usa-se após :: <Tipo>
após a mesma, como nos seguintes exemplos.
> x = 1::Int
> y = 1::Integer
> z = 1::Double
Assim como type
em Python, o GHCi tem o comando :type
(ou simplesmente :t
) que permite verificar o tipo de uma expressão. Por exemplo:
> :type x
x :: Int
> :t y
y :: Integer
> :t z
z :: Double
Acontece que se se olharmos novamente para os exemplos de código em Haskell vistos no capítulo anterior, veremos que em lugar algum foram definidos tipos; isto é possível porquê Haskell consegue inferir os tipos dos dados de forma muito acurada, olhando para as funções que manipulam os dados. Por exemplo, na pela definição da função quad x = x*x
, Haskell sabe que x
precisa ser operável com *
, logo, precisa ser um número.
Apesar da capacidade de inferência do Haskell, frequentemente especificamos tipos, principalmente para funções, mais como uma forma de facilitar a leitura e manutenção do código e para indicar sua intenção ao compilador, que irá testar se os tipos indicados podem ser satisfeitos pelo código e lhe informar caso contrário.