• Nenhum resultado encontrado

MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO

N/A
N/A
Protected

Academic year: 2021

Share "MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO"

Copied!
66
0
0

Texto

(1)

MATEMÁTICA DISCRETA: RESOLUÇÃO

DE PROBLEMAS COM O AUXÍLIO DA

COMPUTAÇÃO

José Luiz dos Anjos Rosa

jrosa@uezo.rj.gov.br

Novembro 2004

(2)

Índice

1. Introdução à Linguagem Haskell ________________________________________ 1

1.1. O que é o Haskell ________________________________________________________ 1

1.2. Matemática Discreta e Haskell _____________________________________________ 1

1.3. Como é um Programa em Haskell __________________________________________ 1

1.4. Tipos em Haskell ________________________________________________________ 3

1.5. Operadores em Haskell ___________________________________________________ 4

1.5.1. Aritméticos ________________________________________________________________ 4 1.5.2. Relacionais ________________________________________________________________ 5 1.5.3. Lógicos ___________________________________________________________________ 5 1.5.4. Divisibilidade ______________________________________________________________ 5 1.5.5. Operações com Números Racionais _____________________________________________ 6

1.6. Tipo Char ______________________________________________________________ 6

1.7. Listas __________________________________________________________________ 7

1.7.1. Definição __________________________________________________________________ 7 1.7.2. Lista com um só Elemento ____________________________________________________ 8 1.7.3. Lista Vazia _________________________________________________________________ 8 1.7.4. Listas Iguais ________________________________________________________________ 8 1.7.5. Progressão Aritmética (PA) ____________________________________________________ 9 1.7.6. Termo Geral de uma PA ______________________________________________________ 9 1.7.7. Progressão Geométrica (PG) ___________________________________________________ 9 1.7.8. Termo Geral de uma PG ______________________________________________________ 9

1.8. Representando Conjuntos através de Listas _________________________________ 10

1.8.1. Descrição _________________________________________________________________ 10 1.8.2. Sub-Lista _________________________________________________________________ 10 1.8.3. Diferença entre Listas _______________________________________________________ 11 1.8.4. Lista Contida em Outra ______________________________________________________ 11 1.8.5. União de Listas ____________________________________________________________ 11 1.8.6. Interseção _________________________________________________________________ 12

1.9. Par Ordenado __________________________________________________________ 12

1.10.

Funções _____________________________________________________________ 13

1.10.1. Conceito __________________________________________________________________ 13 1.10.2. Função afim _______________________________________________________________ 13 1.10.3. Zero de Função afim ________________________________________________________ 14 1.10.4. Exercícios ________________________________________________________________ 15 Exercício 1: Função Constante ________________________________________________________ 15 Exercício 2: Quadrado de um Número __________________________________________________ 15 Exercício 3: Área do Triângulo ________________________________________________________ 16 Exercício 4: Soma de Três Números ____________________________________________________ 16 Exercício 5: Soma dos Quadrados ______________________________________________________ 16 Exercício 6: Raiz Quadrada da Soma dos Quadrados _______________________________________ 17 Exercício 7: Diagonal do Paralelogramo _________________________________________________ 17 Exercício 8: Raízes da Equação do 2° Grau ______________________________________________ 19 Exercício 9: Múltiplos de 4 (entre 1 e 100) _______________________________________________ 19 Exercício 10: Tabuada de 2 (entre 1 e 10) ________________________________________________ 19 Exercício 11: Número Primo __________________________________________________________ 19 Exercício 12: Série Truncada _________________________________________________________ 20 Exercício 13: Fatorial _______________________________________________________________ 20

(3)

Exercício 14: Fibonacci ______________________________________________________________ 21 Exercício 15: Soma dos Dígitos _______________________________________________________ 21 Exercício 16: Maior Número de uma Lista _______________________________________________ 22 Exercício 17: Soma de N Números _____________________________________________________ 22 Exercício 18: Lista Contida em Outra – versão 2 __________________________________________ 23 Exercício 19: Lista Contida em Outra – versão 2 __________________________________________ 25

1.11.

Funções de Haskell para Manipulação de Listas ___________________________ 26

1.12.

Funções Matemáticas de Haskell ________________________________________ 27

2. Lógica Proposicional _________________________________________________ 28

2.1. Conceito de Proposição __________________________________________________ 28

2.2. Proposição Simples e Composta ___________________________________________ 28

2.3. Conectivos _____________________________________________________________ 29

2.3.1. Negação ( ¬¬¬¬ ) ______________________________________________________________ 29 2.3.2. Negação em Haskell ( not ) ___________________________________________________ 29 2.3.3. Conjunção ( ∧∧∧ ) ____________________________________________________________ 30 ∧ 2.3.4. Conjunção em Haskell ( && ) _________________________________________________ 30 2.3.5. Disjunção ( ∨∨∨ ) _____________________________________________________________ 31 ∨ 2.3.6. Disjunção em Haskell ( | | ) ___________________________________________________ 31 2.3.7. Condicional ( →→→ ) __________________________________________________________ 32 → 2.3.8. Condicional em Haskell ______________________________________________________ 32 2.3.9. O operador if ... then ... else ___________________________________________________ 33 2.3.10. Bicondicional ( ↔↔↔↔ ) _________________________________________________________ 33 2.3.11. Bicondicional em Haskell ____________________________________________________ 34

2.4. Exercícios _____________________________________________________________ 35

2.4.1. Proposição: ¬¬¬¬ ( p ∧∧∧∧ ¬¬¬¬ q ) ____________________________________________________ 35 2.4.2. Proposição: (p →→→→ q) ∨∨∨∨ (p ↔↔↔↔ r) _______________________________________________ 35 2.4.3. Tautologia ________________________________________________________________ 36 2.4.4. Contradição _______________________________________________________________ 36 2.4.5. Contingência ______________________________________________________________ 37 2.4.6. Implicação Lógica __________________________________________________________ 37 2.4.7. Regras ___________________________________________________________________ 38 2.4.7.1. Regra de Inferência _____________________________________________________ 38 2.4.7.2. Regra do Silogismo Disjuntivo ____________________________________________ 38 2.4.7.3. Regra Modus Ponens ____________________________________________________ 38 2.4.7.4. Regra Modus Tollens ____________________________________________________ 38 2.4.7.5. Regra do Silogismo Hipotético ____________________________________________ 38 2.4.8. Equivalência Lógica ________________________________________________________ 38 2.4.9. Propriedades da Equivalência Lógica ___________________________________________ 39 2.4.10. Regras ___________________________________________________________________ 39 2.4.7.6. Regra da Comutatividade ________________________________________________ 39 2.4.7.7. Regra da Associatividade ________________________________________________ 39 2.4.7.8. Regra da Distributividade ________________________________________________ 39 2.4.7.9. Regra de De Morgan ____________________________________________________ 39 2.4.7.10. Regra da Idempotência __________________________________________________ 39 2.4.7.11. Regra da Dupla Negação _________________________________________________ 39 2.4.7.12. Regra da Condicional ___________________________________________________ 40 2.4.7.13. Regra da Bicondicional __________________________________________________ 40 2.4.7.14. Regra da Contraposição __________________________________________________ 40 2.4.7.15. Regra da Absorção ______________________________________________________ 40 2.4.7.16. Regra de CLAVIUS _____________________________________________________ 40 2.4.7.17. Método da Demonstração por Absurdo ______________________________________ 40

(4)

2.4.7.18. Regra de Exportação-Importação __________________________________________ 40 2.4.11. Negação Conjunta __________________________________________________________ 40 2.4.12. Negação Disjunta ___________________________________________________________ 41

3. Lógica de Predicados _________________________________________________ 42

3.1. Introdução ____________________________________________________________ 42

3.2. Linguagem Simbólica ___________________________________________________ 42

3.3.1. Quantificador Universal ( ∀∀∀∀ ) _________________________________________________ 43 3.3.2. Quantificador Existencial ( ∃∃∃∃ ) ________________________________________________ 44 3.3.3. Combinação de Fórmulas ____________________________________________________ 44 3.3.4. Resolução de Problemas _____________________________________________________ 45

