matemÁtica discreta: resoluÇÃo de …¡tica discreta com...i matemÁtica discreta: resoluÇÃo de...

66
i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa [email protected] Novembro 2004

Upload: ngonhi

Post on 20-May-2018

237 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

i

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

COMPUTAÇÃO

José Luiz dos Anjos Rosa [email protected]

Novembro

2004

Page 2: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

ii

Í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

Page 3: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

iii

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

Page 4: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

iv

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

Page 5: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

1

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á “pronto” para receber suas digitações.

Page 6: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

2

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)

Figura 3: Resultado produzido pela função f

Page 7: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

3

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 True (Verdadeiro) e False (Falso)

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

Page 8: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

4

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 : R x = 10 – 2

x :: Float x = 10.0 – 2.0

Negação (unário) - x : Z x = -3 + 5

x :: Integer x = -3 + 5

Multiplicação * x : R x = 2 * 5

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

Page 9: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

5

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.

Page 10: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

6

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.

Page 11: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

7

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.

Page 12: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

8

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

Isto posto, temos que: [1,2,3] é igual a [1,2,3], porém, é diferente de: [1,3,2].

Page 13: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

9

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)

O que produz 1024 como resultado.

Page 14: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

10

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] b = [ x | x <<<<−−−− a , 2 < x && x < 6 ]

Page 15: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

11

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,

{ a , b } ∪∪∪∪ { c , d } = { a , b , c , d }

Page 16: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

12

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 )

Page 17: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

13

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).

f (x) = a. x + b

Page 18: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

14

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

Page 19: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

15

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 quad n = n * n

Page 20: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

16

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

Page 21: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

17

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 raizSomaQuad x y z = sqrt ( somaquad x y z )

Page 22: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

18

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

Page 23: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

19

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 primo num = [1,num] == [ i | i <<<<−−−− [1.. num] , num `mod` i == 0 ]

Page 24: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

20

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 fat n = n * fat ( n – 1 )

Page 25: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

21

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 somadig n = ( n `mod` 10 ) + somadig ( n `div` 10 )

Page 26: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

22

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 soma (x : xs) = x + soma xs

Page 27: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

23

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

Page 28: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

24

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

Page 29: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

25

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 contido lista1 lista2 = and [x `elem` lista2 | x <<<<−−−− lista1]

Page 30: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

26

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 ] [ 1 , 2 , 3 ] 'm' : "at discreta" "mat discreta"

Concatena duas listas ( ++ ) [ 1 , 2 ] ++ [ 3 , 4 ] [1 , 2 , 3 , 4 ] "mat " ++ "discreta" "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 ] [ ( 1, 3 ) , ( 2 , 4 ) ] zip [ 1 , 2 , 5] [ 3 , 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 uma condição for satisfeita (dropwhile)

dropWhile (< 5) [ 1 .. 9 ] [ 5 , 6 , 7 , 8 , 9]

Page 31: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

27

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 ] [ [ ],[1],[1,2],[1,2,3] ] inits [ 1 , 1 , 2 ] [ [ ],[1],[1,1],[1,1,2] ]

Cria agrupamentos a partir de todos os elementos de uma lista (tails)

tails [ 1 , 2 , 3 ] [ [1,2,3],[2,3],[3],[ ] ] tails [ 1 , 1 , 2 ] [ [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 1 trunc 1.9 1

Aproxima um número real para o seu inteiro mais próximo (round)

round 1.4 1 round 1.5 2

Aproxima um número real para o maior inteiro mais próximo (ceiling)

ceiling 1.1 2 ceiling 1.9 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.5708 rad

equivale a 90o (1.5708 * 180 / pi == 90.0) e 0.785398 rad equivale a 45º.

Page 32: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

28

2. Lógica Proposicional

2.1. Conceito de Proposição

Chama-se proposição ou sentença ao conjunto de palavras ou símbolos (oração declarativa) que

resultem em um pensamento de sentido completo, isto é, que possam receber uma dentre as duas classificações possíveis: verdadeiro (V) e falso (F).

Assim sendo, são proposições válidas:

- Sete mais cinco é igual a doze ( 7 + 5 = 14 ) ; V (proposição verdadeira) - Sete vezes cinco é igual a quinze ( 7. 5 = 15 ) ; F (proposição falsa) - Sete é menor que dezessete ( 7 < 17 ) ; V (proposição verdadeira) - Sete é maior que dezessete ( 7 > 17 ) ; F (proposição falsa) - Dois é divisor de onze ( 2 | 11 ) ; F (proposição falsa) - A Terra é redonda ; V (proposição verdadeira)

A lógica matemática clássica está baseada em dois princípios básicos:

- Princípio da Não Contradição: uma proposição não pode ser verdadeira e falsa ao mesmo tempo; - Princípio do terceiro Excluído: toda proposição ou é verdadeira ou é falsa, não se admitindo uma

terceira condição.

2.2. Proposição Simples e Composta

Proposição simples é aquela formada de apenas uma proposição, como em:

- matemática é fácil - Haskell é gostoso - 25 é o quadrado de 5

As proposições simples geralmente são representadas por letras minúsculas, quais sejam: p, q, r, s,... ,

chamadas também de letras proposicionais. Dito isto, podemos representar as proposições acima como:

p : matemática é fácil q : Haskell é gostoso r : 25 é o quadrado de 5 s : 5 é a raiz quadrada de 25

Proposição composta é aquela formada por duas ou mais proposições simples, como em:

- matemática é fácil e Haskell é gostoso - 25 é o quadrado de 5 ou 5 é a raiz quadrada de 25

As proposições compostas, também chamadas de fórmulas, geralmente são representadas por letras

maiúsculas, quais sejam: P, Q, R, S,... , chamadas também de letras proposicionais. Dito isto, podemos representar as proposições acima como:

P : matemática é fácil e Haskell é gostoso Q : 25 é o quadrado de 5 ou 5 é a raiz quadrada de 25

Page 33: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

29

2.3. Conectivos

Conectivos são as palavras que compõem as proposições compostas.

2.3.1. Negação ( ¬¬¬¬ )

Se uma proposição for a negação de uma proposição qualquer p , quando o valor lógico de p for o valor verdade o valor lógico da negação de p será o valor falso e, quando o valor lógico de p for o valor falso, valor lógico da negação de p será o valor verdade.

A negação de p, representada por ¬ p (leia: não p), pode ser visualizada melhor pela tabela abaixo:

Tabela 8: Negação

p ¬p V F F V

Exemplos: a) p : 9 > 5 (V) ¬p : 9 < 5 (F) b) q : Um é igual a dois (1 = 2) (F) ¬q : Um não é igual a dois (1 ≠ 2) (V) Obs.: A representação em forma de tabela apresentada acima para a negação é chamada de Tabela-

Verdade a qual contém todas as proposições envolvidas numa fórmula e os valores lógicos relacionados.

2.3.2. Negação em Haskell ( not )

Haskell define o operador lógico not para representar a negação de uma proposição. Por exemplo:

p :: Bool p = 9 > 5 naoP :: Bool naoP = not ( 9 > 5 )

Nesse caso, p é True e naoP é False.

Page 34: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

30

2.3.3. Conjunção ( ∧∧∧∧ )

Chama-se conjunção de duas proposições p e q à proposição cujo valor lógico é o valor verdade quando ambas as proposições forem verdadeiras.

A conjunção de p e q, representada por p ∧ q (leia: p e q), pode ser visualizada melhor pela tabela abaixo:

Tabela 9: Conjunção

p q p ∧ q F F F F V F V F F V V V

