Haskell/Declaração de tipos: diferenças entre revisões

[edição verificada][edição verificada]
Conteúdo apagado Conteúdo adicionado
Adicionado →‎Sintaxe de registros: e execícios
Linha 13:
* Usando <tt>newtype</tt> para definir novos tipos equivalentes a outro existente.
 
Neste capítulo usaremos apenas <tt>data</tt> e <tt>type</tt>. Quanto a <tt>newtype</tt>, este método será discutido em capítulos futuros, quando veremosvirmos como ele pode ser útil.
 
== <tt>data</tt> e funções de construção ==
Linha 71:
É importante saber que cada novo tipo declarado com a <tt>data</tt> deve possuir pelo menos um construtor. Nestes casos, você também verá que é conveniente que o construtor tenha mesmo nome que o tipo:
<source lang="haskell">
data DadoDado1 = Dado Dado1 -- DadoDado1 possui apenas um construtor e não recebe nenhum valor adicional
data Dado'Dado2 = Dado'Dado2 Int -- Dado'Dado2 possui apenas um construtor e recebe um valor adicional do tipo Int
</source>
 
Linha 107:
* Reescreva o tipo <tt>Aniversario</tt> usando <tt>Data</tt>.
* Reescreva as funções <code>mostrarData</code> e <code>mostrarAniversario</code> usando as novas declarações de <tt>Data</tt> e <tt>Aniversario</tt>.
* Redefina <code>joaoRomao</code> e <code>romaoCasamento</code>.
}}
 
Linha 130 ⟶ 131:
{{Exercícios|1=
Reescreva a declarção de <tt>Aniversario</tt> usando o sinônimo <tt>Nome</tt>, e mantendo o uso de <tt>Data</tt>.}}
 
== Sintaxe de registros ==
 
O uso de <tt>data</tt> ainda nos permite definir tipos como sendo registros. Por exemplo, o tipo <tt>Data</tt> definido como registro seria:
 
<source lang="haskell">
data Data = Data {ano :: Int, mes :: Int, dia :: Int}
</source>
 
Para definir os valores de cada campo, usamos a mesma sintaxe, sendo que a ordem dos campos não importa:
 
<source lang="haskell">
fimDoSeculoXXI = Data {dia = 31, mes = 12, ano = 2100}
</source>
 
Esta definição cria, também, três ''funções de acesso'': <code>ano</code>, <code>mes</code> e <code>dia</code>. Podemos ver seus tipos no GHCi:
 
{{HaskellGHCi|1=
Prelude> data Data = Data {ano :: Int, mes :: Int, dia :: Int}
Prelude> :t ano
ano :: Data -> Int
Prelude> :t mes
mes :: Data -> Int
Prelude> :t dia
dia :: Data -> Int}}
 
Isso quer dizer que para sabermos o dia armazenado em <code>fimDoSeculoXXI</code>, por exemplo, basta escrever <code>dia fimDoSeculoXXI</code>.
 
Esta sintaxe também ajuda bastante quando precisamos mudar os valores de alguns campos, em vez de todos:
 
<source lang="haskell">
fimDoSeculoXX = fimDoSeculoXXI {ano = 2000}
</source>
 
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:
 
<source lang="haskell">
data Contato = Contato
String -- nome
String -- sobrenome
Int -- telefone
String -- endreço
String -- email
type Agenda = [Contato]
</source>
 
O principal problema de <code>Cotato</code> é que sua definição pode causar confusão sobre o que cada valor deve ser. Usar <code>:i</code> no GHCi não ajuda muito:
 
{{HaskellGHCi|1=
Prelude> :i Contato
data Contato = Contato String String Int String String
-- Defined at registros.hs:1:1}}
 
Se o tipo <code>Contato</code> 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:
 
<source lang="haskell">
data Contato = Contato { nome :: String
, sobrenome :: String
, telefone :: Int
, endereco :: String
, email :: String
}
</source>
 
O GHCi também seria útil neste caso:
 
{{HaskellGHCi|1=
*Main> :i Contato
data Contato
= Contato {nome :: String,
sobrenome :: String,
telefone :: Int,
endereco :: String,
email :: String}
-- Defined at registros.hs:1:1}}
 
Devemos ter cuidado, entretanto, para não criarmos campos de tipos diferentes com mesmo nome dentro de um mesmo programa.<ref group=nota>Mais especificamente, dentro de um mesmo módulo.</ref> Por exemplo, o compilador não aceitaria as seguintes definições, retornando um erro sobre múltiplas declarações de <code>campo1</code>:
 
<source lang="haskell">
data Dado1 = Dado1 {campo1 :: Int}
data Dado2 = Dado2 {campo1 :: Int, campo2 :: String}
</source>
 
{{Exercícios|1=
# Reescreva a função <code>mostrarData</code> usando a declaração de <tt>Data</tt> 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 ==
<references group=nota />
 
[[en:Haskell/Type declarations]]