Programação Funcional Aulas 5 & 6

Documentos relacionados
Pedro Vasconcelos DCC/FCUP. Programação Funcional 5 a Aula Definições recursivas

Pedro Vasconcelos DCC/FCUP. Programação Funcional 7 a Aula Funções de ordem superior

Programação Funcional

Layout. Módulos. Normalmente, cada módulo está armazenado num ficheiro com o mesmo nome do módulo. Exemplo.hs

Pedro Vasconcelos DCC/FCUP. Programação Funcional 3 a Aula Definição de funções

Funções de Ordem Superior

Listas em Haskell. Listas. Linguagem Haskell. Maria Adriana Vidigal de Lima. Faculdade de Computação - UFU. Setembro

Pedro Vasconcelos DCC/FCUP. Programação Funcional 4 a Aula Listas

Conceitos de Linguagens de Programação

Pedro Vasconcelos DCC/FCUP. Programação Funcional 8 a Aula Listas infinitas

Funções de Ordem Superior

Aula prática 14. Expressão Lambda

Expressões Lambda. Programação Funcional. Capítulo 7. José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto

Programação Funcional

Aula prática 5. Funções Recursivas

Pedro Vasconcelos DCC/FCUP. Programação Funcional 14 a Aula Um verificador de tautologia

Linguagem Funcional Haskell

Aula Prática 3. Paradigmas da Programação I / Programação Funcional. ESI/MCC 1 o ano (2005/2006)

Paradigmas de Programação

Expressões Condicionais

Linguagem Haskell. Universidade Estadual Santa Cruz Conceitos de Linguagens de Programação. Tiago Carneiro 19 Agosto 2013

Programação Funcional. Aula 6. Listas. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2011.

Pedro Vasconcelos DCC/FCUP. Programação Funcional 16 a Aula Árvores equilibradas

Pedro Vasconcelos DCC/FCUP. Programação Funcional 2 a Aula Tipos e classes

Linguagem Haskell. Maria Adriana Vidigal de Lima

Pedro Vasconcelos DCC/FCUP. Programação Funcional 2 a Aula Tipos e classes

Programação Funcional. Capítulo 21. Parsers. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2018.

Programação Funcional em Haskell

Linguagens de Programação Aula 14

Linguagens de Programação. Programação Funcional e Haskell Programação Interativa Thiago Alves

Linguagens de Programação. Programação Funcional. Carlos Bazilio

Pedro Vasconcelos DCC/FCUP. Programação Funcional 15 a Aula Árvores de pesquisa

Aula Prática 2. Paradigmas da Programação I / Programação Funcional

USANDO UM MÉTODO INDUTIVO PARA RESOLVER PROBLEMAS. Bruno Maffeo Departamento de Informática PUC-Rio

Programação Funcional Aulas 9, 10 & 11

Linguagem Haskell. Riocemar S. de Santana

Linguagens de Programação. Programação Funcional Haskell. Carlos Bazilio

Expressão Condicional

Pedro Vasconcelos DCC/FCUP. Programação Funcional 13 a Aula Definição de tipos

Programação I Aula 10 Processamento de listas

Linguagens de Programação Aula 13

INE5403 FUNDAMENTOS DE MATEMÁTICA DISCRETA

Prof. Leonardo Augusto Casillo

b) Recursividade 4 - Sejam a,b,c inteiros, supostamente comprimentos dos lados dum triângulo. Escreva uma função tri que devolva:

Casamento de Padrão. Programação Funcional. Capítulo 6. José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto

Programação Funcional com a Linguagem Haskell

Programação Funcional

Revisão: Tipo Abstrato de Dados Recursividade

Programação Funcional. Aula 4. Definindo Funções. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2011.

Lógica de Hoare. Abordagem que usaremos: aplicar o método de Hoare sobre uma linguagem de programação imperativa simplificada.

Casamento de Padrão. Programação Funcional. Capítulo 5. José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto

Listas Estáticas. SCC Algoritmos e Estruturas de Dados I. Prof. Fernando V. Paulovich. *Baseado no material do Prof.

Lista 1 - PMR2300. Fabio G. Cozman 3 de abril de 2013

INE5403 FUNDAMENTOS DE MATEMÁTICA DISCRETA

Introdução à Programação

Pedro Vasconcelos DCC/FCUP. Programação Funcional 18 a Aula Plataforma Haskell

