# Haskell/Declaração de tipos

* Declaração de tipos
* Básico
* Recursividade
* Listas II (listas infinitas, map)
* Listas III (folds, compreensão)
* Declaração de tipos
* Lambdas e operadores
* Casamento de padrões
* Estruturas de controle: case
* Funções de alta ordem
* Usando o GHCi
Em Haskell, e muitas outras linguagens de programação, não estamos limitados a trabalhar apenas com o tipos de dados predefinidos. Na verdade, há muitas vantagens em definirmos nossos próprios tipos:
* O código pode ser escrito em termos do problema a ser resolvido, o que os torna fácil de serem desenvolvidos, escritos e entendidos.
* Dados correlacionados podem ser organizados e trabalhados de formas mais convenientes do que apenas tratá-los como elementos de listas ou n-uplas.
* Podemos usar casamento de padrões e o sistema de tipos de Haskell em todo seu potencial, fazendo ambos funcionarem com nosso próprios tipos.
Em Haskell, temos três maneiras básicas para declaração de tipos:
* Usando data para novos tipos.
* Usando type para declarar sinônimos de tipos, isto é, nomes alternativos para tipos já existentes.
* Usando newtype para definir novos tipos equivalentes a outro existente.
Neste capítulo usaremos apenas data e type. Quanto a newtype, este método será discutido em capítulos futuros, quando virmos como ele pode ser útil.

## data e funções de construção

Usamos data para criar novos tipos baseando-nos principalmente em outros já existentes. Por exemplo, para uma lista simples de datas de aniversário:
* Um aniversário pode ser de casamento ou aniversário, por exemplo.
** Se for de nascimento, devemos armazenar o nome de uma pessoa. Este dado deve ser um String.
** Se for de casamento, devemos armazenar o nome dos dois cônjuges. Estes dados devem ser Strings.
* Uma data contém três números: dia, mês e ano.
** É possível que usar a ordem ano-mês-dia ajude na ordenação das datas, ou evite equívocos de interpretação. Estes dados devem ser Int.
Agora que já definimos o que queremos armazenar, podemos definir o tipo Aniversario usando data:
O tipo Aniversario possui dois construtores de tipo: Nascimento e Casamento, sendo que cada um deles exige certos valores, como já vimos no nosso esboço. Estes construtores também pode ser chamados de funções de construção ou funções construtoras.
Abra o GHCi e tente:
Isso quer dizer que Nascimento pode ser usado como função, cujos argumentos são um String e três Ints, e cuja saída é um dado do tipo Aniversario. O mesmo vale para Casamento, que possui cinco argumentos:
Já que podemos tratar construtores de tipos como funções, podemos usá-los como funções normais. Por exemplo, para armazenar o aniversário de João Romão, nascido no dia 3 de julho de 1968:
Ele se casou com Maria Romão no dia 4 de março de 1987:
Apesar de armazenarem dados diferentes, joaoRomao e romaoCasamento são ambos do tipo Aniversario. Isso quer dizer que podemos armazená-los juntos numa única lista:
Também poderíamos ter criado a lista sem variáveis intermediárias, mas o código poderia não ficar tão legível:
É importante saber que cada novo tipo declarado com a data deve possuir pelo menos um construtor. Nestes casos, você também verá que é conveniente que o construtor tenha mesmo nome que o tipo:

## Acessando valores armazenados

