Apresentação

Disciplina ministrada na Universidade do Estado de Santa Catarina (Udesc), no Departamento de Ciência da Computação (DCC) do Centro de Ciências Tecnológicas (CCT), campus Joinville/SC, para o curso de Bacharel em Ciência da Computação, durante os semestres de 2008 e 2009.

Objetivo

Ementa

Horário

Softwares Utilizados

Notas de Aula

Ranges e List Comprehension

Ranges

Ranges são uma forma de criar listas numeráveis de maneira aritmética. Portanto, qualquer limite numérico ou que apresente uma ordem crescente é um range. Tudo que pode ser enumerado, pode ser criado com um range. Números podem ser enumerados. Caracteres podem ser enumerados:

Assim, ao invés de escrever os números de 1 a 10 como:

 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

podemos escrever utilizando um range

 [1 .. 20]

que o resultado será equivalente.

O mesmo é válido para caracteres

 ['a' .. 'z']

ou

 ['D' .. 'M']

Podemos também especificar um passo para o range. Por exemplo,

 [1, 3 .. 30]

produzirá uma lista de 1 a 30, pulando os elementos de 2 a 2. Isso aplica-se também a caracteres

 ['a', 'd' .. 'z']

e é bastante útil para representarmos elementos enumeráveis em ordem decrescente. Por exemplo,

 [30, 29 .. 0]

irá produzir uma lista com os valores de 30 à 0.

Com ranges podemos representar sequências de dados infinitas. Por exemplo, se quizermos todos os números maiores que 10, basta

 [10, ..]

se quizermos todos os múltiplos de 13

 [13, 26, ..]

claro que isso irá produzir uma sequência sem fim. Porém é bastante útil para situações onde queremos os primeiros 10 múltiplos de 13, por exemplo. Teríamos algo como

 take 10 [13, 26 ..]

isso funciona graças à avaliação preguiçosa de Haskell, já que o interpretador não tem gerar toda a lista de números, preocupando-se primeiramente em coletar somente os 10 primeiros elementos da lista e só então gerando-a. As 15 primeiras letras do alfabeto poderiam ser obtidas portando por:

 take 15 ['a', 'b' ..]

Algumas funções úteis quando trabalhamos com conjuntos infinitos são a cycle e a repeat:

cycle
toma uma lista e repete-a eternamente
take 10 (cycle ['foo', 'bar'])
repeat
como o nome sugere, repete um elemento indefinidamente
take 10 (repeat 2)

É interessante notar que quando trabalhamos com conjuntos infinitos de dados, devemos de alguma maneira limitá-los. Isso justifica o uso constante da função take.

List Comprehension

A compreensão de listas já é comum para nós. Usamos elas em matemática. Por exemplo, para representarmos os números naturais pares menores que 100, podemos fazê-lo através da fórmula

 A = {x | x PERTENCE {1, 2, .. 100}, x mod 2 == 0}

onde x é chamada de função de saída, x PERTENCE {1, 2, .. 100} é o conjunto de entrada e x mod 2 == 0 é o predicado. Podemos representar exatamente esta lista de termos em Haskell através de

 [x | x <- [1 .. 100], x `mod` 2 == 0]

O predicado é opcional. Se quizermos, por exemplo, os números de 2 a 20, podemos fazer

 [x | x <- [2 .. 20]]

Se quizermos os números dobrados de 1 a 100, basta fazer

 [x*2 | x <- [1 .. 100]]

ou os mesmos, só que somente os maiores de 20

 [x*2 | x <- [1 .. 100], x*2 > 20]

Se quisermos os números de 50 a 1000 onde o resto da divisão deles por 6 seja 2, torna-se fácil usando compreensão

 [x | x <- [50 .. 1000], x `mod` 6 == 2]

Ou os números ímpares de 1 a 10

 [x | x <- [1 .. 10], odd x]

Ou se quizermos uma lista com strings iguais a "par" para os pares e "impar" para os ímpares:

 [if (odd x) then "impar" else "par" | x <- [1 .. 10]]

Podemos também inclur quantos predicarmos quizermos:

 [x | x <- [10 .. 20], x /= 13, x /= 15, x /= 19]

Ainda, podemos ter quantos conjuntos de entrada desejarmos. Por exemplo, para termos uma lista de tuplas de todas as combinações possíveis dos conjuntos [1, 2, 3, .. 10] e [100, 102, 104, .. 120] basta

 [(x, y) | x <- [1 .. 10], y <- [100, 102 .. 120]]

Ou a multiplicação de todas as combinações possíveis de dois conjuntos

 [x*y | x <- [2,5,10], y <- [8,10,11]]  

Ou digamos que os senhor e senhora Silva querem escolher um nome para seu novo filho mas não sabem qual combinação seja a melhor. A compreensão de listas pode ajudar:

 [ x ++ " " ++ y | x <- ["Luiz", "Pedro", "Paulo", "João", "Inácio"], y <- ["Silva", "da Silva"]]

Alguns outros exemplos interessante:

 sum [1 | _ <- [10 .. 100] -- com isso podemos criar a função: tamanho x = sum [1 | _ <- x]

 [c | c <- "Oi João Pedro", c `elem` ['A'..'Z']] -- lembre-se, strings são listas!

Exercícios e Trabalhos Práticos

  • Exercício sobre Ranges e List Comprehensions: analise os dois últimos exercícios dados em sala de aula e resolva-os (quando aplicável) utilizando os conceitos de ranges e compreensão de listas.
    • Entrega: 19/05 - 23:59 no email do prof.

Referências


Page last modified on May 12, 2009, at 10:15 AM