Exemplos: a) p : 9 > 5 (V) q : 15 > 9 (V) p ∧ q : 9 > 5 e 15 > 9 (V) b) p : 3 é divisor de 6 (V) q : 6 é divisor de 15 (F) p ∧ q : 3 | 6 e 6 | 15 (F)

2.3.4. Conjunção em Haskell ( && )

Haskell define o operador lógico && para representar a conjunção entre duas proposições. Por exemplo:

p :: Bool p = 9 > 5 q :: Bool q = 15 > 9 conj :: Bool conj = p && q

Nesse caso, conj é True.

Page 35: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

31

2.3.5. Disjunção ( ∨∨∨∨ )

Chama-se disjunção de duas proposições p e q à proposição cujo valor lógico é o valor verdade quando pelo menos uma das proposições for verdadeira.

A disjunção de p e q, representada por p ∨ q (leia: p ou q), pode ser visualizada melhor pela tabela abaixo:

Tabela 10: Disjunção

p q p ∨ q F F F F V V V F V V V V

Exemplos: a) p : 9 > 5 (V) q : 15 > 9 (V) p ∧ q : 9 > 5 ou 15 > 9 (V) b) p : 3 é divisor de 6 (V) q : 6 é divisor de 15 (F) p ∧ q : 3 | 6 ou 6 | 15 (V)

2.3.6. Disjunção em Haskell ( | | )

Haskell define o operador lógico | | (utiliza-se o caractere pipe ) para representar a disjunção entre duas proposições. Por exemplo:

p :: Bool p = 3 `mod` 6 == 0 q :: Bool q = 6 `mod` 15 == 0 disj :: Bool disj = p | | q

Nesse caso, disj é True.

Page 36: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

32

2.3.7. Condicional ( →→→→ )

Chama-se proposição condicional àquela que contém duas proposições denominadas antecedente e

conseqüente, cujo valor lógico é o valor falso quando o antecedente é verdadeiro e o conseqüente é falso. Denominando-se o antecedente por p e o conseqüente por q, representa-se a condicional de duas

proposições p e q por p → q (leia: se p então q), e que pode ser visualizada melhor pela tabela abaixo:

Tabela 11: Condicional

p q p → q F F V F V V V F F V V V

Exemplos: a) p : 9 > 5 (V) q : 15 > 9 (V) p → q : se 9 > 5 então 15 > 9 (V) b) p : 3 é divisor de 6 (V) q : 6 é divisor de 15 (F) p → q : se 3 | 6 então 6 | 15 (F) c) p : o jacaré é pescoçudo (F) q : a girafa é baixinha (F) p → q : se o jacaré é pescoçudo então a girafa é baixinha (V) De acordo com a tabela-verdade para o condicional, se o antecedente é verdade e o conseqüente é falso

então A → B é falso senão A → B é verdade. Isto posto, pode-se dizer que não se deduz o valor do conseqüente em função do valor do antecedente,

e sim que há uma relação entre eles dada pela tabela-verdade.

2.3.8. Condicional em Haskell

Haskell não define um operador lógico condicional. Neste caso, temos que criar um operador que o represente. Para isso:

- escreva o nome do operador entre parênteses e defina quais os tipos dos operandos envolvidos,

seguido do tipo do resultado que o operador irá produzir (aqui, o operador envolverá dois operandos booleanos – lógicos – produzindo um resultado igualmente booleano);

- na linha seguinte, implemente o operador, utilizando os operandos e os conectivos que sejam necessários.

Por exemplo, para implementar a lógica da proposição condicional, será criado o operador −−−−−−−−>>>>

(contendo dois caracteres hífen e um caracter maior que) que representará o condicional (para não haver conflito com o construtor de tipos de função: −−−−>>>>):

(−−−−−−−−>>>>) :: Bool −−−−>>>> Bool −−−−>>>> Bool

antec −−−−−−−−>>>> conseq = ( not antec ) || conseq

Page 37: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

33

Para testar o operador condicional criado, experimente:

(6 `mod` 3 == 0) −−−−−−−−>>>> (15 `mod` 6 == 0)

Nesse caso, −−−−−−−−>>>> retorna False, pois 6 `mod` 3 == 0 é verdade (6 é divisível por 3) e 15 `mod` 6 == 0 é falso (15 não é divisível por 6).

2.3.9. O operador if ... then ... else Poderíamos implementar o operador condicional utilizando o operador Haskell if ... then ... else ..., que

trabalha com três argumentos, a saber: if <condição> then <ação caso a condição seja verdadeira> else <ação caso a condição seja falsa>

Assim sendo, teremos :

<condição>: antec == True && conseq == False <ação caso a condição seja verdadeira>: retornar False <caso a condição seja falsa>: retornar True e a função fica como: (−−−−−−−−>>>>) :: Bool −−−−>>>> Bool −−−−>>>> Bool antec −−−−−−−−>>>> conseq = if antec == True && conseq == False then False else True ou, substituíndo antec == True por simplesmente antec e conseq == False por not conseq, vem:

(−−−−−−−−>>>>) :: Bool −−−−>>>> Bool −−−−>>>> Bool antec −−−−−−−−>>>> conseq = if antec && not conseq then False else True

2.3.10. Bicondicional ( ↔↔↔↔ )

Chama-se proposição bicondicional àquela que contém duas proposições denominadas antecedente e

conseqüente, cujo valor lógico é o valor verdadeiro quando ambos antecedente e conseqüente têm o mesmo valor lógico e falso nos demais casos.

Denominando-se o antecedente por p e o conseqüente por q, representa-se a bicondicional de duas proposições p e q por p ↔ q (leia: p se e somente se q), e que pode ser visualizada melhor pela tabela abaixo:

Tabela 12: Bicondicional

p q p ↔ q F F V F V F V F F V V V

Page 38: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

34

Exemplos: a) p : 15 > 5 (V) q : 15 > 9 (V) p ↔ q : 15 > 9 se e somente se 15 > 5 (V) b) p : 3 é divisor de 6 (V) q : 6 é divisor de 15 (F) p ↔ q : 3 | 6 se e somente se 6 | 15 (F) c) p : o jacaré é pescoçudo (F) q : a girafa é baixinha (F) p ↔ q : jacaré é pescoçudo se e somente se a girafa é baixinha (V)

2.3.11. Bicondicional em Haskell

Haskell não define um operador lógico bicondicional. Neste caso, temos que criar um operador que o represente. Para isso:

- escreva o nome do operador entre parênteses e defina quais os tipos dos operandos envolvidos,

seguido do tipo do resultado que o operador irá produzir (aqui, o operador envolverá dois operandos booleanos – lógicos – produzindo um resultado igualmente booleano);

- na linha abaixo desta, implemente o operador, utilizando os operandos e os conectivos que sejam necessários.

Por exemplo, para implementar a lógica da proposição bicondicional, será criado o operador <<<<−−−−−−−−>>>> (contendo o sinal de menor que, seguido de dois caracteres hífen e do caracter maior que) que representará o bicondicional (utilizando o comando if ... then ... else ao invés de conectivos):

( <<<<−−−−−−−−>>>>) :: Bool −−−−>>>> Bool −−−−>>>> Bool antec <<<<−−−−−−−−>>>> conseq = if antec == conseq then True else False

carregue o script e teste o operador criado no prompt do Hugs:

False <<<<−−−−−−−−>>>> False

False <<<<−−−−−−−−>>>> True

True <<<<−−−−−−−−>>>> False

True <<<<−−−−−−−−>>>> True