4. Exercícios __________________________________________________________ 47

4.1. Exercícios de Raciocínio Lógico ___________________________________________ 47

Exercício 4.1.1. ____________________________________________________________________ 47 Exercício 4.1.2. ____________________________________________________________________ 48 Exercício 4.1.3. ____________________________________________________________________ 49 Exercício 4.1.4. ____________________________________________________________________ 49 Exercício 4.1.5. ____________________________________________________________________ 50

4.2. Resolução Algorítmica de Problemas ______________________________________ 51

Exercício 4.2.1. ____________________________________________________________________ 51 Exercício 4.2.2. ____________________________________________________________________ 51 Exercício 4.2.3. ____________________________________________________________________ 51 Exercício 4.2.4. ____________________________________________________________________ 51 Exercício 4.2.5. ____________________________________________________________________ 52 Exercício 4.2.6. ____________________________________________________________________ 52 Exercício 4.2.7. ____________________________________________________________________ 52 Exercício 4.2.8. ____________________________________________________________________ 52 Exercício 4.2.9. ____________________________________________________________________ 53 Exercício 4.2.10. ___________________________________________________________________ 53 Exercício 4.2.11. ___________________________________________________________________ 53 Exercício 4.2.12. ___________________________________________________________________ 53 Exercício 4.2.13. ___________________________________________________________________ 54 Exercício 4.2.14. ___________________________________________________________________ 54 Exercício 4.2.15. ___________________________________________________________________ 54 Exercício 4.2.16. ___________________________________________________________________ 55 Exercício 4.2.17. ___________________________________________________________________ 55 Exercício 4.2.18. ___________________________________________________________________ 55 Exercício 4.2.19. ___________________________________________________________________ 56 Exercício 4.2.20. ___________________________________________________________________ 56 Exercício 4.2.21. ___________________________________________________________________ 56 Exercício 4.2.22. ___________________________________________________________________ 57 Exercício 4.2.23. ___________________________________________________________________ 58 Exercício 4.2.24. ___________________________________________________________________ 59 Exercício 4.2.25. ___________________________________________________________________ 60

Bibliografia: ___________________________________________________________ 62

(5)

1. Introdução à Linguagem Haskell

1.1. O que é o Haskell

Haskell é uma linguagem de programação. Possui ambiente de desenvolvimento para diversos sistemas operacionais, incluindo Windows e Linux.

1.2. Matemática Discreta e Haskell

Para que se possa escrever um programa numa determinada linguagem, deve-se obedecer à sintaxe dessa linguagem. Por exemplo, se o operador de multiplicação da linguagem é o asterisco (*), multiplica-se dois números a e b como a * b, e não, a x b como na matemática tradicional.

E por que utilizar Haskell para ensinar matemática discreta? a) Porque sua sintaxe é bem parecida com a da matemática;

b) Porque Haskell é uma linguagem funcional, o que significa dizer que problemas são resolvidos em Haskell por meio da resolução de funções. O resultado do processamento de uma função pode ser utilizado por outra função, e assim por diante;

c) Porque fornece aos estudantes meios de implementação de problemas simples ou complexos com o auxílio de uma ferramenta bem mais simples do que outras ferramentas de apoio, como o MatLab®; d) Porque programação é uma aplicação da matemática discreta e muitas das falhas no ensino de

programação se devem à insuficiência de conhecimento dos estudantes nesta área da matemática.

1.3. Como é um Programa em Haskell

Para que se possa escrever um programa (chamado “script” no jargão usual) em Haskell, precisamos, antes de tudo, obter o ambiente computacional que irá interpretar nossos programas escritos em Haskell (interpretador Haskell). Há dois interpretadores que podemos utilizar para esse fim: o Hugs e o Helium, que podem ser baixados gratuitamente para as plataformas Linux e Windows. O site http://haskell.org/hugs contém o Hugs e o site http://www.cs.uu.nl/helium contém o Helium.

Abaixo podemos ver a tela do WinHugs (Hugs para Windows):

Figura 1: Hugs – interpretador para programas Haskell

Nela você pode ver, à esquerda, atalhos para diversas funções (como carregar e salvar um arquivo, sair do Hugs, etc.) e, à direita, dentro da área branca maior, você pode ver mensagens de iniciação do ambiente e o

prompt do Hugs (aqui o prompt é: Prelude> ), que é uma mensagem que informa que o ambiente está

(6)

Vamos construir nosso primeiro programa em Haskell, o qual vai conter uma função que mapeia valores inteiros em valores inteiros (isto é indicado pelo tipo funcional Integer −> Integer na linguagem Haskell). Na verdade, esta função, que é exibida na Figura 2 abaixo, é a função constante que a todo inteiro n produz o inteiro 5 como valor.

Supondo que você está usando o Windows, o Hugs esteja instalado e que você o executou (aparece uma tela como a da figura 1), siga os seguintes passos:

a) Digite no prompt do Hugs: :edit md.hs b) Pressione a tecla ENTER

c) Surgirá a mensagem: Não é possível localizar o arquivo md.hs.

Deseja criar um novo arquivo?

d) Clique no botão Sim

e) Pronto, o bloco de notas surge para que você digite o arquivo de nome md.hs (md é uma abreviação nossa para matemática discreta e hs é uma extensão de arquivo que o Hugs98 usa para Haskell Script). f) Digite o código que aparece na figura 2 (note que os tipos do argumento e da função aparecem após :: ).

Figura 2: Conteúdo do arquivo md.hs g) Salve o arquivo ( clique em Arquivo e depois em Salvar ).

h) Saia do Bloco de Notas ( Clique em Arquivo e pois em Sair ), o que o faz retornar ao Hugs. i) Digite (no Hugs): :load md.hs

j) A função criada, f, deve ser invocada (invocar uma função é executar a função, ou seja, é digitar o nome dela e pressionar a tecla ENTER no prompt do Hugs).

k) Após ser invocada, você poderá verificar que o valor de retorno da função aparecerá no prompt do Hugs (figura 3)

(7)

1.4. Tipos em Haskell

Como você viu, a função f é uma função constante que produz um resultado do tipo inteiro (retorna sempre o valor inteiro 5). Há situações, entretanto, onde você terá que utilizar funções de tipos diferentes.

Para facilitar o nosso trabalho, abaixo estão listados alguns dos tipos utilizados neste trabalho (note que o nome de tipo sempre inicia por letra maiúscula. Em Haskell somente tipos, de forma obrigatória, iniciam por letra maiúscula. Qualquer outro objeto, como o nome de funções, devem iniciar, obrigatoriamente por letra minúscula):

Tabela 1: Tipos Matemáticos de Haskell Tipo em

Haskell

Valores do Tipo Integer Conjunto dos inteiros (de -∞ a +∞)

Float

Sub-conjunto finito dos racionais (ponto flutuante). Uma função Float limita-se a retornar valores entre ±10-39 e ±1038

Bool Valores Lógicos e False (Falso) True (Verdadeiro)

A sintaxe para a definição de uma função envolve duas linhas de programa:

nome da função :: Tipo do argumento −−−>−>>>Tipo da função

nome da função nome do argumento = valor de retorno

(A bem da verdade, a primeira linha não é necessária pois uma das características de Haskell é a presença de inferência de tipos. Contudo, é sempre excelente prática de programação incluir todos os tipos das variáveis sendo definidas em nossos programas.) Assim sendo, a função matemática abaixo:

f (x) = 5.0

é representada em Haskell (Lembre-se: para obter o resultado do processamento da função no Hugs, você tem que construir o script, como explicado anteriormente, carregá-lo e invocar a função pelo seu nome):

f :: Float −−−−>>>> Float f x = 5.0

Observe que o ponto é utilizado como separador decimal para a notação de ponto-flutuante. Já a proposição:

p: é verdadeiro. (V)

pode ser representada em Haskell como:

p :: Bool p = True

(8)

1.5. Operadores em Haskell

1.5.1. Aritméticos

Tabela 2: Operadores Aritméticos de Haskell

Nome do Operador Símbolo Matemática Haskell

Adição + x : Z