Tópicos Especiais em Informática Linguagem de Programação Haskell. Tiago Alves de Oliveira

Algoritmos e Estruturas de Dados LEE 2013/2014. popular devido à facilidade de implementação e eficiência

UNIVERSIDADE FEDERAL RURAL DO SEMI-ÁRIDO CURSO: CIÊNCIA DA COMPUTAÇÃO. Prof.ª Danielle Casillo

Números Inteiros Algoritmo da Divisão e suas Aplicações

Tipos Algébricos. Programação Funcional. Capítulo 11. José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto

INE5403 FUNDAMENTOS DE MATEMÁTICA DISCRETA

Uma gramática é ambígua se existe alguma cadeia para qual ela tem mais de uma árvore sintática

Transcrição:

Programação Funcional Aulas 5 & 6 Sandra Alves DCC/FCUP 2016/17 Definições usando outras funções Podemos definir funções usando outras previamente definidas (por exemplo: do prelúdio-padrão). Exemplo: factorial :: Int -> Int factorial n product [1..n] Definições recursivas Também podemos definir uma função por recorrência, i.e. usando a própria função que estamos a definir; tais definições dizem-se recursivas. Exemplo: factorial definido recursivamente. factorial :: Int -> Int factorial 0 1 factorial n n * factorial (n-1) Exemplo de uma redução factorial 3 3 * factorial 2 3 * (2 * factorial 1) 1

3 * (2 * (1 * factorial 0)) 3 * (2 * (1 * 1)) 6 Observações A primeira equação define o factorial de zero. A segunda equação define o factorial de n usando factorial de n 1. Logo: o factorial fica definido apenas para inteiros não-negativos. > factorial (-1) Não termina! ^C Interrupted Alternativas Duas equações sem guardas: factorial 0 1 factorial n n * factorial (n-1) Uma equação com guardas: factorial n n0 1 otherwise n*factorial (n-1) Uma equação com uma condição: factorial n if n0 then 1 else n*factorial (n-1) Porquê recursão? Modelo universal de computação: qualquer algoritmo pode ser escrito usando funções recursivas. Vamos ver que podemos demonstrar propriedades de funções recursivas usando indução matemática. Recursão sobre listas Também podemos definir funções recursivas sobre listas. Exemplo: a função que calcula o produto de uma lista de números (do prelúdio-padrão). product [] 1 product (x:xs) x*product xs 2

Exemplo de redução product [2,3,4] 2 * product [3,4] 2 * (3 * product [4]) 2 * (3 * (4 * product [])) 2 * (3 * (4 * 1)) 24 A função length O comprimento duma lista também pode ser definido por recursão. length :: [a] -> Int length [] 0 length (_:xs) 1 + length xs Exemplo de redução: length [1,2,3] 1 + length [2,3] 1 + (1 + length [3]) 1 + (1 + (1 + length [])) 1 + (1 + (1 + 0)) 3 A função reverse A função reverse (que inverte a ordem dos elementos numa lista) também pode ser definida recursivamente. reverse :: [a] -> [a] reverse [] [] reverse (x:xs) reverse xs ++ [x] Exemplo de redução: reverse [1,2,3] reverse [2,3] ++ [1] (reverse [3] ++ [2]) ++ [1] ((reverse [] ++ [3]) ++ [2]) ++ [1] 3

(([] ++ [3]) ++ [2]) ++ [1] [3,2,1] Funções com múltiplos argumentos Também podemos definir recursivamente funções com múltiplos argumentos. Por exemplo: a concatenação de listas. (++) :: [a] -> [a] -> [a] [] ++ ys ys (x:xs) ++ ys x : (xs ++ ys) A função zip que constroi a lista dos pares de elementos de duas listas. zip :: [a] -> [b] -> [(a,b)] zip [] _ [] zip _ [] [] zip (x:xs) (y:ys) (x,y) : zip xs ys A função drop que remove um prefixo de uma lista. drop :: Int -> [a] -> [a] drop 0 xs xs drop n [] [] drop n (x:xs) n>0 drop (n-1) xs Recursão mútua Podemos também definir duas ou mais funções que dependem mutamente umas das outras. Exemplo: testar se um natural é par ou impar. 1 par :: Int -> Bool par 0 True par n n>0 impar (n-1) impar :: Int -> Bool impar 0 False impar n n>0 par (n-1) 1 De forma ineficiente. 4