Page 39: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

35

2.4. Exercícios

2.4.1. Proposição: ¬¬¬¬ ( p ∧∧∧∧ ¬¬¬¬ q ) Construir a tabela-verdade da proposição: ¬¬¬¬ ( p ∧∧∧∧ ¬¬¬¬ q ) e verificar os resultados pelo Haskell. a) Tabela-verdade:

p q ¬ q ( p ∧ ¬ q ) ¬ ( p ∧ ¬ q ) F F V F V F V F F V V F V V F V V F F V

b) Programa em Haskell: tv :: Bool −−−−>>>> Bool −−−−>>>> Bool tv p q = not ( p && not q )

2.4.2. Proposição: (p →→→→ q) ∨∨∨∨ (p ↔↔↔↔ r)

Construir a tabela-verdade da proposição: (p →→→→ q) ∨∨∨∨ (p ↔↔↔↔ r) e verificar os resultados pelo Haskell. a) Tabela-verdade:

p q r p → q p ↔ r (p → q) ∨ (p ↔ r) F F F V V V F F V V F V F V F V V V F V V V F V V F F F F F V F V F V V V V F V F V V V V V V V

b) Programa em Haskell: pqr242 :: [( Bool , Bool , Bool )] - - constrói uma lista com os valores de p, q e r pqr242 = [(p , q , r | p <− [False,True] , q <− [False,True] , r <− [False,True] ] implica242 :: [( Bool , Bool , Bool , Bool )] - - constrói uma lista com os valores de p, q, r e p → q implica242 = [(p , q , r , (p −−> q) ) | p <− [False,True] , q <− [False,True] , r <− [False,True] ] bicond242 :: [( Bool , Bool , Bool , Bool )] - - constrói uma lista com os valores de p, q, r e p ↔ q bicond242 = [( p , q , r , (p <−−> r) ) | p <− [False,True] , q <− [False,True] , r <− [False,True] ] prep242 :: [( Bool , Bool , Bool , Bool )] - - constrói uma lista com os valores de p, q, r e (p → q) ∨ (p ↔ r) prep242 = [( p , q , r , (p −−> q) || (p <−−> r) ) | p <− [False,True] , q <− [False,True] , r <− [False,True]]

Page 40: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

36

2.4.3. Tautologia

Construir a tabela-verdade da proposição: ( p ∧∧∧∧ q ) →→→→ ( p ↔↔↔↔ q ) e verificar os resultados pelo Haskell.

Tautologia é toda a proposição composta cujo valor lógico é sempre verdadeiro, independente dos valores lógicos das proposições simples que a compõem. a) Tabela-verdade:

p q p ∧ q p ↔ q p ∧ q → ( p ↔ q ) F F F V V F V F F V V F F F V V V V V V

b) Programa em Haskell: tautologia :: [( Bool , Bool , Bool )] - - constrói uma lista com os valores de p ∧ q → ( p ↔ q ) tautologia = [( p , q , (p && q) −−> (p <−−> q) ) | p <− [False,True] , q <− [False,True]] Obs.: Para verificar simplesmente se a proposição é tautológica, ao invés de listar seus valores lógicos,

poderíamos utilizar o script abaixo, que efetua a conjunção dos elementos da lista formada pelos valores lógicos possíveis da proposição composta (deve resultar: True):

tautologia :: Bool tautologia = and [ (p && q) −−> (p <−−> q) | p <− [False,True] , q <− [False,True] ]

2.4.4. Contradição

Construir a tabela-verdade da proposição: ¬¬¬¬ ( ( p ∧∧∧∧ q) →→→→ (p ∨∨∨∨ q) ) e verificar os resultados pelo Haskell.

Contradição é toda a proposição composta cujo valor lógico é sempre falso, independente dos valores lógicos das proposições simples que a compõem.

a) Tabela-verdade:

p q ¬ ( ( p ∧ q) → (p ∨ q) ) F F F F V F V F F V V F

b) Programa em Haskell: contradicao :: [Bool] contradicao= [ not ( (p && q) −−> (p || q) ) | p <− [False,True] , q <− [False,True] ] Obs.: Com raciocínio análogo ao seguido para a tautologia, para verificarmos simplesmente se a proposição é

uma contradição, efetua-se a disjunção dos elementos da lista formada pelos valores lógicos possíveis da proposição composta (deve resultar: False):

contradicao :: Bool tautologia= or [ not ( (p && q) −−> (p || q) ) | p <− [False,True] , q <− [False,True] ]

Page 41: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

37

2.4.5. Contingência

Construir a tabela-verdade da proposição: p ↔↔↔↔ ( p ∨∨∨∨ q ) e verificar os resultados pelo Haskell.

Contingência é toda a proposição composta que pode produzir um valor lógico falso ou verdadeiro dependendo dos valores lógicos das proposições simples que a compõem, ou seja, uma proposição é uma contingência se não é nem uma tautologia e nem uma contradição.

a) Tabela-verdade:

p q p ↔ ( p ∨ q ) F F V F V F V F V V V V

b) Programa em Haskell: contingencia :: [Bool] contingencia = [ (p <−−> (p || q)) | p <− [False,True] , q <− [False,True] ]

2.4.6. Implicação Lógica

Construir a tabela-verdade das proposições: p → q e p ↔ ( p ∨ q ) e verificar os resultados pelo Haskell.

Diz-se que duas proposições P e Q implicam logicamente, se Q(p,q,r,s,...) tem valor lógico verdadeiro todas as vezes que P(p,q,r,s,...) também tem valor lógico verdadeiro, ou seja: P(p,q,r,s,...) ⇒ Q(p,q,r,s,...).

a) Tabela-verdade: A proposição ( p → q ) ∧ q tem valor lógico verdadeiro nas linhas 2 e 4 e a proposição p ↔ ( p ∨ q ) tem valor lógico verdadeiro nas linhas 1,2 e 4. Portanto, dizemos que: proposição ( p → q ) ∧ q ⇒ p ↔ ( p ∨ q ). b) Programa em Haskell: implica :: Bool implica = and [ ( (p −−> q ) && q ) && ( not ( p && ( not q ) ) ) | p <− [False,True], q <− [False,True] , ( (p −−> q ) && q ) == True ]

p q ( p → q ) ∧ q ¬ ( p ∧ ¬ q ) F F F V F V V V V F F F V V V V

Linha 1 2 3 4

Page 42: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

38

2.4.7. Regras Da implicação lógica entre duas proposições (donde: para p sendo verdadeira, que q também seja), definem-se as regras abaixo:

2.4.7.1. Regra de Inferência Adição : p ⇒ p ∨ q e q ⇒ p ∨ q Simplificação : p ∧ q ⇒ p e p ∧ q ⇒ q 2.4.7.2. Regra do Silogismo Disjuntivo ( p ∨ q ) ∧ ¬ p ⇒ q 2.4.7.3. Regra Modus Ponens ( p → q ) ∧ p ⇒ q 2.4.7.4. Regra Modus Tollens ( p → q ) ∧ ¬ q ⇒ ¬ p 2.4.7.5. Regra do Silogismo Hipotético ( p → q ) ∧ ( q → r ) ⇒ p → r

2.4.8. Equivalência Lógica

Construir a tabela-verdade das proposições: p → q e p ↔ ( p ∨ q ) e verificar os resultados pelo Haskell.