x = 5 + 6

x :: Integer x = 5 + 6 Subtração - x x = 10 – 2 : R x :: Float x = 10.0 – 2.0 Negação (unário) - x : Z x = -3 + 5 x :: Integer x = -3 + 5

Multiplicação * x x = 2 * 5 : R x :: Float x = 2.0 * 5.0 Divisão entre operandos reais / x : R x = 10 / 3 x :: Float x = 10.0 / 3.0 Divisão entre

operandos inteiros `div`

x : Z x = 10 / 3

x :: Integer x = 10 `div` 3 Resto da divisão entre

operandos inteiros `mod` não há x :: Integer x = 10 `mod` 3 Potenciação (potência inteira) ^ x : R x = 102 x :: Float x = 10.0 ^ 2 Potenciação (potência real) ** x : R x = 101,5 x :: Float x = 10.0 ** 1.5

Valor absoluto abs x : Z x = | -5 | x :: Integer x = abs (-5)

Obs.: Uma vez definidos os operadores aritméticos, podemos agregar à tabela 1 o tipo Rational, que representa valores de frações utilizando o caractere % (porcentagem) como separador entre o dividendo e o divisor. Por exemplo, altere o script md.hs (basta você repetir os passos descritos no item 1.3, editando novamente o arquivo) inserindo as linhas abaixo:

r1 :: Rational r1 = 3 % 2 r 2 :: Rational r 2 = 1 % 3

Salve o arquivo e saia do editor (retornando ao Hugs). No prompt do Hugs digite: r1 e pressione a tecla ENTER. Você vai observar a representação: 3 % 2, correspondendo à fração: 3/

2 . Experimente executar cada um dos itens abaixo:

a) r1 b) r1 + r2 c) r1 – r2 d) r1 * r2 e) r1 / r2

(9)

1.5.2. Relacionais

Tabela 3: Operadores Relacionais de Haskell

Nome do Operador Símbolo Matemática Haskell

Maior que > x : {T,F}

x = 10 > 6

x :: Bool x = 10 > 6 Maior ou igual a > = x : {T,F} x = 10 >= 2 x :: Bool x = 10.0 >= 2.0

Menor que < x : {T,F} x = -3 < 5 x :: Bool x = -3 < 5 Menor ou igual a < = x : {T,F} x = 2 <= 5 x :: Bool x = 2.0 <= 5.0 Igual a (igualdade) = = x : {T,F} x = 10 = 10 x :: Bool x = 10.0 = = 10.0 Diferente de /= x : {T,F} x = 10 ≠ 3 x :: Bool x = 10 /= 3

1.5.3. Lógicos

Tabela 4: Operadores Lógicos de Haskell

Nome do Operador Símbolo Matemática Haskell

conectivo ∧∧∧∧ (conjunção) && x : {T,F} x = 10 > 6 ∧ 20 > 10 x :: Bool x = 10 > 6 && 20 > 10 conectivo ∨∨∨∨ (disjunção) | | x : {T,F} x = 10 >= 2 ∨ F f :: Bool f = 10.0 >= 2.0 | | False conectivo ¬¬¬¬ (negação) not x : {T,F} x = ¬ F f :: Bool f = not False

1.5.4. Divisibilidade

Dizemos que um número inteiro a é divisor de outro inteiro b, simbolizado matematicamente por a | b, quando existe um inteiro c tal que ca = b:

a | b ⇔⇔⇔⇔ ( ∃∃∃∃ c ∈∈∈∈ | ca = b )

Isto significa dizer que, se a divide b, o dividendo da divisão de b por a é igual a c, e o resto da divisão de b por a é igual a zero. Por exemplo, como 2 divide 10 ( 2 | 10 ), temos que c é igual a 5,

10 2

0 5

Em Haskell, quando um número inteiro é divisor de outro número inteiro, o resto da divisão inteira (mod) produz zero como resultado. Assim sendo, 10 `mod` 2 == 0.

Obs.: Observe que mod está delimitado pelo acento grave. Uma outra forma de utilizar mod é: mod 10 2, que produz o mesmo resultado que: 10 `mod` 2. Ou seja, sempre que tivermos uma função binária como mod podemos utilizá-la de modo infixo (isto é, entre seus dois operandos) envolvendo-a pelo acento grave.

(10)

1.5.5. Operações com Números Racionais

Haskell representa os números racionais separando o numerador do denominador pelo sinal de porcentagem (%), ao invés da barra utilizada na matemática.

Revisitando o item 1.5.1, encontramos:

r1 :: Rational

r1 = 3 % 2 r 2 :: Rational r 2 = 1 % 3

Salve o arquivo e saia do editor (retornando ao Hugs). No prompt do Hugs digite: r1 e pressione a tecla ENTER. Você vai observar a representação: 3 % 2, correspondendo à fração: 3/

2 . Experimente executar cada um dos itens abaixo:

f) r1 g) r1 + r2 h) r1 – r2 i) r1 * r2 j) r1 / r2

1.6. Tipo Char

Um elemento de tipo Char (caractere) pode ser qualquer letra, dígito (não numérico, ou seja, como os dígitos de CEP, com os quais não se faz operação aritmética alguma) ou símbolo (!,@,#,$, etc.). Em outras palavras, os elementos do tipo Char representam as teclas que aparecem em seu teclado. Um elemento do tipo

Char deve sempre estar delimitado por apóstrofes (aspas simples), por exemplo: letra :: Char

letra = 'a'

Usualmente, só é aceito um elemento delimitado por apóstrofes; entretanto, é obrigatório se ter um elemento entre os apóstrofes, não existindo elemento nulo. Isto significa dizer que não é válida a definição abaixo em Haskell (onde após o sinal de igual aparecem dois apóstrofes):

letra :: Char

letra = ''

As exceções à esta regra ficam por conta dos chamados caracteres especiais como, por exemplo, o retorno de carro e a tabulação que são representados por '\n' e '\t', respectivamente.

(11)

1.7. Listas

1.7.1. Definição

Chama-se Seqüência a qualquer coleção ordenada de objetos.

Usualmente, os elementos de uma seqüência na matemática são delimitados por < e > e seus elementos separados por vírgulas. Por exemplo, a seqüência de números naturais de 1 a 5 seria escrita como <1,2,3,4,5>. Além disso, utilizamos reticências (...) para, por exemplo, indicar um intervalo de valores, provavelmente extenso.

Em Haskell, seqüências, sejam elas numéricas ou não, são chamadas genericamente de listas, sendo delimitadas por [ e ] e seus elementos, a exemplo da matemática, são separados por vírgulas. Intervalos numéricos podem ser indicados através de dois pontos consecutivos (..). A seqüência acima seria escrita [1,2,3,4,5] em Haskell.

Por exemplo (utilizando a notação de Haskell), a coleção [1,2,3,4,5,6,7,8,9,10] é uma seqüência (além disso, podemos chamá-la de seqüência finita, pois termina em 10). O primeiro elemento (termo) desta seqüência é 1, o segundo termo é 2 e assim por diante. Já a seqüência dos números inteiros ímpares [1,3..] é uma seqüência infinita.

Em Haskell, uma lista é um agrupamento de um mesmo tipo de dado, dentre os válidos para a linguagem. Seu nome sempre inicia com uma letra minúscula.

Uma lista de um determinado tipo é definido em Haskell explicitando o seu nome, seguido de dois caracteres dois pontos ( :: ) seguido do tipo da lista delimitado por colchetes. Os elementos da lista devem igualmente estar delimitados por colchetes e separados por vírgula:

a) Lista de inteiros:

conj :: [ Integer ] conj = [ 1 , 2 , 3 , 4 ]

b) Lista das vogais:

vogais :: [ Char ]

vogais = [ 'a' , 'e' , 'i' , 'o' , 'u' ]

c) Lista dos algarismos romanos:

rom :: [ Char ]

rom = [ 'I' , 'V' , 'X' , 'L' , 'C' , 'D' , 'M' ]

d) Lista dos naipes de cartas de um baralho:

naipes :: [ String ]

naipes = [ "paus" , "ouros" , "copas" , "espadas" ]

