Você está na página 1de 39

Programao Funcional

Aula 5
Funes Recursivas

Jos Romildo Malaquias

Departamento de Computao
Universidade Federal de Ouro Preto

2011.2
1/39
1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

2/39
Layout

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

3/39
Recursividade

I Recursividade uma idia inteligente que desempenha um


papel central na programao funcional e na cincia da
computao em geral.
I Recursividade o mecanismo de programao no qual uma
definio de funo ou de outro objeto refere-se ao prprio objeto
sendo definido.
I Assim funo recursiva uma funo que definida em termos
de si mesma.
I Recursividade o mecanismo bsico para repeties nas
linguagens funcionais.
I So sinnimos: recursividade, recurso, recorrncia.

4/39
Estratgia recursiva

Estratgia para a definio recursiva de uma funo:


1 dividir o problema em problemas menores do mesmo tipo
2 resolver os problemas menores (dividindo-os em problemas
ainda menores, se necessrio)
3 combinar as solues dos problemas menores para formar a
soluo final
Ao dividir o problema sucessivamente em problemas menores
eventualmente os casos simples so alcanados:
I no podem ser mais divididos
I suas solues so definidas explicitamente

5/39
Definio recursiva

De modo geral, uma definio de funo recursiva dividida em


duas partes:
I H um ou mais casos base que dizem o que fazer em
situaes simples, onde no necessria nenhuma recurso.
Nestes casos a resposta pode ser dada de imediato, sem
chamar recursivamente a funo sendo definida.
Isso garante que a recurso eventualmente possa parar.
I H um ou mais casos recursivos que so mais gerais, e
definem a funo em termos de uma chamada mais simples a si
mesma.

6/39
Exemplo: fatorial

I A funo que calcula o fatorial de um nmero natural pode ser


definida recursivamente como segue:
fatorial :: Integer -> Integer
fatorial n
| n == 0 = 1
| n > 0 = fatorial (n-1) * n
I A primeira equao estabelece que o fatorial de 0 1. Este o
caso base.
I A segunda equao estabelece que o fatorial de um nmero
positivo o produto deste nmero e do fatorial do seu
antecessor. Este o caso recursivo.
I Observe que no caso recursivo o subproblema
fatorial (n-1) mais simples que o problema original
fatorial n e est mais prximo do caso base fatorial 0 .
7/39
Exemplo: fatorial (cont.)

I Aplicando a funo 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.)

Exerccio 1
Digite a funo 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 expresso fatorial 7 usando o ambiente
interativo.
c) Determine o valor da expresso fatorial 1000 usando o
ambiente interativo. Se voc tiver uma calculadora cientfica,
verifique o resultado na calculadora.
d) Qual o valor esperado para a expresso
div (fatorial 1000) (fatorial 999)? Determine o valor
desta expresso usando o ambiente interativo.
e) O que acontece ao calcular o valor da expresso fatorial (-2)?

9/39
Exemplo: potncias de 2

I A funo que calcula a potncia de 2 para nmeros naturais


pode ser definida recursivamente como segue:
pot2 :: Integer -> Integer
pot2 n
| n == 0 = 1
| n > 0 = 2 * pot2 (n-1)
I A primeira equao estabelece que 20 = 1. Este o caso base.
I A segunda equao estabelece que 2n = 2 2n1 , sendo n > 0.
Este o caso recursivo.
I Observe que no caso recursivo o subproblema pot2 (n-1)
mais simples que o problema original pot2 n e est mais
prximo do caso base pot2 0 .

10/39
Exemplo: potncias de 2 (cont.)

I Aplicando a funo potncia 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: potncias de 2 (cont.)

Exerccio 2
Considere a seguinte definio para a funo potncia de 2:
pot2 :: Integer -> Integer
pot2 n
| n == 0 = 1
| otherwise = 2 * pot2 (n-1)
O que acontece ao calcular o valor da expresso pot2 (-5)?