Diz-se que duas proposições P e Q são equivalentes logicamente, se suas tabelas-verdade são idênticas, ou seja: P(p,q,r,s,...) ⇔ Q(p,q,r,s,...). a) Tabela-verdade: b) Programa em Haskell: equivalentes :: [ ( Bool , Bool ) ] - - mostra, lado a lado, os valores lógicos de cada proposição simples. equivalentes = [ ( ( p −−> q ) , ( not ( p && ( not q ) ) ) ) | p <− [False,True], q <− [False,True] ]

p q p → q ¬ ( p ∧ ¬ q ) F F V V F V V V V F F F V V V V

Linha 1 2 3 4

Page 43: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

39

Obs.: Dadas duas proposições equivalentes, então, por conseqüência, o valor lógico da bicondicional é sempre verdadeira, ou seja, é tautológica. Portanto, toda bicondicional tautológica corresponde a uma equivalência lógica.

2.4.9. Propriedades da Equivalência Lógica - Reflexiva: P (p,q,r,...) ⇔ P (p,q,r,...) - Simétrica: Se P (p,q,r,...) ⇔ Q (p,q,r,...) então Q (p,q,r,...) ⇔ P (p,q,r,...) - Transitiva: Se P (p,q,r,...) ⇔ Q (p,q,r,...) e Q (p,q,r,...) ⇔ R (p,q,r,...) então P (p,q,r,...) ⇔ R (p,q,r,...)

2.4.10. Regras Da equivalência lógica entre proposições, definem-se as regras abaixo:

2.4.7.6. Regra da Comutatividade p ∧ q ⇔ q ∧ p

2.4.7.7. Regra da Associatividade ( p ∧ q ) ∧ r ⇔ p ∧ ( q ∧ r ) ( p ∨ q ) ∨ r ⇔ p ∨ ( q ∨ r )

2.4.7.8. Regra da Distributividade p ∧ ( q ∨ r ) ⇔ ( p ∧ q ) ∨ ( p ∧ r ) p ∨ ( q ∧ r ) ⇔ ( p ∨ q ) ∧ ( p ∨ r )

2.4.7.9. Regra de De Morgan ¬ ( p ∧ q ) ⇔ ¬ p ∨ ¬ q ¬ ( p ∨ q ) ⇔ ¬ p ∧ ¬ q

2.4.7.10. Regra da Idempotência p ∧ p ⇔ p p ∨ p ⇔ p

2.4.7.11. Regra da Dupla Negação ¬ ( ¬ p ) ⇔ p

Page 44: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

40

2.4.7.12. Regra da Condicional p → q ⇔ ¬ p ∨ q

2.4.7.13. Regra da Bicondicional p ↔ q ⇔ ( p → q ) ∧ ( q → p ) p ↔ q ⇔ ( p ∧ q ) ∨ ( ¬ p ∧ ¬ q )

2.4.7.14. Regra da Contraposição p → q ⇔ ¬ q → ¬ p

2.4.7.15. Regra da Absorção p → p ∧ q ⇔ p → q

2.4.7.16. Regra de CLAVIUS ¬ p → p ⇔ p

2.4.7.17. Método da Demonstração por Absurdo p ∧ ¬ q → c ⇔ p → q Obs.: c é uma contradição!

2.4.7.18. Regra de Exportação-Importação p ∧ q → r ⇔ p → ( q → r )

2.4.11. Negação Conjunta

Chama-se negação conjunta de duas proposições p e q a proposição “não p e não q” (simbolizado por: ¬ p ∧ ¬ q ), ou, utilizando o conectivo de SCHEFFER ( ↓ ) : p ↓ q , sendo a tabela-verdade como:

p q p ↓ q F F V F V F V F F V V F

Page 45: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

41

2.4.12. Negação Disjunta

Chama-se negação disjunta de duas proposições p e q a proposição “não p ou não q” (simbolizado por: ¬ p ∨ ¬ q ), ou, utilizando o conectivo de SCHEFFER ( ↑ ) : p ↑ q , sendo a tabela-verdade como:

p q p ↑ q F F V F V V V F V V V F

Page 46: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

42

3. Lógica de Predicados

3.1. Introdução

Frase é um enunciado de sentido completo, podendo ser constituída de uma ou mais palavras, contendo

ou não um verbo, como por exemplo:

- Cuidado! - Quanta besteira! - Um programa se faz com comandos.

Uma frase pode conter uma ou mais orações. Contém uma oração, se apresenta uma só forma verbal ou duas ou mais formas verbais, integrantes de

apenas uma locução verbal (verbo auxiliar + verbo principal), como em:

- José é bom aluno. - Pode fazer o exercício.

Contém mais de uma oração, quando há mais de um verbo, como em:

- Eu fiz o exercício, mas errei a última questão.

Uma oração tem como termos essenciais o sujeito e o predicado, sendo:

- Sujeito: o ser sobre o qual se faz uma declaração; - Predicado: tudo aquilo que se diz do sujeito.

Sendo assim, na oração José é bom aluno. tem-se:

José é bom aluno. sujeito predicado

3.2. Linguagem Simbólica

Vamos, agora, reescrever a frase José é bom aluno. utilizando uma linguagem simbólica, que

representará o predicado por uma letra maiúscula e o sujeito entre parênteses. Considerando-se B como representando o predicado é bom aluno vem:

B (José) Poderíamos escolher um universo qualquer para compor várias sentenças semelhantes:

B (José) B (João) B (Joaquim)

Page 47: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

43

No caso de o universo incluir um número maior de sujeitos, costuma-se utilizar variáveis para aludir a um elemento do conjunto, utilizando-se as letras x, y e z para esse fim. Assim, a sentença:

B (José)

é reescrita de forma mais conveniente como:

B (x)

podendo ser simplificada retirando-se os parênteses:

Bx

Assim sendo, predicados ficam simbolizados por letras maiúsculas, enquanto que os sujeitos ficam

representados por letras minúsculas, formando sentenças abertas (também chamadas abertos). Os abertos não são falsos e nem verdadeiros, mas sim, satisfeitos para uma determinada gama de variáveis e não satisfeitos para uma outra gama de variáveis.

Um predicado pode ser composto de uma ou mais variáveis, como em:

P (x) : representando: x é par D (x, y) : representando: x é divisor de y M (x, y) : representando: x é maior que y E (x, y,z) : representando: x está entre y e z

A substituição de uma variável por um elemento do universo considerado é denominada instanciação, o que faz com que um aberto vire uma proposição que, esta sim, pode assumir o valor falso ou verdadeiro.

A satisfatibilidade de uma sentença se faz com os elementos do conjunto-verdade, ou seja, com os elementos que tornam a proposição verdadeira.

Há uma outra forma de transformar um aberto em proposição, o que se faz com o auxílio dos quantificadores universal e existencial.

3.3.1. Quantificador Universal ( ∀∀∀∀ )

A expressão ∀ pode ser lida como:

- qualquer que seja

- para todo

Este quantificador é utilizado quando todos os elementos do conjunto universo têm uma certa propriedade. Por exemplo, considerando o conjunto dos naturais, excluindo-se o zero, N*

= {1,2,3,4,5,...} a proposição “ Para todo x, x>0 ” é uma proposição verdadeira, e pode ser simbolizada facilmente utilizando-se o quantificador universal:

(∀∀∀∀x) ( x > 0)

Observe que, se o conjunto universo considerado for o conjunto dos números inteiros, a expressão

acima tem valor lógico falso, pois nem todos os elementos do domínio considerado são maiores que zero.

Page 48: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

44

3.3.2. Quantificador Existencial ( ∃∃∃∃ )

A expressão ∃ pode ser lida como:

- existe pelo menos um

- para algum

