Programação Funcional. Aula 5. Funções Recursivas. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2011.



Documentos relacionados
Aula prática 5. Funções Recursivas

CONCEITOS BÁSICOS PARA A CONSTRUÇÃO DE ALGORITMOS PARA COMPUTADORES. Isac Aguiar isacaguiar.com.br isacaguiar@gmail.com

Regras Métodos Identificadores Variáveis Constantes Tipos de dados Comandos de atribuição Operadores aritméticos, relacionais e lógicos

ALGORITMOS MEMÓRIA, VARIÁVEIS E CONSTANTES, OPERADORES Prof. Angelo Augusto Frozza, M.Sc. frozza@ifc-camboriu.edu.br

Programação Funcional. Capítulo 1. Introdução. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2013.

Aula 4 Estatística Conceitos básicos

Material Teórico - Módulo de Divisibilidade. MDC e MMC - Parte 1. Sexto Ano. Prof. Angelo Papa Neto

Estruturas de Repetição

2ª Lista de Exercícios

Algoritmos e Estruturas de Dados I 01/2013. Estruturas Condicionais e de Repetição (parte 2) Pedro O.S. Vaz de Melo

Notas de Cálculo Numérico

Programas C com Repetição

Algoritmos Estruturas Seqüenciais. José Gustavo de Souza Paiva

Programação: Estruturas de seleção

Capítulo SETE Números em Ponto Fixo e Ponto Flutuante

Definição. de solução de um problema passo-a-passo. Representa a lógica l. passo.

Álgebra. SeM MiSTéRio

Fundamentos Tecnológicos

CURSO BÁSICO DE PROGRAMAÇÃO AULA 7

Programação científica C++

AGRUPAMENTO DE ESCOLAS DR. VIEIRA DE CARVALHO

Recursividade. Aula 9

Comandos de repetição while

Linguagem e Técnicas de Programação I Tipos de dados, variáveis e constantes. Prof. MSc. Hugo Souza Material desenvolvido por: Profa.

LÓGICA DE PROGRAMAÇÃO. Vitor Valerio de Souza Campos

Universidade Federal de São Carlos Departamento de Matemática Curso de Cálculo Numérico - Turma E Resolução da Primeira Prova - 16/04/2008

3º Ano do Ensino Médio. Aula nº10 Prof. Daniel Szente

Programação Funcional. Aula 4. Definindo Funções. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2011.

Conceitos básicos da linguagem C

ALGORITMOS E FLUXOGRAMAS

Figure 2 - Nós folhas de uma árvore binária representando caracteres ASCII

SOCIEDADE BRASILEIRA DE MATEMÁTICA MESTRADO PROFISSIONAL EM REDE NACIONAL PROFMAT

Avaliação 1 - MA Gabarito

INTRODUÇÃO À LINGUAGEM C++

Computação II Orientação a Objetos

JavaScript (ou JScript)

Introdução à Engenharia de Computação

Capítulo 8. CICLOS. Tabela 8.1 Programa8a.f90.

Divisão e Conquista. Túlio Toffolo Marco Antônio Carvalho marco.opt@gmail.com. BCC402 Aula 08 Algoritmos e Programação Avançada

Exercícios de Java Aula 19

Linguagem de Programação

REPRESENTAÇÃO DE DADOS EM SISTEMAS DE COMPUTAÇÃO AULA 03 Arquitetura de Computadores Gil Eduardo de Andrade

A estrutura de repetição em um algoritmo consiste na execução de um trecho do mesmo levando em consideração certas condições imposta pelo algoritmo.

Lista de Exercícios 3 Estruturas de Controle Profa Susana M Iglesias

P r o g r a m a ç ã o d e C o m p u t a d o r e s 1 o S e m P r o f. A n d r é A m a r a n t e L u i z L A B 5 tag %2d while printf PE1:

José Romildo Malaquias

Principais códigos utilizados. Codificação. Código binário puro. Codificação binária. Codificação Binária. Código Binário puro e suas variantes

Aula 2 - Cálculo Numérico

UNIDADE 6 - PROGRAMAÇÃO MODULAR

AV1 - MA (b) Se o comprador preferir efetuar o pagamento à vista, qual deverá ser o valor desse pagamento único? 1 1, , , 980

Um jogo de preencher casas

Estrutura de Dados Básica

Universidade Federal do Paraná. Setor de Ciências Exatas. Departamento de Matemática

Linguagem algorítmica: Portugol

Estrutura de Dados Básica

Python Funções. Introdução à Programação SI1

por séries de potências

Processos Estocásticos

Aula 4 Conceitos Básicos de Estatística. Aula 4 Conceitos básicos de estatística