Obs.: O tipo String, inserido aqui, define uma palavra ou frase, isto é, uma string nada mais é do que uma lista de Char ( String ≡ [ Char ] ), e uma lista de String pode ser considerada como uma lista de lista de Char ( [ String ] ≡ [ [ Char ] ] ). Elementos do tipo String devem sempre estar delimitados por aspas duplas. O tipo String permite a representação da lista vazia, quando então se diz que é uma string vazia. Para tanto, utilizam-se aspas seguidas, sem elemento algum entre elas, como em:

vazia :: String vazia = ""

e) Lista dos números inteiros e positivos:

positivos :: Integer positivos = [ 1.. ]

Obs: Esta lista é infinita, e o incremento entre os elementos é constante e igual a 1. Note que após o elemento, utilizou-se dois caracteres ponto (..) para indicar que a lista deve continuar indefinidamente.

(12)

f) Lista dos números ímpares positivos:

positivos :: Integer positivos = [ 1, 3 .. ]

Obs: Esta lista é infinita, com incremento entre os elementos constante e igual a 2.

1.7.2. Lista com um só Elemento

É a lista que possui um único elemento. Exemplos: a) Divisores de 1: divisoresDeUm :: [ Integer ] divisoresDeUm = [ 1 ] b) Capital do Brasil: capital :: [ String ] capital = [ "Brasília" ]

1.7.3. Lista Vazia

Lista vazia é aquela que não possui elemento algum. Representa-se uma lista vazia em Haskell por colchetes sem elementos entre eles, como mostrado abaixo:

listaVazia :: [ Integer ] listavazia = [ ]

1.7.4. Listas Iguais

Matematicamente, dois conjuntos são iguais se ambos possuem os mesmos elementos, não importando a ordem em que se encontrem, ou seja:

A = B ⇔⇔⇔⇔ ( ∀∀∀∀x ) ( x ∈∈∈∈ A ⇔⇔⇔⇔ x ∈∈∈∈ B )

Em Haskell duas listas são iguais, se os elementos de mesma posição são iguais.

Uma vez dito isto, dadas duas listas a e b, verificamos se elas são iguais em Haskell pelo script abaixo:

a :: [ Integer ] a = [ 1 , 3 , 5 ] b :: [ Integer ] b = [ 1 , 5 , 3 ] iguais :: Bool iguais = a == b

(13)

1.7.5. Progressão Aritmética (PA)

Chama-se PA – Progressão Aritmética – à seqüência em que se pode obter um termo (elemento) somando-se ao termo imediatamente anterior um valor constante denominado razão (r).

Por exemplo, seja a seqüência [1,3,5,7,9]. Neste caso, o primeiro termo é 1, o segundo é 3 (resultado da soma de 1 com 2), o terceiro termo é 5 (resultado da soma de 3 com 2) e assim por diante. Diz-se então que esta seqüência é uma PA de razão igual a 2.

Uma PA pode ser crescente, como em: [1,2,3,4,5], onde a razão é positiva (neste caso igual a 1) ou

decrescente, como em: [100, 98 .. 2], que lista os números inteiros pares de 100 até 2, com razão negativa

igual a –2. Neste último exemplo, a razão é determinada como esperado: 98 – 100.

Obs.: Em Haskell, em caso de omissão, sempre se considerará uma razão unitária. Caso a razão venha a ser diferente de 1, deve-se especificar os dois primeiros termos, o que faz com o Hugs identifique corretamente o valor da razão. Por exemplo, [1..5] é a lista [1,2,3,4,5] e [1,3..5] é a lista [1,3,5].

1.7.6. Termo Geral de uma PA

Seja a PA: [a1, a2 .. an] de razão igual a r.

Define-se o termo geral de uma PA como sendo igual a: an = a1+ (n –1) r.

Por exemplo, calcule o milésimo número inteiro ímpar. Tomando-se por base que 1 é o primeiro termo da série (a1), que a razão r é igual a 2 e que se deseja o milésimo termo (a1000), o que faz com que n seja igual a 1000, tem-se:

a1000 :: Integer

a1000 = 1 + (1000 – 1) * 2

O que produz 1999 como resultado.

1.7.7. Progressão Geométrica (PG)

Chama-se PG – Progressão Geométrica – à seqüência em que se pode obter um termo (elemento) multiplicando-se o termo imediatamente anterior por um valor constante denominado razão (q).

Por exemplo, seja a seqüência [2,4,8,16,32]. Neste caso, o primeiro termo é 2, o segundo é 4 (resultado da multiplicação de 2 com 2), o terceiro termo é 8 (resultado da multiplicação de 4 com 2) e assim por diante. Diz-se então que esta seqüência é uma PG de razão igual a 2.

Uma PG pode ser crescente, como em: [10,100,1000], onde a razão é igual a 10 ou decrescente, como em: [1000, 100 , 10] com razão igual a 0,1.

1.7.8. Termo Geral de uma PG

Seja a PG: [a1, a2 .. an] de razão igual a q.

Define-se o termo geral de uma PG como sendo igual a: an = a1. q( n – 1 ).

Por exemplo, calcule quantos bytes valem 1KBytes (sabendo-se que byte é a unidade de medida utilizada em sistemas de computação, que utiliza a base binária como base numérica e que 1Kbytes é igual a 210 ). Tomando-se por base que 2 é o primeiro termo da série (a1), que a razão q é igual a 2 e que se deseja o décimo termo (a10), o que faz com que n seja igual a 10, tem-se:

a10 :: Integer a10 = 2 * 2 ^ (10 – 1)

(14)

1.8. Representando Conjuntos através de Listas

1.8.1. Descrição

Na matemática, um conjunto é uma coleção de objetos não repetidos e sem ordenação, delimitados por chaves e separados por vírgula (notação eficiente para pequenos conjuntos). Assim sendo, os conjuntos abaixo são o mesmo conjunto:

{1,2,3,4,5,6,7,8,9,10} { 1,6,2,7,3,8,4,9,5,10} {6,7,8,9,10, 1,2,3,4,5} { 1,3,5,7,9,2,4,6,8,10}

Neste trabalho, utilizaremos numa aproximação as listas de Haskell para representar conjuntos (numa aproximação, haja visto que listas não são a mesma coisa que conjuntos).

1.8.2. Sub-Lista

Seja o conjunto A dos números inteiros e positivos abaixo:

A = { 1,2,3,4,5,6,7,8,9,10}

Seja o conjunto B dos números inteiros e positivos maiores do que 2 e menores do que 5:

B = { 3,4,5}

Pode-se ver que B é subconjunto de A.

Uma notação bastante familiar em matemática para representar o disposto acima, seria:

B = { x | x ∈∈∈∈ A ∧∧∧∧ 2 < x < 6 } que pode ser lida como:

“o subconjunto B é formado por elementos x tais que esses elementos vêm do conjunto A

(pertencem à A) e que sofrem a restrição de serem maiores do que 2 e menores do que 6”.

Em Haskell, dada uma lista de um tipo qualquer, obtemos listas derivadas daquela (sub-listas) por meio de List Comprehensions, cuja sintaxe é muito parecida com a notação acima para conjuntos, somente trocando-se as chaves por colchetes, o conectivo ∧∧∧ pela vírgula, representando a primeira restrição que o ∧ elemento x deve sofrer para fazer parte da sublista b (restrições adicionais utilizam os operadores lógicos do Haskell, mostrados na tabela 4), além de representar a pertinência do elemento da lista a pela seta orientada à esquerda: ←←←←.

Obs.: Como na verdade não temos uma tecla que contenha uma seta virada para a esquerda, utilizamos duas teclas para esse fim: a tecla de menor que (<<<) e a tecla de hífen (−< −−− ).

Obs.: Em Haskell a lista a é chamada de lista geradora, pois é essa lista que gera os dados para a formação da sublista).

Por exemplo, tomando-se como base a lista a, obtém-se a lista b como:

a :: [ Integer ]

a = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] b :: [ Int eger]

(15)

1.8.3. Diferença entre Listas

A diferença entre os conjuntos A e B produz um conjunto que contém os elementos de A que não pertencem a B (complementar de B em relação a A):