Este quantificador é utilizado quando um elemento, pelo menos, do conjunto universo tem uma certa propriedade. Por exemplo, considerando o conjunto dos inteiros, Z = {...,-3,-2,-1,0,1,2,3,...} a proposição “ Existe pelo menos um n tal que n + (-n) = 0 ” é uma proposição verdadeira, e pode ser simbolizada facilmente utilizando-se o quantificador existencial:

(∃∃∃∃n) ( n + (-n) = 0)

3.3.3. Combinação de Fórmulas

Por vezes, a simbolização exige a combinação de fórmulas, como em:

“ Se x é um número inteiro e maior que zero e y é um número inteiro negativo, então o dobro de x é sempre maior que o dobro da soma entre x e y. ”

Analisando-se a estrutura acima tem-se:

- antecedentes: Se x é um número inteiro e maior que zero e y é um número inteiro negativo - conseqüente: então o dobro de x é sempre maior que o dobro da soma entre x e y

Vamos utilizar os seguintes símbolos:

- x∈ Z : x é inteiro

- y∈ Z: y é inteiro

- P(x) : x é maior que zero (positivo) - N(y): y é negativo

- D(x) : dobro de x

- S(x,y) : soma de x e y

A sentença, portanto, fica como:

(∀∀∀∀x∀∀∀∀y) ( x, y ∈∈∈∈ Z ) P(x) ∧∧∧∧ N(y) ) ⇒⇒⇒⇒ D(x) > D(S(x,y) Em várias situações encontraremos combinação de fórmulas, como em:

- N(x)•P(x) : x é um número e x é par (ou: N(x) ∧ P(x) ) - P(M(x,y)) : a multiplicação de x por y é par (ou: é par a multiplicação de x por y)

Obs.: Neste último exemplo, o resultado do processamento de M(x,y) é passado para P(n), a qual verifica se n é par.

- (∃x∃y) ( P(x) ∧ P(y) → P(S(x,y)) ) : se x é par e y é par, então a soma de x com y é par

Page 49: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

45

3.3.4. Resolução de Problemas

Resolver problemas em Haskell é, na maior parte das vezes, é identificar os antecedentes e os conseqüentes, analisando o problema como sendo uma frase, ou seja,:

- P é falsa em uma interpretação I se e somente se ¬P é verdadeira nessa I ; - Em uma dada interpretação I, uma sentença não pode ser simultaneamente verdadeira e falsa; - Se P e P → Q são verdadeiras em uma interpretação I, então Q também é verdadeira nessa

interpretação I; - Em uma dada interpretação I, P → Q é falsa se e somente se P é verdadeira e Q é falsa.

Isto posto, passemos a resolver o problema, anteriormente estudado, em Haskell, utilizando os

conceitos aprendidos até o momento.

“ Se x é um número inteiro e maior que zero e y é um número inteiro negativo, então o dobro de x é sempre maior que o dobro da soma entre x e y. ”

onde tem-se:

- antecedentes: Se x é um número inteiro e maior que zero e y é um número negativo - conseqüente: então o dobro de x é sempre maior que o dobro da soma entre x e y

chega-se aos símbolos:

- x∈ Z : x é inteiro

- y∈ Z: y é inteiro

- P(x) : x é maior que zero (positivo) - N(y): y é negativo

- D(x) : dobro de x

- S(x,y) : soma de x e y

com a sentença ficando como:

(∀∀∀∀x∀∀∀∀y) ( x, y ∈∈∈∈ Z ) P(x) ∧∧∧∧ N(y) ) ⇒⇒⇒⇒ D(x) > D(S(x,y)

ou seja, dados dois argumentos inteiros, o primeiro positivo e o segundo negativo, verificar se se trata de uma implicação lógica:

Símbolos Significado Haskell x∈ Z x é inteiro x :: Integer y∈ Z y é inteiro y :: Integer P(x) x é maior que zero p x = x > 0 N(y) y é negativo n y = y < 0 D(x) dobro de x d x = 2 * x

S(x,y) soma de x com y s x y = x + y

Page 50: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

46

Sejam as funções em Haskell abaixo: f :: Integer −> Integer −> Bool f x y = if (p x) && (n y) then d x > d (s x y) else not ( d x < d (s x y) ) p :: Integer −> Bool p x = x > 0 n :: Integer −> Bool n y = y < 0 d :: Integer −> Integer d x = 2 * x s :: Integer −> Integer −> Integer s x y = x + y Executando-se no prompt do Hugs: f 10 (-30) retorna o resultado True como esperado. Obs.: O valor -30 foi passado entre parênteses, pois executar: f 10 -30 , fará o Hugs interpretar a linha de

comando como sendo a chamada à função passando-se apenas um argumento, -20 (resultado da subtração de 10 por 30), o que é inválido, pois a função requer a passagem de dois argumentos inteiros.

Obs.: Para evitar erro de sintaxe, sempre forneça argumentos negativos entre parênteses.

Page 51: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

47

4. Exercícios

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

Exercício 4.1.1. Três amigos, José, Beto e Luis, marcaram encontro com três garotas. José sempre fala a verdade, Beto às vezes fala a verdade e Luis nunca fala a verdade. Quando elas chegaram, eles se identificaram. O que estava sentado à esquerda disse: “José é quem está sentado no meio”. O que estava sentado no meio disse: “Eu sou Beto”. Finalmente, o que estava sentado à direita, disse: “Luis é quem está sentado no meio”. Responda em que ordem eles estavam sentados. Solução: amigos = {José, Beto, Luis} Sejam a proposições: D : sentado à direita M : sentado no meio E : sentado à esquerda J = O que José diz = V B = O que Beto diz = ? L = O que Luis diz = F Afirmações: a1- E(Beto) ou E(Luis) => M(José) <==> B == Verdade ou L == Verdade a2- M(Beto) <==> B == Verdade a3- D(José) ou D(Beto) => M(Luis) <==> J == Verdade ou B == Verdade Conclusão: c1: De a1: B == Verdade ou L == Verdade; como L é sempre Falso, mas não sabemos se B é Verdade, não

sabemos se M(José); c2: De a2: B == Verdade; como não sabemos se B é Verdade, não sabemos se M(Beto); c3: De a3: J == Verdade ou B == Verdade; se J é sempre Verdade então M(Luis); c4: De a1: A partir de a3: M(Luis) => M(José) == Falso <==> B == Falso ou L == Falso; como L é sempre

Falso e B pode ou não ser Verdade então E(Beto) c4: De a2: Por exclusão: D(José) Resposta: Beto, Luis e José.

Page 52: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

48

Exercício 4.1.2. Haroldo, José e Attílio foram comprar um carro. Saíram satisfeitos da vida, cada um com seu carro. Havia na loja um Vectra, um Astra e um Escort para venda. Um dos carros é vermelho, um é cinza e o outro é branco. O carro de Haroldo é vermelho, o carro de Attílio é o Escort; o carro de José não é cinza e não é um Vectra. Qual é o modelo e qual é a cor de cada carro? Solução: donos = {Haroldo, José, Attílio} carros = {Vectra, Astra, Escort} cores = {vermelho, cinza, branco} Sejam a proposições: D : dono do carro M : modelo do carro C : cor do carro Afirmações: a1- C(x) == vermelho e C(y) == cinza e C(z) == branco a2- D(Haroldo) => C(vermelho) a3- D(Attílio) => M(Escort) a4- D(José) => ¬ C(cinza) e ¬ M(Vectra) Conclusão: c1: De a1: C(x) == vermelho e C(y) == cinza e C(z) == branco ; não é muito esclarecedor c2: De a2: D(Haroldo) => C(vermelho) <==> ¬ C(cinza) e ¬ C(branco) c3: De a3: D(Attílio) => M(Escort) <==> ¬ M(Vectra) e ¬ M(Astra) c4: De a4: D(José) => ¬ C(cinza) e ¬ M(Vectra) <==> M(Astra) e C(vermelho) ou M(Astra) e C(branco) ou

M(Escort) e C(vermelho) ou M(Escort) e C(branco) c5: De c2, c3 e 44: D(José) => ¬ C(vermelho) e ¬ C(cinza) e ¬ M(Brasilia) e ¬ M(Escort) <==>

M(Astra) e C(branco) c6: De a2 e c5: D(Attílio) <==> M(Escort) e C(cinza) c7: De c5 e c6: Por exclusão: D(Haroldo) <==> M(Vectra) e C(vermelho)

Resposta:

- José : .Astra branco. - Attílio : Escort cinza - Haroldo : Vectra vermelho

Page 53: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

49

Exercício 4.1.3. Se P é maior que Q então R é igual a S. Se R é menor ou igual a S então T é menor ou igual a U. Sendo T maior que U, responda quais são as relações entre R e S e entre P e Q. Solução: Se P é maior que Q então R é igual a S corresponde a:

P > Q => R = S Se R é menor ou igual a S então T é menor ou igual a U corresponde a:

R ≤ S => T ≤ U

Sendo T maior que U corresponde a:

T > U

Agrupando: P > Q => R = S R ≤ S => T ≤ U T > U E, Se T > U é verdade => T ≤ U ser falso Se T ≤ U é falso => R ≤ S é falso Se R ≤ S é falso => R = S ser falso Se R = S é falso => P > Q é falso Conclusão: Relação entre R e S: R > S Relação entre P e Q: P ≤ Q

Exercício 4.1.4. Ou Juarez é diretor ou João é coordenador. Se José é aluno então Joaquim não é professor. Se João é coordenador então Joaquim é professor. Sendo José aluno, o que se pode concluir sobre os demais? Solução: Diretor(Juarez) é representado por: D(Juarez) Coordenador(João) é representado por: C(João) Aluno(José) é representado por: A(José) Professor(Joaquim) é representado por: P(Joaquim) D(Juarez) ∨ C(João) A(José) => ¬ P(Joaquim) C(João) => P(Joaquim)

Page 54: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

50

Porém: A(José) é verdade Conclusão: A(José) é verdade => ¬ P(Joaquim) ser verdade ¬ P(Joaquim) é verdade => C(João) ser falso C(João) é falso => D(Juarez) ser verdade Sendo José aluno, pode-se concluir que: i- Joaquim não é professor ii- João não é coordenador iii- Juarez é diretor

Exercício 4.1.5. Seja a sentença: No Brasil, todos os maiores de 18 anos votam ou justificam seus votos. Pode-se dizer, a partir dela, que: a) Tem brasileiro maior de 18 anos que não vota e não justifica o voto b) Tem brasileiro maior de 18 anos que vota e justifica o voto c) Tem brasileiro maior de 18 anos que se não vota justifica o voto d) Tem brasileiro maior de 18 anos que se vota justifica o voto e) Tem brasileiro maior de 18 anos que se vota não justifica o voto