Construção dos números racionais, Números fracionários e operações com frações

Introdução a Computação

7. Estrutura de Decisão

Programação: Tipos, Variáveis e Expressões

Programação Funcional. Capítulo 13. Mônadas. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2013.

Instituto Superior Técnico Departamento de Matemática Última actualização: 11/Dez/2003 ÁLGEBRA LINEAR A

b) Sinais diferentes o resultado será negativo: Ex.: (+2 ) (-5) = - 10 (-20) : (+4) = - 5 (+8 ) (-6) = - 48 (+12) : (-2) = - 6

A declaração de uma variável vel define o seu tipo. O tipo do dado define como ele será: Armazenado na memória. Manipulado pela ULA.

TEXTO DE REVISÃO: Uso da calculadora científica e potências de 10.

- Aulas 57, 58, 59 e 60 - Técnicas de programação. Funções

Departamento de Informática

Técnicas de Programação I

Material Teórico - Aplicações das Técnicas Desenvolvidas. Exercícios e Tópicos Relacionados a Combinatória. Segundo Ano do Ensino Médio

Busca em Memória. Secundária

Um estudo sobre funções contínuas que não são diferenciáveis em nenhum ponto

Especificação do Trabalho Prático

Programação Orientada a Objeto

Sumário 1.OPERAÇÕES COM NÚMEROS RACIONAIS Adição e Subtração de Números Racionais Multiplicação e Divisão de Números Racionais...

36ª Olimpíada Brasileira de Matemática GABARITO Segunda Fase

Por que o quadrado de terminados em 5 e ta o fa cil? Ex.: 15²=225, 75²=5625,...

Faculdade de Computação

Figura 5.1.Modelo não linear de um neurônio j da camada k+1. Fonte: HAYKIN, 2001

Polos Olímpicos de Treinamento. Aula 2. Curso de Teoria dos Números - Nível 2. Divisibilidade II. Prof. Samuel Feitosa

Universidade Federal de Rondônia Técnicas de Desenvolvimento de Programas Lista 4

Organização e Arquitetura de Computadores I

DESENVOLVIMENTO DE SOFTWARE

Cotagem de dimensões básicas

2 Ferramentas Utilizadas

Planilha Eletrônica - Excel

Introdução. A Informação e sua Representação (Parte II) Universidade Federal de Campina Grande. Unidade Acadêmica de Sistemas e Computação

Exercícios Teóricos Resolvidos

Programa Olímpico de Treinamento. Aula 9. Curso de Combinatória - Nível 2. Tabuleiros. Prof. Bruno Holanda

CAPÍTULO 1- OPERAÇÕES COM NÚMEROS INTEIROS Indicadores de aprendizagem Verifica se sabes: Identificar o conjunto dos números inteiros.

Algoritmos e Programação

Cálculo Numérico Aula 1: Computação numérica. Tipos de Erros. Aritmética de ponto flutuante

Teoria dos Números. A Teoria dos Números é a área da matemática que lida com os números inteiros, isto é, com o conjunto

QUANTIFICADORES. Existem frases declarativas que não há como decidir se são verdadeiras ou falsas. Por exemplo: (a) Ele é um campeão da Fórmula 1.

Computador E/S, Memória, Barramento do sistema e CPU Onde a CPU Registradores, ULA, Interconexão interna da CPU e Unidade de controle.

INSTITUTO TECNOLÓGICO

Unidade 5: Sistemas de Representação

Introdução. A Informação e sua Representação (Parte III) Universidade Federal de Campina Grande Departamento de Sistemas e Computação

Transcrição:

Programação Funcional Aula 5 Funções Recursivas José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto 2011.2 1/39

1 Funções recursivas 2 Recursividade mútua 3 Recursividade de cauda 2/39

Layout 1 Funções recursivas 2 Recursividade mútua 3 Recursividade de cauda 3/39

Recursividade Recursividade é uma idéia inteligente que desempenha um papel central na programação funcional e na ciência da computação em geral. Recursividade é o mecanismo de programação no qual uma definição de função ou de outro objeto refere-se ao próprio objeto sendo definido. Assim função recursiva é uma função que é definida em termos de si mesma. Recursividade é o mecanismo básico para repetições nas linguagens funcionais. São sinônimos: recursividade, recursão, recorrência. 4/39

Estratégia recursiva Estratégia para a definição recursiva de uma função: 1 dividir o problema em problemas menores do mesmo tipo 2 resolver os problemas menores (dividindo-os em problemas ainda menores, se necessário) 3 combinar as soluções dos problemas menores para formar a solução final Ao dividir o problema sucessivamente em problemas menores eventualmente os casos simples são alcançados: não podem ser mais divididos suas soluções são definidas explicitamente 5/39

