30
Programação Programação Funcional Funcional 7a. Seção de Slides Generalização em Haskell Generalização em Haskell

Programação Funcional

Embed Size (px)

DESCRIPTION

Programação Funcional. Generalização em Haskell. 7a. Seção de Slides. Hoje. Funções de mais alta ordem ou funções de ordem superior (“higher order function”) Generalizações de funções Polimorfismos. Funções como Argumentos. - PowerPoint PPT Presentation

Citation preview

Page 1: Programação Funcional

Programação Programação FuncionalFuncional

7a. Seção de Slides

Generalização em HaskellGeneralização em Haskell

Page 2: Programação Funcional

2

Hoje

• Funções de mais alta ordem ou funções de ordem superior (“higher order function”)

• Generalizações de funções• Polimorfismos

Page 3: Programação Funcional

3

Funções como Argumentos

• Assim como números, tuplas e listas, também funções (já visto nas listas de exercício) podem ser argumentos para outras funções.

• Funções que recebem outras funções como argumentos são chamadas de:

funções de mais alta ordem ou funções de ordem superior (“higher order function”)

Page 4: Programação Funcional

4

Motivação

1 .2 .3 .

1 .2 .3 .

double :: [Int] -> [Int]double [] = []double (a:x) = (2*a) : double x

• Função para retornar uma lista com os elementos “vezes dois” :

1 .2 .3 .

1 .2 .3 .

treble :: [Int] -> [Int]treble [] = []treble (a:x) = (3*a) : treble x

• Função para retornar uma lista com os elementos "triplicados":

Page 5: Programação Funcional

5

Motivação

1 .2 .3 .

1 .2 .3 .

double :: [Int] -> [Int]double [] = []double (a:x) = (2*a) : double x

1 .2 .3 .

1 .2 .3 .

treble :: [Int] -> [Int]treble [] = []treble (a:x) = (3*a) : treble x

• O padrão (formato) de ambas as definições, é o mesmo!

• A única coisa que muda é o modo de como os elementos da lista são transformados (2*a ora 3*a).

Page 6: Programação Funcional

6

Relembrando

1 .2 .3 .

1 .2 .3 .

double :: [Int] -> [Int]double lista = [2*x | x <- lista]double [4, 8 .. 31]

[8,16,24,32,40,48,56]

1 .2 .3 .

1 .2 .3 .

treble :: [Int] -> [Int]treble lista = [3*x | x <- lista]treble [4, 8 .. 31][12,24,36,48,60,72,84]

A proposta é: “seria possível termos funções que generalizassem estas definições sobre parâmetros?”

Page 7: Programação Funcional

7

Generalizando

1 .2 .3 .

1 .2 .3 .

times2, times3 :: Int -> Inttimes2 n = 2*ntimes3 n = 3*n

• Uma função genérica para transformar listas de inteiros deveria então ter dois argumentos:– uma função que especifica a transformação a ser realizada

sobre cada elemento da lista;– a lista a ser transformada.

• Exemplos de funções de transformação para elementos (inteiros)...– Do exemplo anterior teríamos que as funções de

transformação são do tipo:

Page 8: Programação Funcional

8

Generalizando

1 .2 .

1 .2 .

mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

• Função genérica para transformar listas de inteiros:

• A função mapInt recebe como argumentos:– Uma função f que especifica a transformação a ser

realizada em cada elemento da lista;– E a lista a ser transformada.

Mantenha em menteestas construções ..

Page 9: Programação Funcional

9

Generalizando: outra solução

1 .2 .

1 .2 .

mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

• Função genérica para transformar listas de inteiros:

• Outra solução - usando “list comprehensions”:

1 .1 .mapInt f lista = [ (f a) | a <- lista]

Page 10: Programação Funcional

10

Exemplo

mapInt times2 [1,4]= (times2 1) : mapInt times2 [4]= 2 : mapInt times2 [4]= 2 : ((times2 4) : mapInt times2 [])= 2 : (8 : mapInt times2 [])= 2 : (8 : [])= [2,8]

1 .2 .3 .4 .

1 .2 .3 .4 .

mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

times2 n = 2*n

Ativando...

Page 11: Programação Funcional

11

Exemplo

1 .2 .3 .4 .

1 .2 .3 .4 .

mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

times3 n = 3*n

MapInt times3 [1,4] = (times3 1) : mapInt times3 [4]= 3 : mapInt times3 [4]= 3 : ((times3 4) : mapInt times3 [])= 3 : (12 : mapInt times3 [])= 3 : (12 : [])= [3,12]

Ativando...

Page 12: Programação Funcional

12

Redefinindo double e treble

Main> double [1,4][2,8]Main> treble [1,4][3,12]