Usar novos tipos de dados só é útil se pudermos acessar o conteúdo que eles armazenam. Só podemos fazer isso se criarmos funções apropriadas para tais tarefas.
Para nosso exemplo acima, uma operação muito útil seria extrair os nomes e as datas armazenadas, e poder apresentá-los em forma de String. Para isso, criamos uma função chamada mostrarAniversario. Como temos que converter os valores numéricos das datas em String, podemos criar também a função auxiliar mostrarData que usa show para converter os números:
Usamos casamento de padrões para criar mostrarAniversario. São dois padrões: um deles casa com dados construídos com Nascimento, o outro casa com dados construídos com Casamento. Depois de definir o construtor, definimos as variávies de vínculo (binding variables, em inglês). Estes são os nomes que damos para cada valor contido no dado, como nome, ano ou mes, por exemplo. Poderíamos ter escrito Nascimento n a m d e depois usado n, a, m, e d para nos referirmos a cada valor ao longo da definição da função, mas usar nomes mais expressivos deixa o código mais claro.
Os parênteses em torno do nome do construtor e das variáveis vinculadas são obrigatórios, senão, o compilador não criaria mostrarAniversario como sendo uma função de um argumento só. Também é importante saber que a expressão dentro dos parênteses não é uma chamada para as funções de construção, isto é, Casamento nome1 nome1 ano mes dia não será avaliada, pois trata-se apenas de uma descrição do padrão.
Por fim, podemos carregar tudo no GHCi e testar:
* Exercícios
* Observe a função mostrarData. Ela existe apenas para deixar mais clara a definição mostrarAniversario. Note que são passados três argumentos a ela: um ano, um mês e um dia, representados por Ints. Sabemos que não faz sentido passar os argumentos fora de ordem pois são parte de uma data única. Poderíamos, portanto, criar um tipo Data para armazenar apenas datas e evitar confusões:
* Declare um tipo Data que armazene três Ints para representar ano, mês e dia.
* Reescreva o tipo Aniversario usando Data.
* Reescreva as funções mostrarData e mostrarAniversario usando as novas declarações de Data e Aniversario.
* Redefina joaoRomao e romaoCasamento.

## Criando sinônimos de tipo com type

Como dito no começo deste capítulo, ter mais clareza é um dos objetivos que nos leva a criar novos tipos. Neste sentido, seria bom poder deixar claro que os String em Aniversario são nomes e ainda poder manipulá-los como um String comum. Para isso, podemos usar a palavra-chave type para criar um sinônimo:
Esta linha quer dizer que Nome agora é um sinônimo de String. Isso quer dizer que qualquer função que aceite um dado String também aceitará um do tipo Nome, e vice-versa. O lado direito da expressão também pode ser um tipo mais complexo. O próprio tipo String é sinônimo de uma lista de Char, e podemos confirmar isso usando o comando :info (ou :i) no GHCi para obter informações sobre os tipos e outras funções:
GHC.Base é onde está definido o Prelude. Podemos fazer algo semelhante para uma lista de aniversários:
Sinônimos são, em geral, apenas uma conveniência. Eles geralmente nos ajudam a esclarecer o papel tipos complexos -- como listas, n-uplas ou funções -- dentro de um certo contexto. Entretanto, deve-se evitar o uso em excesso dos sinônimos, pois o código pode se tornar bastante confuso: um código que usa vários sinônimos diferentes para um mesmo tipo pode dificultar o seu entendimento.
* Exercícios
* Reescreva a declarção de Aniversario usando o sinônimo Nome, e mantendo o uso de Data.

## Sintaxe de registros

O uso de data ainda nos permite definir tipos como sendo registros. Por exemplo, o tipo Data definido como registro seria:
Para definir os valores de cada campo, usamos a mesma sintaxe, sendo que a ordem dos campos não importa:
Esta definição cria, também, três funções de acesso: ano, mes e dia. Podemos ver seus tipos no GHCi:
Isso quer dizer que para sabermos o dia armazenado em fimDoSeculoXXI, por exemplo, basta escrever dia fimDoSeculoXXI.
Esta sintaxe também ajuda bastante quando precisamos mudar os valores de alguns campos, em vez de todos:
Registros são especialmente úteis quando precisamos criar variáveis que armazenem muitos valores. Por exemplo, sem usar a sintaxe de registros, uma agenda de contatos — onde usamos Int para representar números de telefone — poderia ser:
O principal problema de Cotato é que sua definição pode causar confusão sobre o que cada valor deve ser. Usar :i no GHCi não ajuda muito:
Se o tipo Contato fosse criado como um registro, uma vez que damos nomes para cada campo, esse mesmo problema não existiria, pois saberíamos exatamente o que campo deve ser:
O GHCi também seria útil neste caso:
Devemos ter cuidado, entretanto, para não criarmos campos de tipos diferentes com mesmo nome dentro de um mesmo programa. Por exemplo, o compilador não aceitaria as seguintes definições, retornando um erro sobre múltiplas declarações de campo1:
* Exercícios
* Reescreva a função mostrarData usando a declaração de Data na forma de registro.
* Trantado-se de registros e dentro de um mesmo módulo, por que dois campos, de dois tipos diferentes, não podem ter o mesmo nome?

## Notas

* ↑ Mais especificamente, dentro de um mesmo módulo.