Definição recursiva De modo geral, uma definição de função recursiva é dividida em duas partes: Há um ou mais casos base que dizem o que fazer em situações simples, onde não é necessária nenhuma recursão. Nestes casos a resposta pode ser dada de imediato, sem chamar recursivamente a função sendo definida. Isso garante que a recursão eventualmente possa parar. Há um ou mais casos recursivos que são mais gerais, e definem a função em termos de uma chamada mais simples a si mesma. 6/39

Exemplo: fatorial A função que calcula o fatorial de um número natural pode ser definida recursivamente como segue: fatorial :: Integer -> Integer fatorial n n == 0 = 1 n > 0 = fatorial (n-1) * n A primeira equação estabelece que o fatorial de 0 é 1. Este é o caso base. A segunda equação estabelece que o fatorial de um número positivo é o produto deste número e do fatorial do seu antecessor. Este é o caso recursivo. Observe que no caso recursivo o subproblema fatorial (n-1) é mais simples que o problema original fatorial n e está mais próximo do caso base fatorial 0. 7/39

Exemplo: fatorial (cont.) Aplicando a função fatorial: fatorial 6 fatorial 5 * 6 (fatorial 4 * 5) * 6 ((fatorial 3 * 4) * 5) * 6 (((fatorial 2 * 3) * 4) * 5) * 6 ((((fatorial 1 * 2) * 3) * 4) * 5) * 6 (((((fatorial 0 * 1) * 2) * 3) * 4) * 5) * 6 (((((1 * 1) * 2) * 3) * 4) * 5) * 6 ((((1 * 2) * 3) * 4) * 5) * 6 (((2 * 3) * 4) * 5) * 6 ((6 * 4) * 5) * 6 (24 * 5) * 6 120 * 6 720 8/39

Exemplo: fatorial (cont.) Exercício 1 Digite a função fatorial em um arquivo fonte Haskell e carregue-o no ambiente interativo de Haskell. a) Mostre que fatorial 7 = 5040. b) Determine o valor da expressão fatorial 7 usando o ambiente interativo. c) Determine o valor da expressão fatorial 1000 usando o ambiente interativo. Se você tiver uma calculadora científica, verifique o resultado na calculadora. d) Qual é o valor esperado para a expressão div (fatorial 1000) (fatorial 999)? Determine o valor desta expressão usando o ambiente interativo. e) O que acontece ao calcular o valor da expressão fatorial (-2)? 9/39

Exemplo: potências de 2 A função que calcula a potência de 2 para números naturais pode ser definida recursivamente como segue: pot2 :: Integer -> Integer pot2 n n == 0 = 1 n > 0 = 2 * pot2 (n-1) A primeira equação estabelece que 2 0 = 1. Este é o caso base. A segunda equação estabelece que 2 n = 2 2 n 1, sendo n > 0. Este é o caso recursivo. Observe que no caso recursivo o subproblema pot2 (n-1) é mais simples que o problema original pot2 n e está mais próximo do caso base pot2 0. 10/39

Exemplo: potências de 2 (cont.) Aplicando a função potência de 2: pot2 4 2 * pot2 3 2 * (2 * pot2 2) 2 * (2 * (2 * pot2 1)) 2 * (2 * (2 * (2 * pot2 0))) 2 * (2 * (2 * (2 * 1))) 2 * (2 * (2 * 2)) 2 * (2 * 4) 2 * 8 16 11/39

Exemplo: potências de 2 (cont.) Exercício 2 Considere a seguinte definição para a função potência de 2: pot2 :: Integer -> Integer pot2 n n == 0 = 1 otherwise = 2 * pot2 (n-1) O que acontece ao calcular o valor da expressão pot2 (-5)? 12/39

Exemplo: multiplicação A multiplicação de inteiros está disponível na biblioteca como uma operação primitiva por questões de eficiência. Porém ela pode ser definida usando recursividade em um de seus argumentos: mul :: Int -> Int -> Int mul m n n == 0 = 0 n > 0 = m + mul m (n-1) otherwise = - (mul m (-n)) A primeira equação estabelece que quando o multiplicador é zero, o produto também é zero. Este é o caso base. A segunda equação estabelece que m n = m + m (n 1), sendo n > 0. Este é um caso recursivo. A terceira equação estabelece que m n = (m ( n)), sendo n < 0. Este é outro caso recursivo. 13/39

