Programação Funcional Lucília Camarão de Figueiredo Universidade Federal de Ouro Preto lucilia@dcc.ufmg.br Aula 04: Definição de funções 1
DEFINIÇÃO DE FUNÇÕES f x1 x2...xn = E Define uma função f de tipo T1 T2... Tn T, onde Ti é o tipo do i-ésimo argumento de f, para i=1,....n, e T é o tipo da expressão E (ou seja, o tipo do valor retornado por f) Exemplos de operações: double :: Num a => a a double x = 2*x exor :: Bool Bool Bool exor x y = (x y) && (not (x && y)) max3 x y z :: Ord a => a a a a max3 x y z = max(max(x,y),z) DEFINIÇÃO DE FUNÇÕES 2
EXPRESSÕES CONDICIONAIS f x1 x2...xn = E Na maioria das linguagens de programação, funções podem ser definidas usando-se expressões condicionais: max :: Ord a => a a a max x y = if (x >= y) then x else y abs :: Num a, Ord a => a a abs x = if x > 0 then x else -x EXPRESSÕES CONDICIONAIS 3
EXPRESSÕES CONDICIONAIS Expressões condicionais podem ser aninhadas: signum x = if x>0 then 1 else if x==0 then 0 else -1 Nota: Em Haskell, expressões condicionais devem sempre ter a cláusula else isso evita possíveis problemas de ambiguidade envolvendo expressões condicionais aninhadas. EXPRESSÕES CONDICIONAIS 4
EQUAÇÕES COM GUARDAS Como alternativa ao uso de expressões condicionais, podemos definir funções usando equações com guardas: abs x x > 0 = x otherwise = -x signum x x>0 = 1 x==0 = 0 x<0 = -1 Equações com guardas tornam as definições mais legíveis. Nota: A condição otherwise usada em equações com guardas é definida no Prelude como otherwise = True. EQUAÇÕES COM GUARDAS 5
CASAMENTO DE PADRÃO O uso casamento de padrão favorece a legibilidade: not :: Bool Bool not True = False not False = True (&&) :: Bool Bool Bool True && True = True True && False = False False && True = False False && False = False CASAMENTO DE PADRÃO 6
CASAMENTO DE PADRÃO O operador && pode ser definido mais facilmente como: True && True = True _ && _ = False Entretanto, a seguinte definição é sempre mais eficiente (uma vez que sempre evita a avaliação do segundo argumento): False && _ True && b = b = False Nota: O padrão _ corresponde a um "coringa", que casa com qualquer argumento. CASAMENTO DE PADRÃO 7
PADRÕES PARA LISTAS Em Haskell, toda lista não vazia é construída por meo do operador : (denominado cons), que adiciona um novo elemento ao início da lista, ou seja, : tem tipo a [a] [a]: [1,2,3] significa 1:(2:(3:[])) O operador cons também pode ser usado em padrões, caso no qual ele destrói uma lista não vazia: head :: a [a] head (x:_) = x tail :: [a] [a] tail (_:xs) = xs PADRÕES PARA LISTAS 8
PADRÕES PARA LISTAS Mais alguns exemplos de definições de funções sobre listas: length :: [a] Int length [] = 0 length (_:xs) = 1 + length xs sum :: [a] Int sum [] = 0 sum (x:xs) = x + length xs (++) :: [a] [a] [a] [] ++ ys = ys (x:xs) ++ ys = x:(xs++ys) PADRÕES PARA LISTAS 9
PADRÕES MAIS UM EXEMPLO: A função a seguir determina a média de uma lista de valores inteiros: average :: [Int] Float average xs@(y:yx) = fromint (sum xs) / fromint (length xs) Essa definição ilustra o uso de alias em um padrão. A definição acima não é, entretanto, eficiente. Porque? Uma definição eficiente será apresentada mais adiante. PADRÕES MAIS UM EXEMPLO: 10
EXPRESSÕES LAMBDA Podemos construir uma função sem que seja necessário dar um nome a essa função para isso, usamos uma lambda abstração: λx x+1 representa a função que, dado um argumento x, retorna x+1. EXPRESSÕES LAMBDA 11
PORQUE EXPRESSÕES LAMBDA SÃO ÚTEIS? Expressões Lambda podem ser usadas para dar significado formal a definições de funções currificadas. Por exemplo: add x y = x+y significa add = λx (λx x+y) Expressões Lambda são úteis para definir funções que retornam funções como resultado. Por exemplo: compose f g x = f (g x) é mais naturalmente definida como: compose f g = λx f (g x) PORQUE EXPRESSÕES LAMBDA SÃO ÚTEIS? 12
EXERCÍCIOS 1. Dê 2 possíveis definições para o operador usando casamento de padrão. 2. Considere uma função safetail, que se comporta como a função tail, exceto que safetail mapea a lista vazia em lista vazia, enquanto tail produz um erro nesse caso. Defina safetail usando: (a) uma expressão condicional (b) equações com guardas (c) casamento de padrão Obs: A função null :: [a] Bool, definida no Prelude, pode ser usada para testar se uma lista é vazia. Como vocˆxe definiria essa função? EXERCÍCIOS 13