Solução: No Brasil, todos os maiores de 18 anos votam ou justificam seus votos corresponde a:

(∀b) (b > 18 => vota ∧ ¬ justifica o voto ∨ ¬ vota ∧ justifica o voto)

O que seria melhor entendido como:

(∀b) (b > 18 => vota ∧ ¬ justifica o voto ∨ ¬ vota ∧ justifica o voto) Conclusão: c) Tem brasileiro maior de 18 anos que se não vota justifica o voto

Page 55: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

51

4.2. Resolução Algorítmica de Problemas

Exercício 4.2.1.

A avaliação da expressão 3 + 4 == 4 + 3 resulta em: ( ) 7 ( ) 1 ( ) 0 ( x ) True ( ) False

Exercício 4.2.2.

Seja a seguinte definição de função: f :: Integer −> Integer −> Integer f x y = if x < y then x else y Desta forma, f a (f b c) vale

( ) a. ( ) b. ( ) c. ( ) maior entre a, b e c. ( x ) menor entre a, b e c.

Exercício 4.2.3.

A avaliação da expressão 3 + 4 /= 4 + 3 resulta em: ( ) 7 ( ) 1 ( ) 0 ( ) True ( x ) False

Exercício 4.2.4.

Se f é uma função tal que f 0 é igual a 10 e g é outra tal que g 0 é igual a 10, conclui-se que f (g 10) ( ) vale 0. ( ) vale 10. ( ) vale -10. ( ) vale 100. ( x ) resulta em um valor impossível de se afirmar.

Page 56: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

52

Exercício 4.2.5.

Seja a seguinte definição de função: f :: Integer −> Integer f x = if x < 3 then x else f (x – 1) A avaliação de f 2 resulta em ( ) 0 ( ) 1 ( x ) 2 ( ) 3 ( ) 4

Exercício 4.2.6.

Quanto vale f (f 10) para f definida por f x = x ? ( ) 0 ( x ) 10 ( ) 12 ( ) 20 ( ) 22

Exercício 4.2.7. Se o tipo de f é String −> String, qual o tipo de [ f x | x <− xs ] ? ( ) String −> String ( ) String ( x ) [ String ] ( ) Char ( ) [ Char ]

Exercício 4.2.8. Seja g x = [x] : g (tail x). Pode-se afirmar que ( x ) g não pode ser definida pois há erro de tipo. ( ) g só funciona para argumentos que sejam listas. ( ) g tem tipo [a] −> [a], sendo a um dos tios válidos de Haskell. ( ) g só funciona para argumentos que sejam listas com pelo menos 1 elemento. ( ) nenhuma das opções acima está correta.

Page 57: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

53

Exercício 4.2.9. Sendo a um dos tipos válidos em Haskell, qual das funções abaixo possui o tipo [ a ] −> b −> a ? ( x ) f x y = head x ( ) f x y = y ( ) f x y = head y : x ( ) f x y = tail y ( ) Nenhuma das opções acima.

Exercício 4.2.10. A expressão takeWhile even [ 10 , 8 .. 1 ] resulta em ( ) [ ] ( ) [ 10 ] ( ) [ 10 , 9 ] ( ) [ 9 , 7 , 5 , 3 , 1 ] ( x ) [ 10 , 8 , 6 , 4 , 2 ]

Exercício 4.2.11. Considere a seguinte função g :: Integer −> Integer −> Integer g n m = if n == m then n – m else g (n – 1) m e admita, também, que ela seja chamada sempre com valores n maiores do que m. Marque a resposta mais precisa. ( ) A função sempre produz n-m como resultado. ( ) A função pode entrar em um loop infinito. ( ) A função sempre produz n-1 como resultado. ( x ) A função sempre produz 0 como resultado. ( ) Nenhuma das opções acima.

Exercício 4.2.12. Marque V caso a sentença seja verdadeira e F caso seja falsa. ( F ) A expressão 3+4 < div 9 3 é inválida em Haskell. ( V ) Em Haskell sempre que utilizamos um condicional, há a necessidade de associar um else ao then. ( F ) [ [ ] ] é uma lista vazia. ( F ) Se f n = f (n + 1), sendo n :: Integer, então f 10 = 11. ( V ) Se f é uma função de inteiros para inteiros, então (f a) – (f a), sendo a um inteiro, sempre produzirá 0