Exemplo: multiplicação (cont.) Aplicando a função multiplicação: mul 7 (-3) - (mul 7 3) - (7 + mul 7 2) - (7 + (7 + mul 7 1)) - (7 + (7 + (7 + mul 7 0))) - (7 + (7 + (7 + 0))) - (7 + (7 + 7)) - (7 + 14) - 21-21 A definição recursiva da multiplicação formalisa a idéia de que a multiplicação pode ser reduzida a adições repetidas. Exercício 3 Mostre que mul 5 6 = 30. 14/39

Exemplo: sequência de Fibonacci Na seqüência de Fibonacci 0,1,1,2,3,5,8,13,... os dois primeiros elementos são 0 e 1, e cada elemento subseqüente é dado pela soma dos dois elementos que o precedem na seqüência. A função a seguir calcula o n-ésimo número de Fibonnaci, para n 0: fib :: Int -> Int fib n n == 0 = 0 n == 1 = 1 n > 1 = fib (n-2) + fib (n-1) A primeira e segunda equações são os casos base. A terceira equação é o caso recursivo. 15/39

Exemplo: sequência de Fibonacci (cont.) Neste caso temos recursão múltipla, pois a função sendo definida é usada mais de uma vez em sua própria definição. Aplicando a função de fibonacci: fib 5 fib 3 + fib 4 (fib 1 + fib 2) + (fib 2 + fib 3) (1 + (fib 0 + fib 1)) + ((fib 0 + fib 1) + (fib 1 + fib 2)) (1 + (0 + 1)) + ((0 + 1) + (1 + (fib 0 + fib 1))) (1 + 1) + (1 + (1 + (0 + 1))) 2 + (1 + (1 + 1)) 2 + (1 + 2) 2 + 3 5 16/39

Exemplo: sequência de Fibonacci (cont.) Exercício 4 Mostre que fib 6 = 8. 17/39

Layout 1 Funções recursivas 2 Recursividade mútua 3 Recursividade de cauda 18/39

Recursividade mútua Recursividade mútua ocorre quando duas ou mais funções são definidas em termos uma da outra. 19/39

Exemplo: par e ímpar As funções da biblioteca even e odd, que determinam se um número é par ou ímpar, respectivamente, geralmente são definidas usando o resto da divisão por 2. 20/39

Exemplo: par e ímpar (cont.) No entanto elas também podem ser definidas usando recursividade mútua: par :: Int -> Bool par n n == 0 = True n > 0 = impar (n-1) otherwise = par (-n) impar :: Int -> Bool impar n n == 0 = False n > 0 = par (n-1) otherwise = impar (-n) Zero é par, mas não é ímpar. Um número positivo é par se seu antecessor é ímpar. Um número positivo é ímpar se seu antecessor é par. Um número negativo é par (ou ímpar) se o seu oposto for par (ou ímpar). 21/39

Exemplo: par e ímpar (cont.) Aplicando as função par e ímpar: par (-5) par 5 impar 4 par 3 impar 2 par 1 impar 0 False 22/39

Layout 1 Funções recursivas 2 Recursividade mútua 3 Recursividade de cauda 23/39

Recursividade de cauda Uma função recursiva apresenta recursividade de cauda se o resultado final da chamada recursiva é o resultado final da própria função. Se o resultado da chamada recursiva deve ser processado de alguma maneira para produzir o resultado final, então a função não apresenta recursividade de cauda. 24/39

Recursividade de cauda (cont.) Exemplo: A função recursiva a seguir não apresenta recursividade de cauda: fatorial :: Integer -> Integer fatorial n n == 0 = 1 n > 0 = fatorial (n-1) * n No caso recursivo, o resultado da chamada recursiva fatorial (n-1) é multiplicado por n para produzir o resultado final. 25/39

Recursividade de cauda (cont.) Exemplo: A função recursiva a seguir não apresenta recursividade de cauda: par :: Integer -> Bool par n n == 0 = True n > 0 = not (par (n-1)) No caso recursivo, a função not é aplicada ao resultado da chamada recursiva par (n-1) para produzir o resultado final. 26/39

Recursividade de cauda (cont.) Exemplo: A função recursiva potencia2 a seguir apresenta recursividade de cauda: potencia2 :: Integer -> Integer potencia2 n = potencia2 n 1 potencia2 :: Integer -> Integer -> Integer potencia2 n y n == 0 = y n > 0 = potencia2 (n-1) (2*y) No caso recursivo, o resultado da chamada recursiva potencia2 (n-1) (2*y) é o resultado final. 27/39

Recursividade de cauda (cont.) Exercício 5 Mostre que potencia2 5 = 32. Exercício 6 Faça uma definição recursiva da função par usando recursividade de cauda. 28/39