Quicksort O algoritmo Quicksort para ordenação de uma lista pode ser especificado de forma recursiva: se a lista é vazia então já está ordenada; se a lista não é vazia seja x o primeiro valor e xs os restantes: 1. recursivamente ordenamos os valores de xs que são menores ou iguais a x; 2. recursivamente ordenamos os valores de xs que são maiores do que x; 3. concatenamos os resultados com x no meio. Em Haskell: qsort :: [Int] -> [Int] qsort [] [] qsort (x:xs) qsort menores ++ [x] ++ qsort maiores where menores [x x <-xs, x <x] maiores [x x <-xs, x >x] Esta é provavelmente a implementação mais concisa do algoritmo Quicksort em qualquer linguagem de programação! Exemplo de execução (abreviando qsort para qs): qs [3,2,4,1,5] qs [2,1] ++ [3] ++ qs [4,5] (qs [1]++[2]++qs []) ++ [3] ++ (qs []++[4]++qs [5]) ([1]++[2]++[]) ++ [3] ++ ([]++[4]++[5]) [1,2,3,4,5] Como escrever definições recursivas 1. Definir o tipo da função 2. Enumerar os casos a considerar usando equações com padrões 3. Definir o valor nos casos simples 4. Definir o valor nos outros casos assumindo que a função está definida para valores de tamanho inferior 5. Generalizar e simplificar Exemplo Escrever uma definição recursiva da função init que remove o último elemento duma lista. > init [1,2,3,4,5] [1,2,3,4] > init [1] [] > init [] *** Exception: Prelude.init: empty list 5

Passo 1: o tipo da função é init :: [a] -> [a] Passo 2: enumerar os casos. init :: [a] -> [a] init (x:xs) Notar que init não está definido para a lista vazia. Passo 3: definir o caso simples. init :: [a] -> [a] init (x:xs) null xs [] otherwise Notar que se xs é a lista vazia então a lista (x : xs) tem um só elemento. Passo 4: definir o caso recursivo. init :: [a] -> [a] init (x:xs) null xs [] otherwise x : init xs Notar que xs é uma sub-lista de (x : xs), logo tem comprimento menor. Passo 5: simplificação. init :: [a] -> [a] init [x] [] init (x:xs) x : init xs Podemos separar o caso da lista com um só elemento numa equação e assim eliminar as guardas. Exercícios: Usando o hugs experimente as funções sum, maximum, minimum, notelem, take, zip, unzip, zip3, unzip3. Defina as funções indicadas na alínea anterior. Funções de ordem superior Uma função é de ordem superior se tem um argumento que é uma função ou um resultado que é uma função. Exemplo: o primeiro argumento de twice é uma função. twice :: (a -> a) -> a -> a twice f x f (f x) 6

Porquê ordem superior? Permite definir padrões de computação comuns que podem ser facilmente re-utilizados. Facilita a definição de bibliotecas para domínios específicos: processamento de listas; formatação de texto; parsing ;... Podemos provar propriedades gerais das funções de ordem superior que são válidas em qualquer use específico. A função map A função map aplica uma função a cada elemento duma lista. map :: (a -> b) -> [a] -> [b] Exemplos: > map (+1) [1,3,5,7] [2,4,6,8] > map islower "Hello!" [False,True,True,True,True,False] Podemos definir map usando uma lista em compreensão: map f xs [f x x<-xs] Também podemos definir map usando recursão: map f [] [] map f (x:xs) f x : map f xs Esta forma será útil para provar propriedades usando indução. Função filter A função filter seleciona os elementos duma lista que satisfazem um predicado (isto é, uma função cujo resultado é um valor boleano). filter :: (a -> Bool) -> [a] -> [a] Exemplos: 7