12/39
Exemplo: multiplicao

I A multiplicao de inteiros est disponvel na biblioteca como


uma operao primitiva por questes de eficincia. Porm 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))
I A primeira equao estabelece que quando o multiplicador
zero, o produto tambm zero. Este o caso base.
I A segunda equao estabelece que m n = m + m (n 1),
sendo n > 0. Este um caso recursivo.
I A terceira equao estabelece que m n = (m (n)), sendo
n < 0. Este outro caso recursivo.
13/39
Exemplo: multiplicao (cont.)
I Aplicando a funo multiplicao:
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
I A definio recursiva da multiplicao formalisa a idia de que a
multiplicao pode ser reduzida a adies repetidas.

Exerccio 3
Mostre que mul 5 6 = 30.
14/39
Exemplo: sequncia de Fibonacci

I Na seqncia de Fibonacci

0, 1, 1, 2, 3, 5, 8, 13, . . .

os dois primeiros elementos so 0 e 1, e cada elemento


subseqente dado pela soma dos dois elementos que o
precedem na seqncia.
I A funo a seguir calcula o n-simo nmero de Fibonnaci, para
n 0:
fib :: Int -> Int
fib n
| n == 0 = 0
| n == 1 = 1
| n > 1 = fib (n-2) + fib (n-1)
I A primeira e segunda equaes so os casos base.
I A terceira equao o caso recursivo. 15/39
Exemplo: sequncia de Fibonacci (cont.)

I Neste caso temos recurso mltipla, pois a funo sendo


definida usada mais de uma vez em sua prpria definio.
I Aplicando a funo 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: sequncia de Fibonacci (cont.)

Exerccio 4
Mostre que fib 6 = 8.

17/39
Layout

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

18/39
Recursividade mtua

I Recursividade mtua ocorre quando duas ou mais funes so


definidas em termos uma da outra.

19/39
Exemplo: par e mpar

I As funes da biblioteca even e odd, que determinam se um


nmero par ou mpar, respectivamente, geralmente so
definidas usando o resto da diviso por 2.

20/39
Exemplo: par e mpar (cont.)

I No entanto elas tambm podem ser definidas usando


recursividade mtua:
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)
I Zero par, mas no mpar.
I Um nmero positivo par se seu antecessor mpar.
I Um nmero positivo mpar se seu antecessor par.
I Um nmero negativo par (ou mpar) se o seu oposto for par (ou
mpar).
21/39
Exemplo: par e mpar (cont.)

I Aplicando as funo par e mpar:


par (-5)
par 5
impar 4
par 3
impar 2
par 1
impar 0
False

22/39
Layout

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

23/39
Recursividade de cauda

I Uma funo recursiva apresenta recursividade de cauda se o


resultado final da chamada recursiva o resultado final da
prpria funo.
I Se o resultado da chamada recursiva deve ser processado de
alguma maneira para produzir o resultado final, ento a funo
no apresenta recursividade de cauda.

24/39
Recursividade de cauda (cont.)

I Exemplo:
A funo recursiva a seguir no 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.)

I Exemplo:
A funo recursiva a seguir no apresenta recursividade de
cauda:
par :: Integer -> Bool
par n
| n == 0 = True
| n > 0 = not (par (n-1))
No caso recursivo, a funo not aplicada ao resultado da
chamada recursiva par (n-1) para produzir o resultado final.

26/39
Recursividade de cauda (cont.)

I Exemplo:
A funo 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.)

Exerccio 5
Mostre que potencia2 5 = 32.

Exerccio 6
Faa uma definio recursiva da funo par usando recursividade de
cauda.

28/39
Otimizao de chamada de cauda

I Em muitas implementaes de linguagens de programao uma


chamada de funo usa um espao de memria (quadro, frame
ou registro de ativao) em uma rea da memria (pilha ou
stack) onde so armazenadas informaes importantes, como:
argumentos da funo
variveis locais
variveis temporrias
endereo de retorno da funo