A – B = { x | x ∈∈∈∈ A e x ∉∉∉∉ B }

Em Haskell, utiliza-se \\ , que necessita de import List (vide tabela 6), para produzir a diferença entre listas. Por exemplo, seja o script:

import List x :: [ Integer ]

x = [ 1 , 2 , 3 ] \\ [ 2 , 4 , 5 ]

Neste caso, x produz [ 1, 3 ].

1.8.4. Lista Contida em Outra

Um conjunto A está contido em B se os elementos de A pertencem a B também:

A ⊂⊂⊂⊂ B ⇔⇔⇔⇔ ( ∀∀∀∀x ) ( x ∈∈∈∈ A ⇒⇒⇒⇒ x ∈∈∈∈ B )

Em Haskell, para verificar se uma lista está contida em outra, podemos utilizar a função diferença (\\), que retorna a diferença entre as listas, e comparamos o retorno desta função com o conjunto vazio:

contida :: [Integer] -> [Integer] -> Bool contida lista1 lista2 = lista1 \\ lista2 == [ ]

Por exemplo, seja o script:

import List

x = [ 1,2 ] \\ [ 1,2,3,4 ] == [ ] y = [ 1,2, 4] \\ [ 1,2,3,4 ] == [ ] z = [ 1,5 ] \\ [ 1,2,3,4 ] == [ ]

Neste caso, x e y são True e z é False.

1.8.5. União de Listas

A união do conjunto A com o conjunto B produz o conjunto chamado reunião:

A ∪∪∪∪ B = { x | x ∈∈∈∈ A ou x ∈∈∈∈ B }

Assim sendo,

(16)

Em Haskell, utiliza-se union (necessita import List) para produzir a união entre listas. Por exemplo, seja o script: import List x :: [ Integer ] x = union [ 1 , 2 ] [ 3 , 4 ] y :: [ Char ] y = union [ 'a' , 'b' ] [ 'c' , 'd' ]

Neste caso, x produz [ 1 , 2 , 3 , 4 ] e y produz "abcd". Observe que:

i) y é uma lista de Char;

ii) String é uma lista de Char;

iii) Strings são delimitadas por aspas duplas;

iv) por isso, o resultado vem delimitado por aspas duplas, ao invés de colchetes.

1.8.6. Interseção

Ao conjunto formado pelos elementos que pertencem simultaneamente aos conjuntos A e B é chamado de conjunto interseção:

A ∩∩∩∩ B = { x | x ∈∈∈∈ A e x ∈∈∈∈ B }

Assim sendo,

{ 1, 2 , 3 } ∩∩∩∩ { 2 , 3 , 4 , 5 } = { 2 , 3 }

Em Haskell, utiliza-se intersect (necessita import List) para produzir a interseção entre listas. Por exemplo, seja o script:

import List x :: [ Integer ]

x = intersect [ 1 , 2 , 3 ] [ 2 , 3 , 4 , 5 ]

Neste caso, x produz [ 2 , 3 ] .

1.9. Par Ordenado

Chama-se par ordenado (a,b) ao elemento formado pelos elementos a e b, de modo que se tenha:

( a , b ) = ( c , d ) ⇔⇔⇔⇔ a = c e b = d

Em Haskell, a representação de um par ordenado se faz da mesma forma. Por exemplo, seja o seguinte par ordenado: (1,2). O script ficaria como:

par :: ( Integer , Integer ) par = ( 1 , 2 )

(17)

1.10. Funções

1.10.1. Conceito

Uma função é uma relação em que se tem, de um lado, o conjunto de partida (ou domínio da função), e de outro o conjunto das imagens (ou conjunto imagem), sendo que o conjunto das imagens é um subconjunto do conjunto de chegada (contradomínio):

A B

Figura 4: Conjunto de partida (A) e conjunto imagem (B)

Representa-se a função de A em B como: f : A →→→→ B .

Em Haskell, uma função tem a seguinte representação (sintaxe):

nomeDaFunção :: TipoDoElementoDomínio1 −−−>−>>> TipoDoElementoImagem

Veja que nomeDaFunção inicia com letra minúscula e Tipo (item 1.4) inicia com letra maiúscula.

1.10.2. Função afim

Uma função f : R →→→→ R é uma função afim quando existem a e b reais tais que, para todo x real, temos:

(a ≠ 0)

Se a for igual a 3,0 e b for igual a 2,0 temos: f (x) = 3,0 x + 2,0 . Em Haskell, podemos representar esta função afim como:

f :: Float →→→→ Float

f x = 3.0 * x + 2.0

Experimente executar no Haskell a função digitada acima passando 10 como argumento: f 10 (reveja o item 1.3 para relembrar como executar uma função no Haskell).

(18)

1.10.3. Zero de Função afim

Podemos determinar o zero de uma função afim, conhecidos os valores de a e de b, resolvendo a equação do 1° grau, da forma: ax + b = 0 ,ou seja, temos que achar a solução:

Em Haskell, esta função poderia ser facilmente resolvida fornecendo-se dois valores Float (reais) como argumento, o que faz com que a função retorne o valor da imagem, ou seja, o valor de x:

f : : Float −−−>−>>> Float −−−>−>>> Float

f a b = -b / a

Isto significa dizer que:

f : : Float −−−>−>>> Float −−−−>>>> Float f a b = -b / a

Experimente executar esta função no Haskell, como: f 1 2 (o que fará a = 1 e b = 2). Observe que a função retorna -2.0 :

Figura 5: Tela do Haskell mostrando a chamada à função f e o resultado do processamento (valor de retorno da função)

b a

x =

nomeDaFunção Tipo do 1° argumento Tipo do 2° argumento Tipo do elemento imagem (tipo do valor de retorno da função)

1° argumento 2° argumento valor de retorno da função (cálculo do valor de x)

Tela do editor de textos com o código da função f

(19)

Haskell é uma linguagem com notação muito próxima da matemática, e permite que se trabalhe bem os conceitos matemáticos através da construção de funções.

A seguir, vamos explorar o Haskell, utilizando os conceitos aprendidos até o momento. Observações:

i) Os códigos das funções virão dentro de caixas, indicando o que deve ser digitado no script.

ii) Comentários podem ser feitos na mesma definição da função. Basta que o início da linha inicie por dois traços (hífens), quando for um comentário de somente uma linha, ou inicie com abre-chave-hífen ( {- ) e termine com hífen-fecha-chave ( -} ), quando for um comentário de mais de uma linha. Por exemplo:

-- Este comentário é de somente uma linha

{- Este comentário é de mais de uma linha. Ele inicia nesta linha, e termina nesta linha. -}

iii) Ao final, você poderá observar que programar é aplicar a matemática discreta à informática.

1.10.4. Exercícios

Exercício 1: Função Constante

Exercício 2: Quadrado de um Número

Construa uma função que retorne o quadrado de um valor do conjunto dos reais fornecido como argumento

Obs.: A função quad também poderia ser escrita como:

quad :: Float −−−>−>>> Float

quad n = n ^ 2

-- Esta função retorna sempre o valor numérico inteiro 5

fc :: Integer −> Integer fc n = 5

quad :: Float −−−>−>>> Float

(20)

Exercício 3: Área do Triângulo

Construa uma função que calcule e imprima a área de um triângulo de base b e altura h. (area = b . h ) 2

Obs.: O cálculo da área produz número fracionário (real), por isso os tipos dos argumentos e o tipo da função (tipo do valor de retorno) são Float.

Exercício 4: Soma de Três Números

Construa uma função que retorne a soma de três valores inteiros fornecidos como argumento

Exercício 5: Soma dos Quadrados

Construa uma função que calcule a soma dos quadrados de três valores reais.

Obs.: Para resolver este problema, poderíamos reaproveitar a função quad escrita anteriormente. Assim, o script ficaria como:

quad :: Float −−−>−>>> Float

quad n = n ^ 2

somaquad :: Float −−−>−>>> Float −−−>−>>> Float −−−>−>>> Float

somaquad x y z = quad x + quad y + quad z area :: Float −−−−>>>> Float −−−−>>>> Float

