Programação Funcional

Propaganda
Programação Funcional
Lucília Camarão de Figueiredo
Universidade Federal de Ouro Preto
[email protected]
Aula 06: Funções Recursivas
1
I NTRODUÇÃO
Funções odem ser definidas em termos de outras funções:
fact :: Int → Int
fact n = product [1..n]
mapea um inteiro n no produto dos inteiros compreendidos entre 1 e n.
Expressões são avaliadas passo a passo por meio da aplicação
de funções a seus argumentos. Por exemplo:
fact 3
B product [1..3]
B product [1,2,3]
B 1*2*3
B 6
I NTRODUÇÃO
2
D EFINIÇÕES
RECURSIVAS
Funções podem ser também definidas em termos delas próprias:
fact :: Int → Int
fact 0 = 1
fact n = n * fact (n-1)
mapea 0 em 1 e qualquer outro valor inteiro positivo n no produto desse
valor pelo fatorial do antecessor de n.
Por exemplo:
fact 3
B 3 * fact
B 3 * (2 *
B 3 * (2 *
B 3 * (2 *
B 6
D EFINIÇÕES
RECURSIVAS
2
fact 1)
(1 * fact 0))
(1 * 1))
3
P ORQUE
RECURSÃO É ÚTIL ?
• Na prática, muitas funções podem ser naturalmente definidas
em termos de si próprias.
• Propriedades de funções recursivas podem ser provadas por
meio de um princípio matemático simples e poderoso: o
princípio de indução.
Exemplo:
rangeSum :: Int → Int → Int
rangeSum m n
| n < m = 0
| n == m = m
| n > m = n + rangeSum m (n-1)
Prove que, para quaisquer inteiros m e n tais que n ≥ m,
rangeSum m n = (n(n + 1) − m(m − 1))/2
P ORQUE
RECURSÃO É ÚTIL ?
4
R ECURSÃO
SOBRE LISTAS
product :: Num a => [a] → a
product []
= 1
product (x:xs) = x * product xs
Exemplo:
product [1..3]
B product [1,2,3]
B 1 * product [2,3]
B 1 * (2 * product [3])
B 1 * (2 * (3 * product []))
B 1 * (2 * (3 * 1))
B 6
R ECURSÃO
SOBRE LISTAS
5
E XERCÍCIOS
Defina uma função para solução de cada problema:
1. Determinar a soma dos valores de uma lista de números.
2. Dobrar todos os valores de uma lista de números inteiros.
3. Inverter uma lista de valores.
4. Determinar se um dado valor ocorre em uma lista de valores.
5. Determinar o número de ocorrências de um valor em uma lista.
6. Dadas duas listas, retornar a lista cujos elementos são pares
de valores em posições correspondentes nas listas dadas.
7. Dada uma lista de pares de valores, retornar um par de listas,
onde os elementos da primeira e segunda listas são, respec.,
o primeiro e segundo componentes de cada par da lista dada.
E XERCÍCIOS
6
M AIS
EXERCÍCIOS
(++) :: [a] → [a] → [a]
[]
++ ys = ys
(x:xs) ++ ys = x:(xs++ys)
count :: a → [a] → Int
count y [] = 0
count y (x:xs)
| y==x = 1 + count y xs
| y!=x = count y xs
reverse :: [a] → [a]
reverse []
= []
reverse (x:xs) = reverse xs ++ [x]
1. Prove que: count x (ys++zs) = count x ys + count x zs
2. Prove que: reverse (xs++ys) = reverse ys ++ reverse xs
M AIS
EXERCÍCIOS
7
M AIS
EXERCÍCIOS
shunt :: [a] → [a] → [a]
shunt []
ys
= ys
shunt (x:xs) ys
= shunt xs (x:ys)
reverse :: [a] → [a]
reverse xs = shunt xs []
1. Prove que, para toda lista finita xs:
reverse (reverse xs) = xs
M AIS
EXERCÍCIOS
8
O RDENAÇÃO - Q UICKSORT
O procedimento de ordenação conhecido como quicksort pode ser
especifcado do seguinte modo:
• A lista vazia já está ordenada.
• Listas não vazias podem ser ordenadas do seguinte modo:
➜ ordenar todos os elementos da cauda da lista que são menores
que primeiro elemento da lista;
➜ ordenar todos os elementos da cauda da lista que são maiores ou
iguais ao primeiro elemento da lista;
➜ concatenar as listas resultantes, respectivamente, à esquerda e à
direita do primeiro elemento da lista;
O RDENAÇÃO - Q UICKSORT
9
O RDENAÇÃO - Q UICKSORT
qsort :: Ord a => [a] → [a]
qsort []
= []
qsort (x:xs) = qsort [ a | a ← xs, a<x ]
++ [x] ++
qsort [ b | b ← xs, b>=x ]
Essa é possivelmente a implementação mais simples de quicksort
em qualquer linguagem de programação!
O RDENAÇÃO - Q UICKSORT
10
O RDENAÇÃO - Q UICKSORT
Por exemplo (abreviando qsort como q):
q [3,2,4,1,5]
⇓
q [2,1] ++ [3] ++ q [4,5]
⇓
⇓
q [1] ++ [2] ++ q []
q [] ++ [4] ++ q [5]
⇓
⇓
⇓
⇓
[1]
[]
[]
[5]
O RDENAÇÃO - Q UICKSORT
11
E XERCÍCIO
1. Defina uma função recursiva
insert ::
Ord a => a → [a] → [a]
que insere um elemento em uma lista ordenada, de maneira
que a lista resultante permaneça ordenada. Por exemplo:
> insert 3 [1,5,7.8]
[1,3,5,7,8]
2. Defina uma função recursiva:
isort ::
Ord a => [a] → [a]
que implementa o método de ordenação por inserção.
E XERCÍCIO
12
E XERCÍCIO
3. Defina uma função recursiva
merge ::
Ord a => [a] → [a] → [a]
que intercala duas listas ordenadas resultando em uma lista
ordenada. Por exemplo:
> merge [2,5,6] [1,3,7,8]
[1,2,3,5,6,7,8]
4. Defina uma função recursiva:
msort ::
Ord a => [a] → [a]
que implementa o método de ordenação por intercalação.
E XERCÍCIO
13
E XERCÍCIO
5. Teste suas três implementações paa ordenação usando o
Hugs e observe como elas se comparam quanto a eficiência.
Por exemplo:
> :set +s
> isort (reverse [1..5000])
> msort (reverse [1..5000])
O comando :set +s indica ao Hugs para fornecer algumas
estatísticas úteis após cada avaliação.
E XERCÍCIO
14
M AIS
UM EXERCÍCIO
O objetivo desse exercício é provar que qsort é correto, isto é:
qsort xs é uma ordenação de xs, para qualquer lista finita xs.
Como expressar formalmente essa propriedade?
➜ Devemos garantir que os elementos de qsort xs são exatamente os
elementos de xs ou, em outras palavras, que qsort xs é uma
permutação de xs. Isso pode ser expresso por meio do predicado:
perm xs ys ⇔ ∀x. count x xs = count x ys
➜ Além disso, devemos garantir que qsort xs seja uma lista ordenada.
Isso será expresso por meio do predicado:
sorted ::
Ord a => [a] → Bool
➜ Podemos então expressar a asserção a ser provada como:
∀n ∈ N. ∀xs::[a]. length xs=n ⇒ perm xs (qsort xs) ∧
sorted (qsort xs)
M AIS
UM EXERCÍCIO
15
M AIS
UM EXERCÍCIO ( CONTINUAÇÃO )
O predicado sorted pode ser definido como:
sorted
sorted
sorted
sorted
:: Ord a => [a] → Bool
[]
= True
[x]
= True
(x:y:xs) = x <= y && sorted (y:xs)
sorted pode também ser definido usando list comprehension:
sorted []
= True
sorted zs@(_:xs) = and [ x<=y | (x,y) ← zip zs xs ]
As duas definições são igualmente eficientes?
M AIS
UM EXERCÍCIO ( CONTINUAÇÃO )
16
M AIS
UM EXERCÍCIO ( CONTINUAÇÃO )
Prova: por indução sobre o comprimento de xs.
Caso base: length xs = 0, isto é, xs=[]
perm (qsort []) [] ∧ sorted (qsort [])
Caso indutivo: length xs > 0
def
Sejam l1 = [ y | y ← ys, y<x ]
def
l2 = [ y | y ← ys, y>=x ]
Devemos provar que:
perm l1 (qsort l1) ∧ sorted l1 ∧
perm l2 (qsort l2) ∧ sorted l2
⇒
perm xs (qsort l1 ++ [x] ++ qsort l2) ∧
sorted (qsort l1 ++ [x] ++ qsort l2)
M AIS
UM EXERCÍCIO ( CONTINUAÇÃO )
17
Download