29/39
Otimizao de chamada de cauda (cont.)

I Uma chamada de cauda acontece quando uma funo chama


outra funo como sua ltima ao, no tendo mais nada a fazer.
O resultado final da funo dado pelo resultado da chamada de
cauda.
I Em tais situaes o programa no precisa voltar para a funo
que chama quando a funo chamada termina.
I Portanto, aps a chamada de cauda, o programa no precisa
manter qualquer informao sobre a funo chamadora na pilha.
I Algumas implementaes de linguagem tiram proveito desse fato
e na verdade no utilizam qualquer espao extra de pilha quando
fazem uma chamada de cauda.
I Esta tcnica chamada de eliminao da cauda, otimizao
de chamada de cauda ou ainda otimizao de chamada
recursiva.

30/39
Otimizao de chamada de cauda (cont.)

I A otimizao de chamada de cauda permite que funes com


recursividade de cauda recorram indefinidamente sem estourar a
pilha.
I Muitas linguagens funcionais no possuem estruturas de
repetio e usam funes recursivas para fazer repeties.
I Nestes casos a otimizao de chamada de cauda fundamental
para uma boa eficincia dos programas.

31/39
Vantagens de usar recursividade

I Muitas funes podem ser naturalmente definidas em termos de


si mesmas.
I Propriedades de funes definidas usando recurso podem ser
provadas usando induo, uma tcnica matemtica simples,
mas poderosa.

32/39
Exerccios

Exerccio 7
O fatorial duplo de um nmero natural n o produto de todos os
nmeros 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 funo para calcular o fatorial duplo usando recursividade.

Exerccio 8
Defina uma funo recursiva que recebe dois nmeros naturais m e n
e retorna o produto de todos os nmeros no intervalo [m, n]:

m (m + 1) (n 1) n

33/39
Exerccios (cont.)

Exerccio 9
Usando a funo definida no exerccio 8, escreva uma definio no
recursiva para calcular o fatorial de um nmero natural.

Exerccio 10
Defina uma funo recursiva para calcular a soma de dois nmeros
inteiros, sem usar os operadores + e -. Utilize as funes succ e pred
da biblioteca, que calculam respectivamente o sucessor e o
antecessor de um valor.

Exerccio 11
Defina uma funo recursiva para calcular a potncia de um nmero,
considerando que o expoente um nmero natural. Utilize o mtodo
das multiplicaes sucessivas.

34/39
Exerccios (cont.)

Exerccio 12
A raiz quadrada inteira de um nmero inteiro positivo n o maior
nmero 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 funo recursiva para calcular a raiz quadrada inteira.

Exerccio 13
Defina duas funes recursivas que calculam o quociente e o resto da
diviso inteira de dois nmeros inteiros usando subtraes
sucessivas.

35/39
Exerccios (cont.)

Exerccio 14
Defina uma funo recursiva para calcular o mximo divisor comum
de dois nmeros inteiros no 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 preldio j tem a funo


gcd :: Integral a => a -> a -> a que calcula o mximo
divisor comum de dois nmeros integrais.

36/39
Exerccios (cont.)

Exerccio 15
Faa uma definio recursiva para uma funo
maior :: (Integer -> Integer) -> Integer -> Integer
que recebe uma funo f e um nmero inteiro no negativo n, e
retorna o maior dos valores

f 0, f 1, f 2, . . . , f (n-1), f n

Por exemplo, considerando a funo


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
Exerccios (cont.)

Exerccio 16
Considere a seguinte funo para calcular o fatorial de um nmero:
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 clculo de fat 6 com o clculo de fatorial 6
apresentado anteriormente. Qual verso da funo fatorial mais
eficiente: fatorial ou fat? Explique.

Exerccio 17
Defina uma funo com recursividade de cauda para calcular o
n-simo (n 0) nmero de Fibonacci.
38/39
Fim

39/39

Você também pode gostar