area b h = b * h / 2

Soma3 :: Integer −−−>−>>> Integer −−−>−>>> Integer −−−−>>>> Integer

Soma3 a b c = a + b + c

somaquad :: Float −−−>−>>> Float −−−>−>>> Float −−−>−>>> Float somaquad x y z = x ^ 2 + y ^ 2 + z ^ 2

(21)

Exercício 6: Raiz Quadrada da Soma dos Quadrados

Construa uma função que calcule a raiz quadrada da soma dos quadrados de três valores reais.

Aqui fizemos uso da função predefinida do Haskell sqrt, que calcula a raiz quadrada de um valor numérico real:

sqrt valor é o mesmo que valor ∴ sqrt ( 4 ) ≡ 4

Exercício 7: Diagonal do Paralelogramo

Construa uma função que calcule a diagonal D do paralelogramo abaixo:

A solução passa por dois triângulos retângulos.

D

a

b

c

quad :: Float −−−>−>>> Float quad n = n ^ 2

somaquad :: Float −−−>−>>> Float −−−>−>>> Float −−−>−>>> Float somaquad x y z = quad x + quad y + quad z raizSomaQuad :: Float −−−>−>>> Float −−−−>>>> Float −−−>−>>> Float

(22)

O primeiro, é o triângulo cuja hipotenusa é h ( h2 = a2 + b2 ):

O segundo, é o triângulo cuja hipotenusa é D ( D2 = h2 + c2 ):

Ou seja, D2 = a2 + b2 + c2 , no que resulta em: D = a2 + b2 + c2

Observe o reaproveitamento da função raizSomaQuad.

quad :: Float −−−>−>>> Float

quad n = n ^ 2

somaquad :: Float −−−>−>>> Float −−−>−>>> Float −−−>−>>> Float

somaquad x y z = quad x + quad y + quad z raizSomaQuad :: Float −−−>−>>> Float −−−−>>>> Float −−−>−>>> Float

raizSomaQuad x y z = sqrt ( somaquad x y z ) diagonal :: Float −−−>−>>> Float −−−−>>>> Float −−−−>>>> Float

diagonal a b c = raizSomaQuad x y z

D

a

b

c

h

D

a

b

c

h

(23)

Exercício 8: Raízes da Equação do 2° Grau

Construa uma função que calcule as raízes reais da equação do 2° grau.

Obs.: Neste exercício, pela limitação das linguagens de programação, não consideraremos a hipótese de ∆ (delta) ser negativo.

Calcularemos as raízes como: x = - b ±±±±∆∆∆ , sendo: ∆∆∆∆ = b 2 – 4 a c .

2a

Note que: b 2 – 4 a c representada em Haskell fica: b ^ 2 – 4 * a * c .

Exercício 9: Múltiplos de 4 (entre 1 e 100)

Obs.: O tipo Int representa valores inteiros, no intervalo: -2147483648 e +2147483647 . Você pode utilizar

Int ou Integer para valores que estejam dentro do intervalo considerado. Para valores menores do que

-2147483648 e para valores maiores do que +2147483647 somente utilize o tipo Integer.

Exercício 10: Tabuada de 2 (entre 1 e 10)

Exercício 11: Número Primo

Construa uma função que responda se um número é ou não primo.

x1 :: Float −−−>−>>> Float −−−−>>>> Float −−−−>>>> Float

x2 :: Float −−−>−>>> Float −−−−>>>> Float −−−−>>>> Float

x1 a b c = ( - b - sqrt ( b ^ 2 – 4 * a * c ) ) / ( 2 * a ) x2 a b c = ( - b + sqrt ( b ^ 2 – 4 * a * c ) ) / ( 2 * a ) multiplos4 :: [ Int ] multiplos4 = [ e | e <<<−<−−− [1 .. 100] , e `mod` 4 == 0 ] tabuada2 :: [ Integer ] tabuada2 = [ e * 2 | e <<<<−−−− [1 .. 10] ]

primo :: Integer −−−−>>>> Bool

(24)

Exercício 12: Série Truncada

Crie uma função que calcule a série S = 1 + 1 + ... + 1 , truncada no N-ésimo termo.

2 N

Obs.: A função sum soma todos os elementos de uma lista numérica. Por exemplo, dada a lista [1,2,3,4], fazer

sum [1,2,3,4] produz: 10.

Exercício 13: Fatorial

Construa uma função que calcule o fatorial de um número inteiro.

Para que entendamos o script em Haskell, precisamos, em primeiro lugar, entender como se calcula o fatorial de um número:

0! = 1, por definição. N! = N x N-1 x ... x 1

Dito isto, temos que: 5! = 120 , pois: 5! = 5 x 4 x 3 x 2 x 1 Podemos ver no cálculo do fatorial que: 5! = 5 x 4 x 3 x 2 x 1 mas: 4! = 4 x 3 x 2 x 1

ou seja: 5! = 5 x 4!

mas: 4! = 4x3x2x1 e 3! = 3x2x1 no que resulta: 4! = 4 x 3! Em resumo:

5! = 5 x 4! ∴ 4! = 4 x 3! ∴ 3! = 3 x 2! ∴ 2! = 2 x 1! ∴ 1! = 1 x 0! ∴ 0! = 1

Isto posto, podemos dizer que: N! = N x (N-1)! , até que se encontre 0! que é igual a 1, sem mais chamadas ao fatorial. Em Haskell, fica:

Dizemos que há uma chamada recursiva à função fatorial, pois a função fat chama a ela mesma com o antecessor do seu argumento.

serie :: Float −−−−>>>> Float

serie n = sum [ 1/i | i <<<<−−−− [1 .. n] ]

fat :: Integer −−−−>>>> Integer

fat 0 = 1

(25)

Exercício 14: Fibonacci

Construa uma função que imprima o enésimo termo da série de Fibonacci.

A série de Fibonacci é uma seqüência cujo primeiro termo é 0, o segundo termo é 1 e os demais termos são iguais à soma dos dois elementos antecessores imediatos.

Aproveitando o conhecimento de recursividade aprendido anteriormente, temos que o enésimo termo da série de Fibonacci é a soma dos dois antecessores imediatos do argumento da função, até que o termo seja igual a 1 ou igual a 0 (zero). O script vem a ser então:

Exercício 15: Soma dos Dígitos

Crie uma função que calcule a soma dos dígitos de um número. Por exemplo, f 259 deve retornar 16, pois: .

16 = 9 + 5 + 2.

Para que possamos calcular a soma dos dígitos de um número, devemos somar o dígito menos significativo com o restante do número, fazendo nova chamada à função, até que se faça uma chamada à função passando 0 (zero) como argumento, quando então a função retorna 0 (zero), sem haver nova chamada recursiva, isto é:

somadig 259 = 9 + somadig 25 somadig 25 = 5 + somadig 2 somadig 2 = 2 + somadig 0 somadig 0 = 0

Utilizando os operadores resto da divisão (mod) e divisão entre inteiros (div), temos:

somadig 259 = (259 `mod` 10) + somadig (259 `div` 10) somadig 25 = (25 `mod` 10) + somadig (25 `div` 10) somadig 2 = (2 `mod` 10) + somadig (2 `div` 10) somadig 0 = 0

E o script fica:

fib :: Integer −−−−>>>> Integer

fib 0 = 0 fib 1 = 1

fib n = fib (n-2) + fib (n-1)

somadig :: Integer −−−>−>>> Integer

somadig 0 = 0

(26)

Exercício 16: Maior Número de uma Lista

Crie uma função que informe o maior número de uma lista de números inteiros.

Utilizaremos duas funções do Haskell: last (que obtém o último elemento de uma lista) e sort (que classifica a lista em ordem crescente; esta função necessita import List):

Exercício 17: Soma de N Números

Crie uma função que some os números de uma lista de inteiros, sem utilizar a função sum.

Utilizaremos aqui o operador cons ( : ), que insere um elemento na primeira posição da lista.

Uma lista pode ser representada em termos de seus elementos e o operador cons. Por exemplo, a lista:

[1,2,3] pode ser representada como: 1 : [2,3] , também pode ser representada como: 1 : 2 : [3] , bem como

por: 1 : 2 : 3 : [ ] . Neste caso dizemos que o primeiro elemento é a cabeça da lista e os demais elementos formam a cauda.

Se x é um elemento da lista e xs é a cauda, podemos representar uma lista como: x : xs . Por exemplo, para a lista fornecida acima, 1:[2,3], x seria igual a 1 e xs seria igual a [2,3].

Dito isto, a soma dos elementos de uma lista seria igual a:

soma [1,2,3] = 1 + soma [2,3] soma [2,3] = 2 + soma [3] soma [3] = 3 + soma [ ] soma [ ] = 0

ou, utilizando o operador cons:

( x : xs ) x xs

soma 1 : [2,3] = 1 + soma [2,3] soma 2 : [3] = 2 + soma [3] soma 3 : [ ] = 3 + soma [ ] soma [ ] = 0

A soma dos elementos de uma lista vazia é sempre igual a 0 (zero), pois não existem elementos a somar. No caso acima, é uma condição de parada, pois ao efetuar a chamada da função soma passando uma lista vazia como argumento, a função retorna 0 sem efetuar nova chamada a ela mesma de forma recursiva.

Em Haskell, o argumento utilizando cons deve ser delimitado por parênteses, como em (x : xs):

import List

maior :: [ Integer ] −−−−>>>> Integer

maior lista = last ( sort lista )

soma :: [ Integer ] −−−>−>>> Int

soma [ ] = 0

(27)

Exercício 18: Lista Contida em Outra – versão 2

Crie uma função que verifique se uma lista está contida em outra (sem utilizar a função \\ ).

Para resolver este exercício, vamos utilizar as funções: length, sort, !! , inits e or. Você verá, após a resolução do exercício, que é muito mais fácil resolvê-lo utilizando a função diferença entre listas ( \\ ), mas a proposta aqui é desenvolver o raciocínio pela busca de soluções diferentes das já encontradas.

Antes de iniciar a resolução do exercício, porém, vamos explicar como as funções citadas funcionam. Dada a lista: a = [ 1 , 7 , 5 , 3 , 9 ]

i) Obter o comprimento da lista A: length a

length a informa o comprimento da lista (número de elementos não nulos dessa lista)

Neste caso, length a = 5

ii) Para ordenar os elementos de uma lista a qualquer, fazemos: sort a (necessita import List). Por exemplo,

sort [ 1 , 7 , 5 , 9 , 3 ]

produz: [ 1 , 3 , 5 , 7 , 9 ]

iii) Obter o elemento de uma posição (índice) qualquer de A: a !! posição Neste caso, a !! 0 = 1

a !! 1 = 7 a !! 2 = 5 a !! 3 = 3 a !! 4 = 9

Obs.: Note que a primeira posição é a posição 0 (zero) e a última posição é igual ao comprimento da lista subtraído de 1.

Obs.: Se tivéssemos ordenado a lista antes, teríamos um resultado diferente:

( sort a ) !! 0 = 1 ( sort a ) !! 1 = 3 ( sort a ) !! 2 = 5 ( sort a ) !! 3 = 7 ( sort a ) !! 4 = 9

iv) Obter a disjunção de uma lista boolena (lista de elementos lógicos, ou booleanos): or lista Dada as listas booleanas: b = [ True , True , False , False , True ]

c = [ False , False , False ]

Temos: or b = True or c = False

(28)

A aplicação de inits (necessita import List ) sobre uma lista produz o desmembramento dessa lista em sublistas. Por exemplo:

inits [ 1 , 5 , 2 , 3 , 0 ]

produz: [ [ ] , [1] , [1,5] , [1,5,2] , [1,5,2,3] , [1,5,2,3,0] ] e, inits ( sort [ 1 , 5 , 2 , 3 , 0 ] )

produz: [ [ ] , [0] , [0,1] , [0,1,2] , [0,1,2,3] , [0,1,2,3,5] ]

Em Haskell, podemos verificar se uma lista está contida em outra, realizando a disjunção da lista formada pela comparação da lista ordenada a com cada um dos elementos da lista resultante da aplicação de

inits à lista ordenada b.

O script Haskell fica, então:

import List a = [ 1 , 2 , 0 , 3 ] b = [ 1 , 5 , 2 , 3 , 0]

contida = or [ sort a == (inits (sort b)) !! i | i <<<<−−−− [ 0 .. length (inits b) - 1] ] Obs.: Os passos que ocorrem ao se executar o script acima são:

contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0 .. length (inits b) - 1] ]

contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0 .. length ( [ [ ],[1],[1,5],[1,5,2],[1,5,2,3],[1,5,2,3,0] ] ) - 1] ] contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0 .. length ( [ [ ],[1],[1,5],[1,5,2],[1,5,2,3],[1,5,2,3,0] ] ) - 1] ] contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0 . . 6 - 1] ]

contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0 . . 5] ] contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [ sort a == (inits (sort b)) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == (inits (sort b)) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == (inits (sort b)) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == (inits ([0,1,2,3,5])) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == (inits ([0,1,2,3,5])) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ← [ 0,1,2,3,4,5 ] ] contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] i ←←←← 0 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 0 , produz: [ ] [ 0,1,2,3 ] == [ ] , produz: False contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] i ←←←← 1 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 1 , produz: [0] [ 0,1,2,3 ] == [0] , produz: False

(29)

contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] i ←←←← 2 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 2 , produz: [0,1] [ 0,1,2,3 ] == [0,1] , produz: False contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] i ←←←← 3 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 3 , produz: [0,1,2] [ 0,1,2,3 ] == [0,1,2] , produz: False contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] i ←←←← 4 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 4 , produz: [0,1,2,3] [ 0,1,2,3 ] == [0,1,2,3] , produz: True contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,5 ] ] i ←←←← 5 ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! 5 , produz: [0,1,2,3,5] [ 0,1,2,3 ] == [0,1,2,3,5] , produz: False contida = or [[ 0,1,2,3 ] == ([ [ ],[0],[0,1],[0,1,2],[0,1,2,3],[0,1,2,3,5] ]) !! i | i ←←←← [ 0,1,2,3,4,5 ] ] contida = or [False,False,False,False,True,False] contida = or [False,False,False,False,True,False] contida = True

Ou seja, os elementos de a = [ 1 , 2 , 0 , 3 ] estão contidos na lista b = [ 1 , 5 , 2 , 3 , 0].

Exercício 19: Lista Contida em Outra – versão 2

Crie uma função que verifique se uma lista está contida em outra (sem utilizar a função \\ ).

Para resolver este exercício, vamos utilizar a função elem que retorna True se um elemento for pertencente à lista:

Neste exemplo, para todo elemento da lista1 é efetuada a sua pertinência à lista2. Caso um determinado elemento da lista1 não seja elemento da lista2, executar x `elem` lista2 retorna False e, em conseqüência disto, a conjunção da lista final retorna False.

contido :: [Integer] −−−−>>>> [Integer] −−−−>>>> Bool

(30)

1.11. Funções de Haskell para Manipulação de Listas

A seguir, são listadas várias funções de Haskell para manipular listas, inclusive as que já foram utilizadas neste trabalho.

Tabela 5: Funções de Haskell para manipulação de listas

Descrição Operação Resultado

Insere um elemento a uma lista utilizando cons ( : ) 1 : [ 2 , 3 ] 'm' : "at discreta" [ 1 , 2 , 3 ] "mat discreta" Concatena duas listas ( ++ ) [ 1 , 2 ] ++ [ 3 , 4 ] "mat " ++ "discreta" [1 , 2 , 3 , 4 ] "mat discreta" Retorna o enésimo elemento de uma lista ( !! )

[ 1 , 3 , 5 ] !! 0 1 [ 1 , 3 , 5 ] !! 1 3 [ 1 , 3 , 5 ] !! 2 5 Concatena os elementos de uma lista de listas

produzindo uma lista simples (concat) concat [ [1,2] , [3,4] ] [ 1 , 2 , 3 , 4 ] Obtém o comprimento de uma lista (length) length [ 1 , 5 , 10 ] 3