Main> double [1,4][2,8]Main> treble [1,4][3,12]

1 .2 .3 .4 .5 .6 .7 .8 .9 .

1 .2 .3 .4 .5 .6 .7 .8 .9 .

mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

times2, times3 :: Int -> Inttimes2 n = 2*ntimes3 n = 3*n

double lista = mapInt times2 listatreble lista = mapInt times3 lista

Page 13: Programação Funcional

13

Definindo tipos

1 .2 .3 .

1 .2 .3 .

mapInt :: t1??? -> t2??? -> t3???mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

• Qual o tipo de mapInt ?– o primeiro argumento é uma função que transforma um inteiro em

outro inteiro:

(2*Int ou 3*Int, resultando em Int, logo: Int -> Int)– o segundo argumento é uma lista de inteiros: [Int];– retorna outra lista de inteiros : [Int].

Page 14: Programação Funcional

14

Definindo tipos

1 .2 .3 .

1 .2 .3 .

mapInt :: (Int->Int) -> [Int] -> [Int]mapInt f [] = []mapInt f (a:x) = (f a) : mapInt f x

• Repetindo:– o primeiro argumento é uma função que transforma um

inteiro em outro inteiro;– o segundo argumento é uma lista de inteiros;– retorna outra lista de inteiros.

Page 15: Programação Funcional

15

Vantagens

• Ao usar funções de mais alta ordem, consegue-se mais clareza e simplicidade nas definições.

• Fica mais fácil proceder modificações. Por exemplo, se for necessário modificar apenas a função de transformação de elementos.

• Permite reutilização (reusabilidade de código) de definições. A função mapInt pode ser usada em muitas outras situações.

Page 16: Programação Funcional

16

Exemplo 1

1 sales :: Int -> Int2 sales x3 | x == 0 = 124 | x == 1 = 205 | x == 2 = 186 | x == 3 = 257 | otherwise = 0

1 sales :: Int -> Int2 sales x3 | x == 0 = 124 | x == 1 = 205 | x == 2 = 186 | x == 3 = 257 | otherwise = 0

8 totalSales :: Int -> Int9 totalSales n10 | n == 0 = sales 011 | otherwise = totalSales (n-1) + (sales n)

8 totalSales :: Int -> Int9 totalSales n10 | n == 0 = sales 011 | otherwise = totalSales (n-1) + (sales n)

Função totalSales usauma definição

específica para sales.

Função totalSales usauma definição

específica para sales.

Page 17: Programação Funcional

17

Exemplo 1 - generalizando

8 .9 .10.11.12.13.

8 .9 .10.11.12.13.

total :: (Int - > Int) -> Int -> Inttotal f n | n==0 = f 0 | otherwise = total f (n-1) + f n

• Contudo, “a genérica”, função total, pode ser usada em muitas outras situações...

totalSales n = total sales n

Page 18: Programação Funcional

18

Exemplo 1 - generalizando

8 .9 .10.11.12.13.14.15.16.17.18.19.

8 .9 .10.11.12.13.14.15.16.17.18.19.

total :: (Int - > Int) -> Int -> Inttotal f n | n==0 = f 0 | otherwise = total f (n-1) + f n

totalSales n = total sales n

sumSquares :: Int -> IntsumSquares n = total sq n

sq :: Int -> Intsq x = x*x

Calcula a somados quadrados

de 0 a n.

Calcula a somados quadrados

de 0 a n.

É o reuso de código !

Page 19: Programação Funcional

19

Exemplo 2

• Soma dos elementos de uma lista de inteiros:

e1 + e2 + ... + ek

• Máximo elemento de uma lista de inteiros:

e1 'maxi' e2 'maxi' ... 'maxi' ek

• Tipos das funções aplicadas a pares de elementos:

(+), 'maxi' :: Int -> Int -> Int

Page 20: Programação Funcional

20

Exemplo 2 - generalizando

1 .2 .3 .4 .5 .6 .7 .89101112 .

1 .2 .3 .4 .5 .6 .7 .89101112 .

foldInt :: (Int -> Int -> Int) -> [Int] -> Int

foldInt f [a] = afoldInt f (a:b:x) = f a (foldInt f (b:x))oufoldInt f (a:x) = f a (foldInt f x)

sumList lista = foldInt (+) listamaxList lista = folInt maxi lista

Page 21: Programação Funcional

21

Detalhando

1 .2 .3 .4 .5 .6 .7 .89101112 .

1 .2 .3 .4 .5 .6 .7 .89101112 .

maior_da_LISTA [8,1,7,-3,9,-7]

9

maior_da_LISTA lista = reduz maior_de_2 lista

maior_de_2 x y| x >= y = x| otherwise = y