como resultado. ( V ) É possível que, dependendo de uma função f que mapeia inteiros em inteiros, f 9 produza 3 como

resultado.

Page 58: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

54

( F ) Não importa qual seja a função f mapeando inteiros em inteiros que sempre teremos f 0 retornando 0 como resultado.

( F ) Se f e g são funções de inteiros para inteiros e a é inteira, então f (g a) é igual a g (f a). ( V ) Se x é um inteiro de dois dígitos, então (mod x 10) * 10 + div x 10 fornece um número que tem os

dois dígitos de x na ordem inversa. ( V ) A expressão a + 1 = 2, sendo a :: Integer, contém um erro. ( F ) Um tipo é um conjunto de valores inteiros. ( V ) Quaisquer que sejam as funções de inteiros para inteiros f e g, sempre teremos f 10 + g 3 sendo igual

a g 3 + f 10, pois a adição é comutativa em Haskell. ( F ) f :: (Integer, Integer) −> Integer é a assinatura de uma função que possui dois argumentos inteiros de

entrada. ( F ) Se td é uma função que determina quantos dígitos tem um número inteiro, então div n (td n) fornece

o dígito mais significativo de n, ou seja, aquele que ocorre mais à esquerda em n. ( F ) As listas em Haskell são bastante flexíveis com relação a como os seus elementos são calculados,

desde que nenhum deles seja obtido a partir de uma expressão condicional pois, neste caso, um erro de tipo é imediatamente enviado.

Exercício 4.2.13. Seja a seguinte definição de função: f :: Integer −> Integer f x = if x < 3 then x else f (x – 1) A avaliação de f 30 resulta em ( ) 0 ( ) 1 ( x ) 2 ( ) 3 ( ) 30

Exercício 4.2.14. Dentre os seguintes identificadores, quantos podem ser nomes de variáveis ou funções: soma_2, 2soma, Soma, soma? ( ) um ( x ) dois ( ) três ( ) quatro

Exercício 4.2.15. Sendo a um dos tipos válidos de Haskell, a −> a −> (a,a) é o tipo de funções que ( ) geram listas com dois elementos. ( ) têm dois argumentos repetidos e geram um par contendo a repetição destes valores. ( x ) têm argumentos de mesmo tipo e geram pares com componentes deste mesmo tipo. ( ) geram uma função cujos argumentos possuem o mesmo tipo do argumento de entrada.

Page 59: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

55

Exercício 4.2.16. Qual das funções abaixo não está em loop infinito? ( ) f x = f x + 1 ( ) f x = x + f 1 ( ) f x = f (x + 1) ( x ) f x = x + 1 ( ) f x = x : f x

Exercício 4.2.17. Seja a seguinte definição de função: f :: Integer −> Integer f [ ] = 1 f (x : xs) = x - f xs Então pode-se afirmar que: ( ) f determina o total de elementos da lista de entrada ( ) f determina a soma dos elementos da lista de entrada ( ) f retorna 0 qualquer que seja a lista de inteiros de entrada ( ) f possui um erro de tipo ( x ) Nenhuma das respostas acima

Exercício 4.2.18. Crie uma função que imprima os termos de uma PG, sendo fornecidos: o primeiro termo, ( a1 ), a razão ( q ) e o número de termos ( n ).

Solução: Sendo o termo geral da PG igual a: : an = a0 . q( n – 1 )., podemos construir a função: pg :: Integer −−−−>>>> Integer −−−−>>>> Integer −−−−>>>> [ Integer ] pg a0 q n = [a0 * q ^ ( i – 1 ) | i <<<<−−−− [ 1 .. n ] ] Por exemplo, executar: pg 2 2 10 retorna [ 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 512 , 1024 ] .

Page 60: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

56

Exercício 4.2.19. Escreva uma função que retorne a multiplicação de todos os dígitos de um número inteiro de entrada. Solução: Dado um determinado número, digamos, 123, a função deve retornar 6, resultante de: 1 x 2 x 3. Devemos multiplicar o dígito menos significativo com uma chamada recursiva à função, passando o restante dos dígitos, até que o argumento seja nulo, quando então a função deve retornar 1 (elemento nulo da multiplicação): f :: Integer −−−−>>>> Integer f 0 = 1 f num = num `mod` 10 * f (num `div` 10) Observe que a chamada à função com argumento nulo vem antes da chamada à função com argumento não nulo! Isto é necessário, pois do contrário a função continuria indefinidamente sua chamada, num loop infinito.

Exercício 4.2.20. O que produz a função f, definida como f [ ] = [ ] f (x:xs) = if x == [ ] then f [ ] else f ( [ x ] : xs ) Solução: Suponha que haja uma chamada á função passando-se a lista [1,2,3] como argumento. Então, f (x:xs) é o mesmo f (1:[2,3]), x é 1 e xs é [2,3], donde: f (1:[2,3]) => x == [ ] é falso => chamada à f ( [ 1 ] : xs ) Porém, f ( [ 1 ] : xs ) é um erro de tipo, pois para [ 1 ] : xs ser sintaticamente correta, xs deveria ser uma lista de lista, o que não é verdade, pois no início passamos a lista [1,2,3] e não a lista [ [ 1 ] , [ 2 ] , [ 3 ] ]. Ou seja, ocorre um erro de tipo.

Exercício 4.2.21. Escreva uma função para determinar se a soma do dígito mais significativo de um número com o seu dígito menos significativo é um número ímpar. Solução: Este problema será divido em sub-problemas: 1°- Determinação do dígito mais significativo de um número (digMais) 2°- Determinação do dígito menos significativo de um número (digMenos) 3°- Soma de dois números (soma) 4°- Verificar se um número é ímpar (impar)

Page 61: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

57

Implementando as funções: 1°- Função para determinar o dígito mais significativo de um número Aqui, devemos ir dividindo o número enquanto esta divisão (inteira) não resultar nula, quando então o dígito mais significativo do número foi encontrado: digMais :: Integer −−−−>>>> Integer digMais num = if num `div` 10 == 0 then num else digMais (num `div` 10) 2°- Função para determinar o dígito menos significativo de um número Aqui devemos simplesmente obter o resto da divisão do número por 10: digMenos :: Integer −−−−>>>> Integer digMenos num = num `mod` 10 3°- Soma de dois números soma :: Integer −−−−>>>> Integer −−−−>>>> Integer soma a b = a + b 4°- Verificar se um número é ímpar Podemos utilizar a função Haskell odd (por exemplo, odd 13 retorna True) ou podemos impar criar nossa própria função, sabendo-se que o resto da divisão (inteira) de um número ímpar por 2 é sempre 1: impar :: Integer −−−−>>>> Bool impar num = num `mod` 2 == 1 Juntando tudo, temos que: se impar ( soma (digMais num) (digMenos num) ) é verdade então a soma do dígito mais significativo de um número com o seu dígito menos significativo é um número ímpar: f :: Integer −−−−>>>> Bool f num = impar ( soma (digMais num) (digMenos num) )

Exercício 4.2.22. Escreva uma função para determinar o dobro do quadrado de um número inteiro. dobro :: Integer −−−−>>>> Integer dobro n = n * 2 quadrado :: Integer −−−−>>>> Integer quadrado n = n * n Utilizando composição de funções, temos: f :: Integer −−−−>>>> Integer f n = ( dobro . quadrado ) n

Page 62: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

58