Retorna o primeiro elemento de uma lista (head) head [ 1 , 3 , 5 ] 1 Retorna o último elemento de uma lista (last) last [ 1 , 3 , 5 ] 5 Com exceção do primeiro, retorna todos os

elementos de uma lista (tail) tail [ 1, 2 , 3 , 4 ] [ 2 , 3 , 4 ] Com exceção do último, retorna todos os elementos

de uma lista (init) init [ 1, 2 , 3 , 4 ] [ 1, 2 , 3 ] Cria uma lista com n cópias do item especificado

(replicate) replicate 5 1 [ 1 , 1 , 1 , 1 , 1 ] Obtém os n elementos iniciais de uma lista (take) take 3 [ 1, 3 , 5 , 7, 9 ] [ 1, 3 , 5 ] Retira os n elementos iniciais de uma lista (drop) drop 3 [ 1, 3 , 5 , 7, 9 ] [ 7, 9 ]

Divide uma lista em uma dada posição (splitAt) splitAt 3 [ 1, 3, 5, 7, 9 ] ( [ 1, 3, 5 ] , [ 7, 9 ] ) Inverte a ordem dos elementos de uma lista (reverse) reverse [ 1, 3, 5, 7, 9 ] [ 9, 7, 5, 3, 1 ] Obtém uma lista de pares a partir de um par de

listas (zip) zip [ 1 , 2 ] [ 3 , 4 ] zip [ 1 , 2 , 5] [ 3 , 4 ] [ ( 1, 3 ) , ( 2 , 4 ) ] [ ( 1, 3 ) , ( 2 , 4 ) ] Obtém um par de listas a partir de uma lista de

pares (unzip) unzip [ ( 1, 3 ) , ( 2 , 4 ) ] ( [ 1 , 2 ] , [ 3 , 4 ] ) Obtém a soma dos elementos de uma lista (sum) sum [ 1, 3 , 5 ] 9

Obtém o produto dos elementos de uma lista

(product) product [ 1, 3 , 5 ] 15

Opera a conjunção de uma lista de booleanos (and) and [ True , False ] False Opera a disjunção de uma lista de booleanos (or) or [ True , False ] True

Transforma todos os elementos de uma lista (map) map (^2) [ 1 , 2 , 3 , 4 ] [ 1 , 4 , 9 , 16 ] Obtém uma lista a partir de uma lista original

fornecido um filtro (filter) filter (> 2) [ 1 , 2 , 3 , 4 ] [ 3 , 4 ] Cria uma lista a partir de uma lista original

enquanto uma condição for satisfeita (takewhile) takeWhile (< 5) [ 1 .. 9 ] [ 1 , 2 , 3 , 4 ] Cria uma lista a partir de uma lista original após

(31)

Tabela 6: Funções de Haskell para manipulação de listas que necessitam import List

Descrição Operação Resultado

Retira os elementos repetidos de uma lista (nub) nub [ 1 , 1 , 2 , 3 , 3 , 4 ] [ 1 , 2 , 3 , 4 ] Retira de uma lista a primeira ocorrência de um

elemento especificado (delete) delete 3 [ 1 , 2 , 3 , 3 , 4 ] [ 1 , 2 , 3 , 4 ] Produz a união entre duas listas (union) union [ 1 , 2 ] [ 3 , 4 ] [ 1, 2 , 3 , 4 ] Produz a interseção entre duas listas (intersect) intersect [ 1,2,3,4 ] [ 1,2 ] [ 1, 2 ] Produz a diferença entre duas listas (\\) [ 1,2,3,4 ] \\ [ 1,2 ] [ 3 , 4 ] Cria agrupamentos a partir dos elementos de uma

lista (group)

group [ 1 , 2 , 3 ] [ [1] , [2] , [3] ] group [ 1 , 1 , 2 , 3 ] [ [1,1] , [2] , [3] ] group [ 1 , 1 , 2 , 2 , 3 ] [ [1,1] , [2,2] , [3] ] Cria agrupamentos a partir do início de uma lista

(inits) inits [ 1 , 2 , 3 ] inits [ 1 , 1 , 2 ] [ [ ],[1],[1,2],[1,2,3] ] [ [ ],[1],[1,1],[1,1,2] ] Cria agrupamentos a partir de todos os elementos de

uma lista (tails) tails [ 1 , 2 , 3 ] tails [ 1 , 1 , 2 ] [ [1,2,3],[2,3],[3],[ ] ] [ [1,1,2],[1,2],[2],[ ] ] Ordena uma lista (sort) sort [ 2 , 5 , 1 , 4 , 3 ] [ 1 , 2 , 3 , 4 , 5 ]

As funções da tabela 6 necessitam que se digite no início do script a assertiva import List, fazendo com que sejam carregadas para o ambiente de interpretação as definições de cada uma delas (das funções); do contrário, o Hugs emite uma mensagem de erro de sintaxe ao utilizá-las. Por exemplo, suponha que o arquivo

md.hs contenha na linha 10 o comando sort [1,3,2,0]. Ao carregar o script (:l md.hs) surge a mensagem:

ERROR “md.hs” : 10 - Undefined variable “sort”

1.12. Funções Matemáticas de Haskell

Tabela 7: Funções matemáticas de Haskell

Descrição Operação Resultado

Raiz quadrada de um número (sqrt) sqrt 4 2.0 Trunca um número, desprezando a parte fracionária

(truncate) trunc 1.1 trunc 1.9 1 1

Aproxima um número real para o seu inteiro mais

próximo (round) round 1.4 round 1.5 1 2 Aproxima um número real para o maior inteiro mais

próximo (ceiling) ceiling 1.1 ceiling 1.9 2 2 Aproxima um número real para o menor inteiro

mais próximo (floor)

floor 1.1 1

floor 1.9 1

Retorna o valor de pi (pi) pi 3.14159*

Retorna en (exp) exp 1 2.71828*

Logaritmo natural (log) log (exp 1) 1.0 Logaritmo na base especificada (logBase) logBase 10 1000 3.0 Seno de um ângulo em radianos (sin) sin (pi / 2) 1.0 Cosseno de um ângulo em radianos (cos) cos 0 1.0 Tangente de um ângulo em radianos (tan) tan (pi/4) 1.0 Arco-seno em radianos (asin) asin 1 1.5708**

Arco-cosseno em radianos (acos) acos 1 0.0**

Arco-tangente em radianos (atan) atan 1 0.785398**

*

Este valor é uma aproximação do valor real.

** Para verificar que ângulos são esses em graus, multiplique por 180 e divida por pi. Por exemplo, 1.5708rad

Referências

Documentos relacionados

De seguida, vamos adaptar a nossa demonstrac¸ ˜ao da f ´ormula de M ¨untz, partindo de outras transformadas aritm ´eticas diferentes da transformada de M ¨obius, para dedu-

6 Consideraremos que a narrativa de Lewis Carroll oscila ficcionalmente entre o maravilhoso e o fantástico, chegando mesmo a sugerir-se com aspectos do estranho,

Com o objetivo de compreender como se efetivou a participação das educadoras - Maria Zuíla e Silva Moraes; Minerva Diaz de Sá Barreto - na criação dos diversos

A Psicologia, por sua vez, seguiu sua trajetória também modificando sua visão de homem e fugindo do paradigma da ciência clássica. Ampliou sua atuação para além da

No entanto, para aperfeiçoar uma equipe de trabalho comprometida com a qualidade e produtividade é necessário motivação, e, satisfação, através de incentivos e política de

Este trabalho buscou, através de pesquisa de campo, estudar o efeito de diferentes alternativas de adubações de cobertura, quanto ao tipo de adubo e época de

A prova do ENADE/2011, aplicada aos estudantes da Área de Tecnologia em Redes de Computadores, com duração total de 4 horas, apresentou questões discursivas e de múltipla

17 CORTE IDH. Caso Castañeda Gutman vs.. restrição ao lançamento de uma candidatura a cargo político pode demandar o enfrentamento de temas de ordem histórica, social e política