reduz f [a] = a reduz f (a : resto) = f a (reduz f resto)

Page 22: Programação Funcional

22

Exemplo 3

• Filtrar algarismos/números de um texto:digits "29 February 1996"= "291996"

• Filtrar letras de um texto:

• Tipos das funções aplicadas a cada elemento:

isDigit, isLetter :: Char -> Bool

letters "29 February 1996"= "February"

Page 23: Programação Funcional

23

Exemplo 3 - generalizando

1 .2 .3 .4 .5 .6 .7 .8 .9 .10.11.12.13.14.

1 .2 .3 .4 .5 .6 .7 .8 .9 .10.11.12.13.14.

filterString :: (Char -> Bool) -> [Char] -> [Char]

filterString p [] = []filterString p (a:x) | p a = a : filterString p x | otherwise = filterString p x

isDigit, isLetter :: Char -> BoolisDigit ch = ('0'<=ch && ch<='9')isLetter ch = ('a'<=ch && ch <='z') || ('A'<=ch && ch <='Z')

digits st = filterString isDigit stletters st = filterString isLetter st

Page 24: Programação Funcional

24

Exemplo 3 - outra solução

1 .2 .3 .4 .5 .6 .7 .8 .9 .10.11.

1 .2 .3 .4 .5 .6 .7 .8 .9 .10.11.

filterString :: (Char -> Bool) -> [Char] -> [Char]

filterString p x = [ a | a <- x , p a ]

isDigit, isLetter :: Char -> BoolisDigit ch = ('0'<=ch && ch<='9')isLetter ch = ('a'<=ch && ch <='z') || ('A'<=ch && ch <='Z')

digits st = filterString isDigit stletters st = filterString isLetter st

Page 25: Programação Funcional

25

Polimorfismo

• Função que calcula o comprimento de uma lista:

• Qual o tipo de length ?

length :: [t] -> Int

1 .2 .

1 .2 .

length [] = 0length (a:x) = 1 + length x

t = variável de tipot = variável de tipo

Page 26: Programação Funcional

26

Listas> comp_lista [1 .. 20]20Listas> comp_lista ['a' .. 'z']26Listas> comp_lista ["a" .. "z"]ERROR - Illegal Haskell 98 class constraint in inferred type*** Expression : comp_lista (enumFromTo "a" "z")*** Type : Enum [Char] => Integer

Listas> comp_lista ["a" , "c", "z"]3Listas> comp_lista " xxxxxxx "9

Listas> comp_lista [1 .. 20]20Listas> comp_lista ['a' .. 'z']26Listas> comp_lista ["a" .. "z"]ERROR - Illegal Haskell 98 class constraint in inferred type*** Expression : comp_lista (enumFromTo "a" "z")*** Type : Enum [Char] => Integer

Listas> comp_lista ["a" , "c", "z"]3Listas> comp_lista " xxxxxxx "9

Polimorfismo - Exemplo

1 .2 .

1 .2 .

comp_lista [] = 0comp_lista (_:resto) = 1 + comp_lista resto

Page 27: Programação Funcional

27

Outros exemplos de polimorfismo

• Função que calcula o reverso de uma lista:

• Qual o tipo de rev ?

rev :: [t] -> [t]

1 .2 .

1 .2 .

rev [] = []rev (a:x) = rev x ++ [a]

Importante: retorna lista do mesmo tipoque o argumento de entrada

Importante: retorna lista do mesmo tipoque o argumento de entrada

Page 28: Programação Funcional

28

Outros exemplos de polimorfismo

• Função para construir lista de pares:

• Qual o tipo de zip ?

zip :: [t] -> [u] -> [ (t,u) ]

1 .2 .

1 .2 .

zip (a:x) (b:y) = (a,b) : zip x yzip _ _ = []

Importante: os tipos t e unão estão relacionados!

Importante: os tipos t e unão estão relacionados!

Page 29: Programação Funcional

29

Vantagens

• Ao usar polimorfismo, as definições ficam mais genéricas;

• As definições podem ser reutilizadas em muitas situações diferentes;

• Por exemplo, a função length calcula o comprimento de listas de qualquer tipo;

• Sem polimorfismo, seria necessário criar uma versão de length para cada tipo de lista a ser utilizada.

Page 30: Programação Funcional

30

Conclusões

• Funções de ordem superior exigem abstração, contudo: elegantes!

• Temos 3 clássicas: reduzir (seleciona um da lista) filtrar (seleciona nenhum, alguns ou todos), e mapear (sobre todos);

• Ao usar polimorfismo, as definições das funções ficam mais genéricas: seria necessário criar uma versão de comp_lista para cada tipo de lista a ser utilizada.