Compor funções é o ato de utilizar a saída de uma função como entrada de uma outra função, ou seja, dadas duas funções f e g tem-se que: ( . ) :: (a -> b) −> (c -> a) −> (c -> b) ( f . g ) x = f ( g x ) onde: a, b e c são tipos válidos em Haskell. Note que foi utilizado o ponto ( . ) em substituição ao símbolo matemático ( o ) de composição de funções: ( f o g ) x . Note também, que x tem que ter tipo c, o mesmo tipo do argumento de g.

Composições em Haskell são associativas, logo: f . ( g . h ) = ( f . g ) . h implica em: realize h, depois realize g e, por último, realize f .

Exercício 4.2.23. Escreva uma função para determinar se o maior divisor de um número, exceto ele próprio, é um número primo. Solução: - Dividindo o problema em sub-problemas: 1°- Determinar os divisores do número (divisores) 2°- Encontrar o maior dos divisores (maiorDiv) 3°- Verificar se um número é primo (primo) - Implementando cada uma das funções: 1°- Determinar os divisores do número (divisores) Dada a lista geradora [1..n], construa uma sub-lista com todos os valores i vindos daquela lista que sejam múltiplos de n (n `mod` i == 0): divisores :: Integer −−−−>>>> [Integer] divisores n = [ i | i <<<<−−−− [1..n] , n `mod` i == 0] 2°- Encontrar o maior dos divisores (maiorDiv) Utilizando composição de funções (consulte as funções last e init na tabela 5): maiorDiv n = ( last . init . divisores ) n 3°- Verificar se um número é primo (primo) primo :: Integer −−−−>>>> Bool primo n = [1,n] == (divisores n) Resolvendo (novamente utilizando composição de funções): f :: Integer −−−−>>>> Bool f n = ( primo . maiorDiv ) n

Page 63: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

59

Exercício 4.2.24. Um número é dito Juareziano se o seu dígito menos significativo for um número par, se a soma dos seus dígitos for um número ímpar e se, além de ser divisível pela soma de seus dígitos, for um múltiplo de 7. Escreva um programa funcional para determinar se um número n é Juareziano. Solução: - Dividindo o problema em sub-problemas: Um número é Juareziano se o seu dígito menos significativo for um número par, se a soma dos seus dígitos for um número ímpar e se, além de ser divisível pela soma de seus dígitos, for um múltiplo de 7. Ou seja: J: número é Juareziano (juareziano) D: dígito menos significativo (dms) P: for um número par (par) S: soma dos seus dígitos (sd) I: for um número ímpar (impar) , o mesmo que: ¬P V: divisível por (divide) M: múltiplo de 7 (multi7) E: J(n) <=> P.D(n) ∧ ¬P.S(n) ∧ V(n S(n)) ∧ M(n) : - Implementando cada uma das funções: D: dígito menos significativo (dms) dms :: Integer −−−−>>>> Integer dms n = n `mod` 10 P: for um número par (par) par :: Integer −−−−>>>> Bool par n = n `mod` 2 == 0 S: soma dos seus dígitos (sd) sd :: Integer −−−−>>>> Integer sd n = if n < 10 then n else (dms n) + sd (n `div` 10) I: for um número ímpar (impar) impar :: Integer −−−−>>>> Bool impar n = not (par n)

Page 64: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

60

V: divisível por (divide) divide :: Integer −−−−>>>> Integer −−−−>>>> Bool divide n m = m `mod` n == 0 M: múltiplo de 7 (multi7) multi7 :: Integer −−−−>>>> Bool multi7 n = n `mod` 7 == 0 Resolvendo J(n) <=> P.D(n) ∧ ¬P.S(n) ∧ V(n S(n)) ∧ M(n) : juareziano :: Integer −−−−>>>> Bool juareziano n = par (dms n) && not (par (sd n)) && divide n (sd n) && multi7 n Obs.: Pode-se resolver J(n) utilizando composição de funções: juareziano :: Integer −−−−>>>> Bool juareziano n = (par . dms) n && (not . par . sd) n && divide n (sd n) && multi7 n

Exercício 4.2.25. Defina uma expressão em Haskell para listar todos os números perfeitos entre dois inteiros m e n, com m < n. Um número é dito perfeito quando é igual à soma de seus divisores, exceto ele próprio. Por exemplo, 28 é perfeito pois os seus divisores são 1, 2, 4, 7 e 14 e 1 + 2 + 4 + 7 + 14 é igual a 28. Solução:

- Dividindo o problema em sub-problemas:

1°- Criar uma lista com os divisores do número 2°- Somar os elementos da lista (com exceção do último): 2.1- Obter uma sub-lista com todos os elementos de uma lista com exceção do último elemento 2.2- Obter a soma de todos os elementos da sub-lista obtida em 2.1 3°- Verificar se um número é perfeito - Implementando cada uma das funções:

1°- Criar uma lista com os divisores do número (divisores) Dada a lista geradora [1..n], construa uma sub-lista com todos os valores i vindos daquela lista que sejam múltiplos de n (n `mod` i == 0): divisores :: Integer −−−−>>>> [Integer] divisores n = [ i | i <<<<−−−− [1..n] , n `mod` i == 0]

Page 65: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

61

2°- Somar os elementos da lista (com exceção do último) 2.1- Obter uma sub-lista com todos os elementos de uma lista com exceção do último elemento: sublista :: [Integer] −−−−>>>> [Integer] sublista lista = init lista 2.2- Obter a soma de todos os elementos de uma lista (neste caso, da sub-lista obtida em 2.1): soma :: [Integer] −−−−>>>> Integer soma lista = sum lista 3°- Verificar se um número é perfeito, ou seja, comparar o número com a soma dos seus divisores: perfeito :: Integer −−−−>>>> Bool perfeito n = n = = ( soma . sublista . divisores ) n

Page 66: MATEMÁTICA DISCRETA: RESOLUÇÃO DE …¡tica Discreta com...i MATEMÁTICA DISCRETA: RESOLUÇÃO DE PROBLEMAS COM O AUXÍLIO DA COMPUTAÇÃO José Luiz dos Anjos Rosa jrosa@uezo.rj.gov.br

62

Bibliografia: Alencar Filho, Edgard de. Iniciação à lógica matemática. São Paulo: Nobel, 2002. Bezerra, Manoel J. Questões de matemática. São Paulo: Companhia Editora Nacional, 1977. Bird, Richard. Introduction to functional programming using Haskell. 2ª ed. Harlow: Prentice Hall, 1998. Cunha, Celso, Cintra, Luís F. L. Nova gramática do português contemporâneo. Rio de Janeiro: Nova Fronteira, 1985. Fethi, Rabhi, Lapalme, Guy. Algorithms: a functional programming approach. 2ª ed. Harlow: Addison-Wesley, 1999. Gersting, Judith L. Fundamentos matemáticos para a ciência da computação. Rio de Janeiro: LTC, 2001. Hall, Cordelia, O'Donell, John. Discrete mathematics using a computer. Londres: Springer, 2000. Hegenberg, Leônidas. Lógica: o cálculo de predicados. São Paulo: Herder, 1973. Iezzi, Gelson, Murakami, Carlos. Fundamentos de matemática elementar, 1: conjuntos, funções. 7ª ed. São Paulo: Atual, 1993. Scheinerman, Edward R. Matemática Discreta: uma introdução. São Paulo: Pioneira Thomson Learning, 2003. Souza, João Nunes de. Lógica para ciência da computação: fundamentos da linguagem, semântica e sistemas

de dedução. Rio de Janeiro: Campus, 2002. Thompson, Simon. Haskell: the craft of functional programming. 2ª ed. Harlow: Addison-Wesley Longman, 1999.