Otimização de chamada de cauda Em muitas implementações de linguagens de programação uma chamada de função usa um espaço de memória (quadro, frame ou registro de ativação) em uma área da memória (pilha ou stack) onde são armazenadas informações importantes, como: argumentos da função variáveis locais variáveis temporárias endereço de retorno da função 29/39

Otimização de chamada de cauda (cont.) Uma chamada de cauda acontece quando uma função chama outra função como sua última ação, não tendo mais nada a fazer. O resultado final da função é dado pelo resultado da chamada de cauda. Em tais situações o programa não precisa voltar para a função que chama quando a função chamada termina. Portanto, após a chamada de cauda, o programa não precisa manter qualquer informação sobre a função chamadora na pilha. Algumas implementações de linguagem tiram proveito desse fato e na verdade não utilizam qualquer espaço extra de pilha quando fazem uma chamada de cauda. Esta técnica é chamada de eliminação da cauda, otimização de chamada de cauda ou ainda otimização de chamada recursiva. 30/39

Otimização de chamada de cauda (cont.) A otimização de chamada de cauda permite que funções com recursividade de cauda recorram indefinidamente sem estourar a pilha. Muitas linguagens funcionais não possuem estruturas de repetição e usam funções recursivas para fazer repetições. Nestes casos a otimização de chamada de cauda é fundamental para uma boa eficiência dos programas. 31/39

Vantagens de usar recursividade Muitas funções podem ser naturalmente definidas em termos de si mesmas. Propriedades de funções definidas usando recursão podem ser provadas usando indução, uma técnica matemática simples, mas poderosa. 32/39

Exercícios Exercício 7 O fatorial duplo de um número natural n é o produto de todos os números de 1 (ou 2) até n, contados de 2 em 2. Por exemplo, o fatorial duplo de 8 é 8 6 4 2 = 384, e o fatorial duplo de 7 é 7 5 3 1 = 105. Defina uma função para calcular o fatorial duplo usando recursividade. Exercício 8 Defina uma função recursiva que recebe dois números naturais m e n e retorna o produto de todos os números no intervalo [m,n]: m (m + 1) (n 1) n 33/39

Exercícios (cont.) Exercício 9 Usando a função definida no exercício 8, escreva uma definição não recursiva para calcular o fatorial de um número natural. Exercício 10 Defina uma função recursiva para calcular a soma de dois números inteiros, sem usar os operadores + e -. Utilize as funções succ e pred da biblioteca, que calculam respectivamente o sucessor e o antecessor de um valor. Exercício 11 Defina uma função recursiva para calcular a potência de um número, considerando que o expoente é um número natural. Utilize o método das multiplicações sucessivas. 34/39

Exercícios (cont.) Exercício 12 A raiz quadrada inteira de um número inteiro positivo n é o maior número inteiro cujo quadrado é menor ou igal a n. Por exemplo, a raiz quadrada inteira de 15 é 3, e a raiz quadrada inteira de 16 é 4. Defina uma função recursiva para calcular a raiz quadrada inteira. Exercício 13 Defina duas funções recursivas que calculam o quociente e o resto da divisão inteira de dois números inteiros usando subtrações sucessivas. 35/39

Exercícios (cont.) Exercício 14 Defina uma função recursiva para calcular o máximo divisor comum de dois números inteiros não negativos a e b, usando o algoritmo de Euclides: mdc(a, b) se b < 0, mdc(a,b) = a se b = 0, mdc(a,b mod a) se b > 0 Nota: o prelúdio já tem a função gcd :: Integral a => a -> a -> a que calcula o máximo divisor comum de dois números integrais. 36/39

Exercícios (cont.) Exercício 15 Faça uma definição recursiva para uma função maior :: (Integer -> Integer) -> Integer -> Integer que recebe uma função f e um número inteiro não negativo n, e retorna o maior dos valores f 0, f 1, f 2,..., f (n-1), f n Por exemplo, considerando a função g :: Integer -> Integer g x even x = 2*x^2-3*x + 1 otherwise = div (x^3) 2 temos maior g 10 364 37/39

Exercícios (cont.) Exercício 16 Considere a seguinte função para calcular o fatorial de um número: fat n = fat n 1 where fat n x n == 0 = x n > 0 = fat (n-1) (n*x) a) Mostre que fat 6 = 720. b) Compare o cálculo de fat 6 com o cálculo de fatorial 6 apresentado anteriormente. Qual versão da função fatorial é mais eficiente: fatorial ou fat? Explique. Exercício 17 Defina uma função com recursividade de cauda para calcular o n-ésimo (n 0) número de Fibonacci. 38/39

Fim 39/39