> filter even [1..10] [2,4,6,8,10] > filter islower "Hello, world!" "elloworld" Podemos definir filter usando uma lista em compreensão: filter p xs [x x<-xs, p x] Também podemos definir filter usando recursão: filter p [] [] filter p (x:xs) p x x : filter p xs otherwise filter p xs Funções takewhile e dropwhile takewhile seleciona o maior prefixo duma lista cujos elementos verificam um predicado. dropwhile remove o maior prefixo cujos elementos verificam um predicado. As duas funções têm o mesmo tipo: takewhile, dropwhile :: (a -> Bool) -> [a] -> [a] Exemplos: > takewhile isletter "Hello, world!" "Hello" > dropwhile isletter "Hello, world!" ", world!" > takewhile (\n -> n*n<10) [1..5] [1,2,3] > dropwhile (\n -> n*n<10) [1..5] [4,5] Definições recursivas de takewhile e dropwhile (do prelúdio-padrão): takewhile :: (a -> Bool) -> [a] -> [a] takewhile p [] [] takewhile p (x:xs) p x x : takewhile p xs otherwise [] dropwhile :: (a -> Bool) -> [a] -> [a] dropwhile p [] [] dropwhile p (x:xs) p x dropwhile p xs otherwise x:xs 8

As funções all e any all verifica se um predicado é verdadeiro para todos os elementos duma lista. any verifica se um predicado é verdadeiro para algum elemento duma lista. As duas funções têm o mesmo tipo: all, any :: (a -> Bool) -> [a] -> Bool Exemplos: > all even [2,4,6,8] True > any odd [2,4,6,8] False > all islower "Hello, world!" False > any islower "Hello, world!" True Podemos definir all e any usando map, and e or: all p xs and (map p xs) any p xs or (map p xs) A função foldr Muitas funções sobre listas seguem o seguinte padrão de definição recursiva: f [] z f (x:xs) x f xs Ou seja, f transforma: a lista vazia em z; a lista não-vazia x : xs usando uma operação para combinar x com f xs. Exemplos: sum [] 0 z 0 sum (x:xs) x + sum xs + product [] 1 z 1 product (x:xs) x * product xs and [] True z True and (x:xs) x && and xs && 9

or [] False z False or (x:xs) x or xs length [] 0 z 0 length (x:xs) 1 + length xs \x n 1 + n A função de ordem superior foldr ( fold right ) abstrai este padrão de recursão; os seus argumentos são a operação e o valor z: sum foldr (+) 0 product foldr (*) 1 and or foldr (&&) True foldr ( ) False length foldr (\x n->n+1) 0 Definição recursiva de foldr (do prelúdio-padrão): foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] z foldr f z (x:xs) f x (foldr f z xs) Podemos visualizar foldr f z como a transformação que substitui: cada (:) por f; [ ] por z. Exemplo: sum [1,2,3,4] foldr (+) 0 [1,2,3,4] 10

foldr (+) 0 (1:(2:(3:(4:[])))) 1+(2+(3+(4+0))) 10 Outro exemplo: product [1,2,3,4] foldr (*) 1 [1,2,3,4] foldr (*) 1 (1:(2:(3:(4:[])))) 1*(2*(3*(4*1))) 24 A função foldl A função foldr transforma uma lista usando uma operação associada à direita ( fold right ): foldr ( ) v [x 1, x 2,..., x n ] x 1 (x 2 (... (x n v)...)) Existe outra função foldl que transforma uma lista usando uma operação associada à esquerda ( fold left ): foldl ( ) v [x 1, x 2,..., x n ] ((... ((v x 1 ) x 2 )...) x n ) Se f for associativa com elemento neutro z, então foldr f z e foldl f z dão o mesmo resultado. foldl (+) 0 [1,2,3,4] (((0+1)+2)+3)+4 10 foldr (+) 0 [1,2,3,4] 1+(2+(3+(4+0))) 10 Tal como foldr, a função foldl está definida no prelúdio-padrão usando recursão: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] z foldl f z (x:xs) foldl f (f z x) xs No entanto, pode ser mais fácil visualizar foldl como uma transformação sobre listas: 11

Fonte: http://en.wikipedia.org/wiki/fold_(higher-order_function). Outras funções de ordem superior A função ( ) é a composição de duas funções. (.) :: (b -> c) -> (a -> b) -> a -> c f. g \x -> f (g x) Exemplo par :: Int -> Bool par x x mod 2 0 impar :: Int -> Bool impar not. par A composição permite muitas vezes simplificar definições embricadas, omitido os parêntesis e o argumento. Exemplo: f xs sum (map (^2) (filter par xs)) é equivalente a f sum. map (^2). filter par Exercícios Utilize a função any para implementar a função elem Utilize a função foldr para implementar as funções maximum e minimum Exprima a compreensão [f x x <- xs, p x] usando as funções map e filter. 12