Introdução - DECOM-UFOP

Propaganda
Programação Funcional
Aula 1
Introdução
José Romildo Malaquias
Departamento de Computação
Universidade Federal de Ouro Preto
2011.2
1/32
1
Programação Funcional
2
Algumas características de Haskell
3
Antecedentes históricos
4
Experimentando Haskell
2/32
A Crise de Software
I
Como podemos lidar com o tamanho e a complexidade dos
programas de computador modernos?
I
Como podemos reduzir o tempo e o custo de desenvolvimento
do programas?
I
Como podemos aumentar nossa confiança de que os programas
já concluídos funcionam corretamente?
3/32
Linguagens de Programação
Uma abordagem para a crise do software é a concepção de
novas linguagens de programação que:
I
permitam que programas sejam escritos de forma clara, concisa,
e com um alto nível de abstração;
I
suportem componentes de software reutilizáveis;
I
incentivem o uso de verificação formal;
I
permitam prototipagem rápida;
I
forneçam poderosas ferramentas de resolução de problemas.
4/32
Linguagens de Programação (cont.)
As linguagens funcionais fornecem um quadro particularmente
elegante para abordar estes objetivos.
5/32
Função
I
Função é um mapeamento de um ou mais argumentos em um
resultado único.
I
Em Haskell uma função é definida usando uma equação que dá
um nome para a função, um nome para cada um de seus
argumentos, e um corpo que especifica como o resultado pode
ser calculado em termos dos argumentos.
I
Exemplo:
Uma função chamada double que recebe um número x como
seu argumento, e produz o resultado x + x
double x = x + x
6/32
Aplicação de função
I
Quando uma função é aplicada aos argumentos reais, o
resultado é obtido pela substituição desses argumentos no corpo
da função no lugar dos nomes dos argumentos.
I
Este processo pode produzir imediatamente um resultado que
não pode ser mais simplificado, como por exemplo um número.
I
Mais comumente, no entanto, o resultado será uma expressão
contendo outras aplicações de função, que devem, então, ser
processadas da mesma maneira para produzir o resultado final.
7/32
Aplicação de função (cont.)
I
Exemplo:
Apcação da função double no argumento 3
double 3
= { aplicando double }
3 + 3
= { aplicando + }
6
8/32
Aplicação de função (cont.)
I
Exemplo:
Aplicação aninhada de double
double (double 2)
= { aplicando double interno }
double (2 + 2)
= { aplicando + }
double 4
= { aplicando double }
4 + 4
= { aplicando + }
8
9/32
Aplicação de função (cont.)
I
Exemplo:
Aplicação aninhada de double, calculada de outra maneira
double (double 2)
= { aplicando double externo }
double 2 + double 2
= { aplicando o primeiro double }
(2 + 2) + double 2
= { aplicando o primeiro + }
4 + double 2
= { aplicando double }
4 + (2 + 2)
= { aplicando o segundo + }
4 + 4
= { aplicando + }
8
10/32
Aplicação de função (cont.)
I
Em geral, a ordem na qual funções são aplicadas em um cálculo
não afeta o valor do resultado final, mas pode afetar o número de
passos necessário, e pode afetar se o processo de cálculo
termina.
11/32
O que é uma linguagem funcional?
As opiniões divergem, e é difícil dar uma definição precisa, mas de um
modo geral:
I
Programação funcional é um estilo de programação em que o
método básico de computação é a aplicação de funções a
argumentos.
I
Uma linguagem funcional é aquela que apoia e incentiva o
estilo funcional.
12/32
O que é uma linguagem funcional? (cont.)
Exemplo:
Somando os inteiros 1 a 10 em C:
total = 0;
for (i = 1; i < 10; ++i)
total = total + i;
I
O método de cálculo é atribuição de variável.
I
Em geral, linguagens de programação em que o método básico
de computação consiste em mudar os valores armazenados em
variáveis são chamadas de linguagens imperativas, pois os
programas nestas linguagens são construídos a partir de
instruções imperativas que especificam precisamente como o
cálculo deve ser realizado.
13/32
O que é uma linguagem funcional? (cont.)
Exemplo:
Somando os inteiros 1 a 10 em Haskell:
sum [1..10]
I
O método de cálculo é aplicação de função.
14/32
Algumas características de Haskell
I
Programas concisos
I
Sistema de tipos poderoso
I
Compreensões de lista
I
Funções recursivas
I
Funções de ordem superior
I
Efeitos monádicos
I
Avaliação lazy
I
Raciocínio sobre programas
15/32
Antecedentes históricos
I
Década de 1930:
Alonzo Church desenvolve o cálculo lambda, uma teoria de
funções simples, mas poderosa.
16/32
Antecedentes históricos (cont.)
I
Década de 1950:
John McCarthy desenvolve Lisp, a primeira linguagem funcional,
com algumas influências do cálculo lambda, mas mantendo as
atribuições de variáveis.
17/32
Antecedentes históricos (cont.)
I
Década de 1960:
Peter Landin desenvolve ISWIM, a primeira linguagem funcional
pura, baseada fortemente no cálculo lambda, sem atribuições.
18/32
Antecedentes históricos (cont.)
I
Década de 1970:
John Backus desenvolve FP, uma linguagem funcional que
enfatiza funções de ordem superior e raciocínio sobre programas.
19/32
Antecedentes históricos (cont.)
I
Década de 1970:
Robin Milner e outros desenvolvem ML, a primeira linguagem
funcional moderna, que introduziu a inferência de tipos e tipos
polimórficos.
20/32
Antecedentes históricos (cont.)
I
Décadas de 1970 e 1980:
David Turner desenvolve uma série de linguagens funcionais
com avaliação lazy, culminando com o sistema Miranda.
21/32
Antecedentes históricos (cont.)
I
1987:
Um comitê internacional de pesquisadores inicia o
desenvolvimento de Haskell, uma linguagem funcional lazy
padrão.
22/32
Antecedentes históricos (cont.)
I
2003:
O comitê publica o relatório Haskell 98, a definição de uma
versão estável da linguagem Haskell.
23/32
Antecedentes históricos (cont.)
I
2009:
O comitê publica o relatório Haskell 2010, uma revisão da
definição da linguagem Haskell.
24/32
Experimentando Haskell
sum :: Num a => [a] -> a
sum []
= 0
sum (x:xs) = x + sum xs
sum [1, 2, 3]
= { aplicando sum }
1 + sum [2, 3]
= { aplicando sum }
1 + (2 + sum [3])
= { aplicando sum }
1 + (2 + (3 + sum [ ]))
= { aplicando sum }
1 + (2 + (3 + 0))
= { aplicando + }
6
25/32
Experimentando Haskell (cont.)
f []
= []
f (x:xs) = f ys ++ [x] ++ f zs
where
ys = [a | a <- xs, a <= x]
zs = [b | b <- xs, b > x]
?
26/32
Experimentando Haskell (cont.)
f [x]
= { aplicando f }
f [] ++ [x] ++ f []
= { aplicando f }
[] ++ [x] ++ []
= { aplicando ++ }
[x]
27/32
Experimentando Haskell (cont.)
f [3, 5, 1, 4, 2]
= { aplicando f }
f [1, 2] ++ [3] ++ f [5, 4]
= { aplicando f }
(f [] ++ [1] ++ f [2]) ++ [3] ++ (f [4] ++ [5] ++ f [])
= { aplicando f, propriedade anterior }
([] ++ [1] ++ [2]) ++ [3] ++ ([4] ++ [5] ++ [])
= { aplicando ++ }
[1, 2] ++ [3] ++ [4, 5]
= { aplicando ++ }
[1, 2, 3, 4, 5]
28/32
Experimentando Haskell (cont.)
I
O tipo de f é
f :: Ord a => [a] -> [a]
I
Dada uma lista xs, f xs é a lista formada pelos elementos de xs
em ordem crescente.
I f
implementa o algoritmo de ordenação quick sort.
29/32
Exercícios
Exercício 1
Dê outro cálculo possível para o resultado de double (double 2).
Exercício 2
Mostre que sum [x] = x para qualquer número x.
Exercício 3
Defina uma função product que produza o produto de uma lista de
números, e mostre, usando sua definição, que
product [2,3,4] = 24
Exercício 4
Mostre como a definição da função qsort deve ser modificada para
que ela produza uma versão de uma lista ordenada em ordem
decrescente.
30/32
Exercícios (cont.)
Exercício 5
Qual é o efeito de trocar <= por < na definição de qsort? Dica:
considere o exemplo qsort [2,2,3,1,1].
31/32
Fim
32/32
Download