Logo Passei Direto
Buscar

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

Notas de Aula - Programação I
Tipos de Dados Parte 3
Evelin Carvalho Freire de Amorim
10 de abril de 2012
Nas aulas anteriores vimos os tipos numéricos (inteiro e real) e booleano. Nesta aula veremos três
tipos de dados restantes do Haskell: caracteres, tuplas e listas.
1 Caracteres
Caracteres não são tão interessantes matematicamante, porém na computação podemos utilizar os car-
acteres para, por exemplo, processar palavras. Por qual motivo poderíamos querer processar palavras?
Existem vários problemas que envolvem processar palavras:
1. Comparar duas palavras e verificar se as duas são iguais;
2. Contar o número de letrar em uma palavra;
3. etc.
Em Haskell nós temos o tipo caracter para representar símbolos de uma palavra. Qualquer símbolo
entre aspas simples é considerado um caracter. O tipo caracter é definido pela palavra Char. Veja a
seguir alguns exemplos:
Exemplo: 'a' '@' '1'
Para processar caracteres de forma mais fácil foram criados vários padrões que associam um caracter
a um número. Um dos primeiros padrões e o mais difundido foi o ASCII. São 128 caracteres associados
a algum número. Veja na Figura 1 a tabela Ascii. Esta tabela já foi extendida para comportar símbolos
de outras línguas.
Figura 1: Tabela ASCII
1
A seguinte função em Haskell determina se um determinado caracter é um número.
ehNum :: Char -> Bool
ehNum x = '0' <= x && x <= '9'
Veja que os operadores de comparação servem para carateres também. Podemos fazer funções pare-
cidas para checar se um caracter é maísculo ou minúsculo.
ehMaiscula :: Char -> Bool
ehMaiscula x = 'A'<=x && x<='Z'
ehMinuscula :: Char -> Bool
ehMinuscula x = 'a'<=x && x<='a'
Exercício 1): Faça uma função em Haskell que passe uma letra maíscula para minúscula e outra que
faz o inverso.
1.1 Tuplas
Uma forma de combinar tipos para formar novos é formando pares com eles. Por exemplo, (Integer,Char)
consiste de todos os pares de valores para os quais o primeiro componente é um inteiro e o segundo um
caracter. O tipo tupla aceita não apenas pares, mas quantos o usuário definir.
Exemplo: ('a',1) (1,1,1) (1,(2.0,'a'))
Segue aqui duas funções simples para uma tupla de dois elementos.
primeiro :: (a,b) -> a
primeiro (x,y) = x
segundo :: (a,b) -> b
segundo (x,y) = y
Exercício 2) Teste as funções primeiro e segundo com os exemplos de tuplas acima.
Exercício 3) Considere agora tuplas com 4 elementos. Faça as funções primeiro, segundo, terceiro
e quarto, para pegar respectivamente o primeiro, o segundo, o terceiro e o quarto elemento da tupla.
1.2 Listas
Uma lista é tipo de dado que representa um sequência de elementos, os quais devem ser dos mesmo tipos.
No Haskell é possível a representação de listas infinitas, mas dado o escopo do nosso curso vamos apenas
trabalhar com listas finitas.
Uma lista finita é denotada utilizando chaves e vírgulas. Por exemplo, [1,2,3] é uma lista de três
números e ['a','b'] é uma lista de dois caracteres. A lista vazia é representada por [] e uma lista com apenas
um elemento a é escrita [a].
Exemplo: A seguir alguns exemplos de lista e seus tipos.
[1,2,3] :: [Integer]
['h','a','s','k','e','l','l'] :: [Char]
[ [1,2],[3]] :: [[Char]]
Diferentemente de um conjunto uma lista pode ter elementos repetidos. Por exemplo, [1,1] é uma lista
de dois elementos. O primeiro elemento de uma lista é chamado cabeça da lista e o a lista sem o primeiro elemento
é chamado de cauda da lista. Por exemplo, a acabeça da lista [1,1] é 1 e a cauda dela é [1].
Em listas acrescenta-se um novo elemento usando-se um operador definido em Haskell como dois
pontos �:� . Tal operador é o separador de um elemento da lista. Por exemplo:
2
Prelude> 1:[]
[1]
Prelude> 2:[1]
[2,1]
Veja que o elemento sempre é adicionado no início da lista. Agora digamos que queremos a cauda da
lista, então definimos a função a seguir.
cauda :: [a] -> [a]
cauda (x:xs) = xs
Primeiro vamos olhar a assinatura de tipo da função acima. Ele deve receber como entrada uma lista
que possui elementos do tipo a e a saída é uma lista com elementos do tipo a. Então se chamamos a
função acima devemos colocar uma lista, como a seguir
1 cauda [1,2,3,4,5]
2 ⇒ cauda 1:[2,3,4,5]
3 ⇒ [2,3,4,5]
Na primeira linha fazemos a instânciação da função cauda. A segunda é possui um racícionio um
pouco mais complicado. Sabemos que o operador �:� acrescenta um elemento na lista, então é razoável
que [1,2,3,4,5] == 1:[2,3,4,5]. O resultado da aplicação de �1:� em [2,3,4,5] é o lado esquerdo da igualdade,
então podemos afirmar que elas são equivalentes. Se são equivalente eu posso substituir um pelo outro,
e desta forma chegamos no mesmo formato da definição da função cauda.
Agora se eu quiser a cabeça da lista? Então a seguinte definição de função satisfaz como solução.
cabeca :: [a] -> a
cabeca (x:xs) = x
Nesta solução temos o mesmo caso de cauda. Segue a instânciação e a resolução mecânica de um
exemplo instânciando a função cabeca.
1 cabeca [1,2,3,4,5]
2 ⇒ cabeca 1:[2,3,4,5]
3 ⇒ 1
Existem também algumas operações que podem ser aplicadas em elementos do tipos lista.
Posição: Para capturar um elemento em uma determinada posição na lista basta utilizar o operador
!!.
Exemplo:
Prelude> [1,2,3,4,5]!!0
1
Prelude> [1,2,3,4,5]!!2
3
Concatenação: Duas listas podem ser concatenadas para formar uma lista maior. Esta função é
denotada pelo operador binário ++.
Prelude> [1,2,3]++ [4,5]
[1,2,3,4,5]
Prelude> [1,2] ++ [] ++ [1]
[1,2,1]
Assim como a soma na aritmética o operador ++ é associativo e tem como elemento identidade [].
Em outras palavras:
3
(xs ++ ys) ++ zs = xs ++ (ys ++zs)
[] ++ xs = xs ++ [] = xs
para qualquer lista xs, ys, e zs.
Tamanho: O tamanho de uma lista finita é o número de elementos que ela contém. A operação
utilizada para saber o tamanho de uma lista é a função length.
Prelude> length [1,2,3,4,5] 5
Prelude> length [] 0
Prelude> length ['a','b','c','d','e'] 5
Cabeça e Cauda: A função head do Haskell existe por padrão e sua saída é a cabeça. Segue alguns
exemplos:
Prelude> head [1,2,3,4,5] 1
Prelude> head [] *** Exception: Prelude.head: empty list
Prelude> head ['a','b','c','d','e'] 'a'
Exercício 4) Qual das igualdades abaixo são verdadeiras e quais são falsas?
a) [[]] + +xs == xs
b) [[]] + +xs == [xs]
c) [[]] + +xs == [[], xs]
d) [[]] + +[xs] == [[], xs]
e) [xs] + +[] == [xs]
f) [xs] + +[xs] == [xs, xs]
Exercício 5) Qual o valor de [head xs] ++ tail xs quando xs é igual a []?
1.3 Strings
As strings em Haskell são uma sequência de caracteres. Dado este fato, a representação interna das strings
são listas de caracteres e todas as funções e operadores de listas servem para strings. A representação
explícita de strings, no entanto, pode ser feitas através de aspas duplas.
Veja um exemplo de uma função que pega o primeiro caracter de uma string.
cabecaStr :: String -> Char
cabecaStr (x:xs) = x
Testando:
Prelude> cabecaStr �teste�
't'
Podemos redefinir a cabecaStr como se segue:
cabecaStr :: [Char] -> Char
cabecaStr (x:xs) = x
E testá-la da mesma forma.
Prelude> cabecaStr �teste�
't'
4

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?