Você está na página 1de 39

Programao Funcional

Captulo 6

Funes Recursivas

Jos Romildo Malaquias

Departamento de Computao
Universidade Federal de Ouro Preto

2012.1

1/39
1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

2/39
Tpicos

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

3/39
Recursividade

Recursividade uma idia inteligente que desempenha um papel central na


programao funcional e na cincia da computao em geral.
Recursividade o mecanismo de programao no qual uma definio de
funo ou de outro objeto refere-se ao prprio objeto sendo definido.
Assim funo recursiva uma funo que definida em termos de si
mesma.
Recursividade o mecanismo bsico para repeties nas linguagens
funcionais.
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:
no podem ser mais divididos
suas solues so definidas explicitamente

5/39
Definio recursiva

De modo geral, uma definio de funo recursiva dividida em duas partes:


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

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
A primeira equao estabelece que o fatorial de 0 1. Este o caso base.
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.
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.)

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

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)

A primeira equao estabelece que 20 = 1. Este o caso base.


A segunda equao estabelece que 2n = 2 2n1 , 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 prximo do caso base pot2 0 .

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

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

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))
A primeira equao estabelece que quando o multiplicador zero, o produto
tambm zero. Este o caso base.
A segunda equao estabelece que m n = m + m (n 1), sendo n > 0.
Este um caso recursivo.
A terceira equao estabelece que m n = (m (n)), sendo n < 0. Este
outro caso recursivo.

13/39
Exemplo: multiplicao (cont.)

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
A definio recursiva da multiplicao formalisa a idia de que a multiplicao
pode ser reduzida a adies repetidas.

14/39
Exemplo: multiplicao (cont.)

Exerccio 3
Mostre que mul 5 6 = 30.

15/39
Exemplo: sequncia de Fibonacci

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.
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)
A primeira e segunda equaes so os casos base.
A terceira equao o caso recursivo.

16/39
Exemplo: sequncia de Fibonacci (cont.)

Neste caso temos recurso mltipla, pois a funo sendo definida usada
mais de uma vez em sua prpria definio.
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

17/39
Exemplo: sequncia de Fibonacci (cont.)

Exerccio 4
Mostre que fib 6 = 8.

18/39
Tpicos

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

19/39
Recursividade mtua

Recursividade mtua ocorre quando duas ou mais funes so definidas


em termos uma da outra.

20/39
Exemplo: par e mpar

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.

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

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)
Zero par, mas no mpar.
Um nmero positivo par se seu antecessor mpar.
Um nmero positivo mpar se seu antecessor par.
Um nmero negativo par (ou mpar) se o seu oposto for par (ou mpar).

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

Aplicando as funo par e mpar:


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

23/39
Tpicos

1 Funes recursivas

2 Recursividade mtua

3 Recursividade de cauda

24/39
Recursividade de cauda

Uma funo recursiva apresenta recursividade de cauda se o resultado final


da chamada recursiva o resultado final da prpria funo.
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.

25/39
Recursividade de cauda (cont.)

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.

26/39
Recursividade de cauda (cont.)

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.

27/39
Recursividade de cauda (cont.)

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.

28/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.

29/39
Otimizao de chamada de cauda

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

30/39
Otimizao de chamada de cauda (cont.)
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.
Em tais situaes o programa no precisa voltar para a funo que chama
quando a funo chamada termina.
Portanto, aps a chamada de cauda, o programa no precisa manter
qualquer informao sobre a funo chamadora na pilha.
Algumas implementaes de linguagem tiram proveito desse fato e na
verdade no utilizam qualquer espao extra de pilha quando fazem uma
chamada de cauda.
Esta tcnica chamada de eliminao da cauda, otimizao de chamada
de cauda ou ainda otimizao de chamada recursiva.
A otimizao de chamada de cauda permite que funes com
recursividade de cauda recorram indefinidamente sem estourar a pilha.
Muitas linguagens funcionais no possuem estruturas de repetio e usam
funes recursivas para fazer repeties.
Nestes casos a otimizao de chamada de cauda fundamental para uma
boa eficincia dos programas. 31/39
Vantagens de usar recursividade

Muitas funes podem ser naturalmente definidas em termos de si mesmas.


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:

a
se b = 0,
mdc(a, b) = mdc(b, a mod b) se b > 0,

mdc(a, b) 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