1 / 23

Funções Curried

Funções Curried. Vamos introduzir uma nova notação para definir funções de ordem superior. Suponhamos que temos uma função f que está definida como sendo do tipo int  (int  int) , desta forma faz sentido escrever f 5 (uma aplicação de f a 5) que denota uma função do tipo int  int .

Download Presentation

Funções Curried

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Funções Curried Vamos introduzir uma nova notação para definir funções de ordem superior. Suponhamos que temos uma função f que está definida como sendo do tipo int  (int  int), desta forma faz sentido escrever f 5 (uma aplicação de f a 5) que denota uma função do tipo int  int. A aplicação desta função a 3 continua a fazer sentido e escreve-se (f 5) 3. Aqui temos um exemplo em que a função é representada por uma expressão composta em vez de um nome. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  2. Funções Curried Como esta notação irá ocorrer muito frequentemente quando trabalhamos com funções de ordem superior, vamos assumir associatividade à esquerda na aplicação de funções e eliminar os parêntesis. Assim f 5 3 é lido com (f 5) 3 e em geral E1 E2 ... En é lido como ( ... (E1E2) E3 ...) En) Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  3. Funções Curried Com base nesta convenção introduz-se uma notação mais simples para definir funções como f - a notação curried. Assim nas definições fun soma m n = m + n fun vezes m n = m * n só a sintaxe das funções mudou, a semântica é a mesma. Por exemplo soma é uma função que tem como argumento um inteiro m e tem como resultado uma função, a qual tem como argumento um inteiro n e cujo resultado é m + n. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  4. Funções Curried Embora possa parecer que esta notação é apenas mais uma forma de escrever somas e multiplicações, na verdade temos mais do que isso. Podemos escrever expressões ‘intermédias’ tais como vezes 3 que representa a função que multiplica os seus argumentos por 3. Esta expressão pode depois ser usada em qualquer contexto onde faça sentido. Por exemplo val triplo = vezes 3 Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  5. Funções Curried No exemplo anterior temos a definição de uma função (triplo: int  int) que não faz uso de parâmetros. No entanto, da definição de triplo e vezes temos que para qualquer argumento inteiro x: triplo x = vezes 3 x = 3 * x Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  6. Funções Curried Também podemos escrever expressões do tipo val funnyfun = dobro ° (soma 6) que descreve uma função do tipo int  int e é a composição de uma função que adiciona 6 ao seu argumento e uma função que duplica o respectivo argumento. funnyfun 10 = dobro (soma 6 10) = dobro (6+10) = dobro 16 = 2*16 = 32 Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  7. Funções Curried De uma forma geral, para qualquer função da forma fun f (a1, a2, ..., an) = b f: (1 x 2 x ... x n)   a1: 1, a2: 2, ..., an: n, b:  É possível definir a sua versão curried: fun curryf a1, a2, ..., an = b curryf: 1  (2  (...  (n  ) ... )) Assume-se associatividade à direita para o operador . Assim podemos abreviar: curryf: 1  2  ...  n   Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  8. Listas Um conceito bastante importante em matemática é o de sequência ou lista de elementos. As listas também desempenham um papel preponderante na programação funcional, por isso vamos estudar as listas e operações sobre estas. A importância das listas advém do facto de estas providenciarem uma forma simples de agrupar elementos. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  9. Listas Podemos ver uma lista como um valor que consiste num número arbitrário e finito de elementos, todos do mesmo tipo. Se T é o tipo dos elementos da lista então escrevemos Tlist para representar o novo tipo. Assim, o novo operador sobre tipos - list - estende o nosso sistema de tipos, o que nos permite usar tipos tais como: int list (lista de inteiros) (bool x string) list (lista de pares booleanos-inteiros) (int list) list (lista de listas de inteiros) (int  string) list (lista de funções de inteiros para strings) int  (string list) (funções de inteiros para lista de strings)  list (lista de elementos do tipo ) Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  10. Listas Iremos frequentemente escrever listas usando a seguinte notação: [5, 6, 3, 2, 8] (um valor do tipo int list) [true, true, false] (um valor do tipo bool list) Uma expressão da forma [not false, 3<5, 3 = 5] descreve um valor que é uma lista (bool list, neste caso) e este valor pode também ser representado pela sua forma simplificada [true, true, false]. Note-se que não são permitidas listas com elementos de tipos distintos, como por exemplo: [3, true, 5, 8] Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  11. Listas A lista vazia (com zero elementos) é escrita simplesmente com [], que se pronuncia ‘nil’ e temos que o seu tipo é: []:  list uma vez que [] denota, polimorficamente, uma lista vazia de qualquer tipo de elementos. O extremo esquerdo da lista é visto como o início da lista e usa-se um operador infixo especial (denotado por :: e que se lê cons) para adicionar um novo elemento ao início da lista. Por exemplo: 5::[6, 3, 2, 8] = [5, 6, 3, 2, 8] Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  12. Listas O tipo do operador :: é dado por  x  list   list o que nos garante que apenas podemos adicionar um elemento à lista se este for do mesmo tipo que os elementos já existentes. Os construtores de listas, são pois o operador constante [] e o operador ::. De facto qualquer lista que tenhamos pode ser construída inteiramente através do uso de [] e de ::. Assim a notação anterior que usamos para listas é uma abreviatura da notação canónica (notação que recorre apenas às operações construtoras das listas), sendo que as seguintes listas são equivalentes: [1, 2, 3, 4] 1::2::3::4::[] Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  13. Operações sobre listas • Além dos construtores referidos atrás, podemos considerar algumas operações acessórias, que iremos introduzir através de exemplos: • @: ( list x  list)   list, operador infixo de concatenação de listas • [1, 2, 3] @ [4, 5] = [1, 2, 3, 4, 5] • rev:  list   list, função que inverte listas • rev [1, 2, 3, 4, 5] = [5, 4, 3, 2, 1] • null:  list  bool, função que indica se uma lista é a lista vazia • implode: string list  string, função que concatena as strings que constam de uma lista de strings • implode [“isto ”, “ e”, “ aquilo”] = “isto e aquilo” Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  14. Operações sobre listas • link: ( list) list   list, função que concatena as listas que constam de uma lista de listas • link [[1, 2], [3, 4], [5, 6]] = [1, 2, 3, 4, 5, 6] • length:  list  int, função que dá o comprimento de uma lista • length [2, 4, 6, 9] = 4 • hd:  list  , função que dá o elemento à cabeça da lista • hd [1, 5, 8, 3] = 1 • tl:  list   list, função que dá a cauda da lista • tl [1, 5, 8, 3] = [5, 8, 3] • member: = list  =  bool, função que testa se um dado elemento pertençe à lista • member [3, 6, 2, 5, 2, 7] 5 = true Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  15. Operações sobre listas • upto: (int x int)  int list, operador infixo que constrói a lista dos inteiros entre dois dados valores • 1 upto 5 = [1, 2, 3, 4, 5] • copy: int     list, função que constrói uma lista com n cópias de um dado valor • copy 6 10 = [10, 10, 10, 10, 10, 10] • sumlist: int list  int, função que retorna a soma dos inteiros da lista • sumlist [1, 6, 2, 7, 9] = 1 + 6 + 2 + 7 + 9 = 25 • prodlist: int list  int, função que retorna o produto dos inteiros da lista • prodlist [2, 6, 1, 4] = 2 * 6 * 1 * 4 = 48 Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  16. Pattern matching com listas Uma vez que todas as listas são ou [] ou da forma a::x, podemos definir funções sobre listas, descrevendo qual o seu comportamento em cada um dos casos do argumento. Muitas funções podem ser introduzidas utilizando apenas dois casos: aquele em que se trata da lista vazia (utilizamos como parâmetro o construtor []) e o outro em que temos uma lista com um ou mais elementos (utilizamos como parâmetro o construtor :: e variáveis para representarem a cabeça e a cauda da lista: a::x). Podemos também ter funções sobre listas que necessitem de ser definidas utilizando mais do que dois casos. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  17. Pattern matching com listas Por exemplo, a função alternate:  list   list retorna a lista composta por ‘elemento não, elemento sim’ da lista recebida como argumento. A sua definição inclui casos separados para a lista vazia, para a lista com um único elemento e para listas com dois ou mais elementos: fun alternate(a::b::x) = b :: alternate x | alternate [a] = [] | alternate [] = [] o primeiro caso irá emparelhar com listas que tenham 2 ou mais elementos, sendo que a será ligado ao 1º elemento, b ao 2º e x à cauda da lista. O segundo caso apenas irá emparelhar com listas que tenham um único elemento e o terceiro com listas vazias. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  18. Pattern matching com listas Temos assim a definição das funções acima apresentadas, utilizando o ‘pattern matching’: fun rev [] = [] fun implode [] = “” | rev (a::x) = (rev x) @ [a] | implode (a::x) = a ^ implode x fun link [] = [] fun length [] = 0 | link (a::x) = a @ link x | length (a::x) = 1 + length x fun hd [] = error “hd de []” fun tl [] = error “tl de []” | hd (a::x) = a | tl (a::x) = x fun member a [] = false | member a (b::x) = if a=b then true else member a x Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  19. Pattern matching com listas fun null (a::x) = false | null [] = true fun sumlist (a::x) = a + sumlist x | sumlist [] = 0 fun prodlist (a::x) = a * prodlist x | prodlist [] = 1 fun (a::x) @ y = a::(x @ y) | [] @ y = y Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  20. Funções de ordem superior com listas As funções de ordem superior que são apresentadas de seguida têm um maior grau de generalidade e podem servir de base a uma redefinição mais simples de algumas operações já apresentadas. Além disso, permitem encapsular o processamento recursivo das listas. A função map aplica uma função f a todos os elementos de uma lista e retorna a lista das imagens por f desses elementos. A função filter aplica um predicado p aos elementos de uma lista e retorna a lista dos elementos que satisfazem p. A função exists aplica um predicado p aos elementos de uma lista e retorna true se existe algum elemento que satisfaça p e false caso contrário. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  21. Funções de ordem superior com listas A função all aplica um predicado p aos elementos de uma lista e retorna true se todos os elementos satisfazem p e false caso contrário. A função zip aplica uma função binária e curriedf a duas listas, elemento a elemento, e retorna como resultado a lista das imagens por f desses elementos. As funções accumulate e reduce: accumulate f a [a1, a2, a3, ..., an] = f (... f (f (f a a1) a2) a3 ...) an reduce f a [a1, a2, a3, ..., an] = f a1 (f a2 (f a3 ( ... (f an a)...))) Assim, accumulate calcula em primeiro lugar f a a1 e depois este valor e a2 entram como argumento para a invocação seguinte, etc. A função reduce aplica f aos seus argumentos pela ordem inversa. Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  22. Funções de ordem superior com listas fun map f [] = [] (  )   list   list | map f (a::x) = f a :: map f x val doublelist = map (times 2) fun filter p [] = [] (  bool)   list   list | filter p (a::x) = if p a then a :: filter p x val onlyeven = filter even else filter p x fun exists p [] = false | exists p (a::x) = if p a then true (  bool)   list  bool else exists p x val anyeven = exists even fun all p [] = true (  bool)   list  bool | all p (a::x) = if p a then all p x val alleven = all even else false Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

  23. Funções de ordem superior com listas fun zip f [] [] = [] (    )   list   list   list | zip f (a::x) (b::y)= f a b :: zip f x y | zip f x y error “listas com tamanhos diferentes” fun accumulate f a [] = a (    )     list   | accumulate f a (b::x) = accumulate f (f a b) x fun reduce f a [] = a (    )     list   | reduce f a (b::x) = f b (reduce f a x) Programação em Lógica e Funcional (2000/01) (Actualizado em 2005/06)

More Related