Funciones recursivas y de orden superior Paradigmas de programación Grado en Ingeniería del Software Soto Montalvo soto.montalvo@urjc.es (Adaptado por Eduardo G. Pardo) Paradigmas de Programación Grado en Ingeniería del Software Objetivos • Aprender a definir funciones de forma más compacta mediante la recursividad y el orden superior • Aprender a definir funciones anónimas y el concepto de polimorfismo Paradigmas de Programación Grado en Ingeniería del Software GIS 2 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 3 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 4 Funciones recursivas • Una definición se dice que es recursiva si el concepto que se está definiendo participa (aparece) en la definición • Ejemplo: La definición de un factorial de un entero positivo se puede realizar de forma recursiva n! = n*(n-1)*(n-2)*...*2*1 (n-1)! = (n-1)*(n-2)*...*2*1 Entonces: n! = n*(n-1)! Paradigmas de Programación Grado en Ingeniería del Software GIS 5 Funciones recursivas • Ejemplo: cálculo de 3! 3! = 3*2! = 3*2*1! = 3*2*1*0! Por definición: 0! = 1 (Caso base) • De forma general se puede establecer que para el factorial: 1, si n! = n * ( n − 1)!, Paradigmas de Programación Grado en Ingeniería del Software GIS n=0 si n 1 6 Funciones recursivas • En una definición recursiva deben existir obligatoriamente: • Caso(s) base(s): no provocan un nuevo cálculo recursivo, finalizando la recursión, con lo que se puede obtener una solución • Caso(s) recursivo(s): aquéllos que provocan la realización de nuevos cálculos recursivos (sobre datos más “pequeños”) Paradigmas de Programación Grado en Ingeniería del Software GIS 7 Funciones recursivas • En Haskell la función factorial sería: factorial:: Int -> Int factorial n = if n == 0 then 1 else n * factorial (n-1) • Si se combina el uso de patrones con la recursividad la definición de la función queda más compacta factorial:: Int -> Int factorial 0 = 1 factorial n = n * factorial (n-1) Paradigmas de Programación Grado en Ingeniería del Software GIS 8 Funciones recursivas • Tipos de recursividad: • Recursividad lineal: la aplicación de la función contiene una única llamada recursiva • Recursividad no lineal: la aplicación de la función contiene más de una llamada recursiva (conocida también como recursividad múltiple) • Ejemplo: serie de Fibonacci, ya que recursivamente la función se aplica más de una vez 1, si n = 0 n = 1 Fibonacci (n) = Fibonacci( n − 1) + Fibonacci( n − 2), Paradigmas de Programación Grado en Ingeniería del Software GIS si n 2 9 Funciones recursivas • Árbol de llamadas recursivas (Fibonacci(5)) Fib(5) Fib(3) Fib(4) Fib(3) Fib(2) Fib(2) Fib(2) Fib(1) Fib(1) Fib(0) 1 1 Fib(1) 1 Fib(0) 1 1 Paradigmas de Programación Grado en Ingeniería del Software GIS Fib(1) 1 Fib(1) Fib(0) 1 1 10 Funciones recursivas • La recursividad lineal se puede clasificar, a su vez, en: • Recursividad final o de cola: si la llamada recursiva es la operación más externa, es decir, es la última operación que se ejecuta • Recursividad no final: cuando la recursividad es lineal, pero no de cola • Ejemplo: ¿Qué tipo de recursividad tiene el factorial? n! = n*(n-1)! Paradigmas de Programación Grado en Ingeniería del Software GIS (No final) 11 Funciones recursivas • La recursividad final es especialmente interesante ya que conduce a un método sencillo y alternativo de construir programas (técnica de los parámetros de acumulación) • El método consiste en definir una función auxiliar con algún(os) parámetro(s) adicional(es) para calcular el resultado • Los parámetros suelen ser internos para no tener que recordarlos a la hora de usar las funciones Paradigmas de Programación Grado en Ingeniería del Software GIS 12 Funciones recursivas r , si n = 1 fact 2( n, r ) = fact 2( n − 1, n * r ), si n 1 • Ejemplo: factorial fact:: Int -> Int fact n = fact2(n,1) fact2:: (Int,Int) -> Int fact2 (n,r) = if n == 1 then r else fact2(n-1,r*n) Evaluación: fact 4 → fact2(4,1) → fact2(3,4) → fact2(2,12) → fact2(1,24) → 24 (Recursividad final, ya que la llamada recursiva es la última operación que se efectúa) Paradigmas de Programación Grado en Ingeniería del Software GIS 13 Funciones recursivas • En el ejemplo del factorial, en su versión de parámetros de acumulación, el resultado calculado por fact2 es el mismo que el de fact • A su vez, el segundo parámetro de fact2 “acumula” el valor del resultado que se devuelve cuando n=1 Paradigmas de Programación Grado en Ingeniería del Software GIS 14 Funciones recursivas • La técnica de parámetros de acumulación tiene cierta similitud con los bucles en la programación imperativa • Ejemplo: bucle para el cálculo del factorial en Pascal ... r := 1; while n > 1 do Begin r := r*n; n := n-1; end; … Paradigmas de Programación Grado en Ingeniería del Software 15 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 16 Funciones de orden superior • Consiste en tratar a las funciones como datos del lenguaje: • Se pueden tener funciones como argumentos de otras funciones • Se pueden tener funciones como resultado de otras funciones (composición de funciones) • Se pueden tener estructuras de datos que contienen funciones • Ventajas: • Programas más concisos • Programas genéricos • Potenciación de la reutilización Paradigmas de Programación Grado en Ingeniería del Software GIS 17 Funciones de orden superior • Funciones como argumento incremento :: Int -> Int incremento x = x + 1 dosVeces :: (Int -> Int) -> Int -> Int dosVeces f x = f (f x) ModuleName> dosVeces (*3) 2 3 ModuleName> dosVeces doble 18 12 ModuleName> dosVeces incremento 2 4 Paradigmas de Programación Grado en Ingeniería del Software GIS 18 Funciones de orden superior • Funciones como resultado • Se utiliza mucho con la currificación sumac:: Int -> (Int -> Int) sumac x y = x + y ModuleName> sumac 2 3 5 Paradigmas de Programación Grado en Ingeniería del Software GIS 19 Funciones de orden superior • Algunas funciones de orden superior sobre listas: función map • map f xs, obtiene una lista resultado de aplicar la función f a cada elemento de la lista xs ModuleName> map (*2) [3,4,7] [6,8,14] Pruebas1> map even [1..5] [False,True,False,True,False] Paradigmas de Programación Grado en Ingeniería del Software GIS 20 Funciones de orden superior • Algunas funciones de orden superior sobre listas: función filter • filter p xs, devuelve los elementos de la lista que cumplen alguna condición ModuleName>filter even [1..10] [2, 4, 6, 8, 10] Paradigmas de Programación Grado en Ingeniería del Software GIS 21 Funciones de orden superior • Algunas funciones de orden superior sobre listas: función all • all p xs, verifica si todos los elementos de la lista xs cumplen la propiedad p. ModuleName> all even [2,4,8] True ModuleName> all even [1,4,8] False Paradigmas de Programación Grado en Ingeniería del Software GIS 22 Funciones de orden superior • Algunas funciones de orden superior sobre listas: función any • any p xs, verifica si algún elemento de la lista xs cumple la propiedad p. ModuleName> any even [1,2,3] True ModuleName> any even [1,3,5] False Paradigmas de Programación Grado en Ingeniería del Software GIS 23 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Muchas de las funciones que se definen sobre listas siguen el siguiente patrón recursivo: • Si el argumento es la lista vacía, se devuelve cierto valor base (correspondiente al caso base de la definición). • En otro caso, se opera, mediante cierta función u operador (plegador), la cabeza de la lista y una llamada recursiva con la cola de la lista. Paradigmas de Programación Grado en Ingeniería del Software GIS 24 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Ejemplos de funciones sobre listas con patrón similar sumaLista :: [Int] -> Int sumaLista [] = 0 sumaLista (x:xs) = x + sumaLista xs (El valor base es 0 y el plegador es (+)) productoLista :: [Int] -> Int productoLista [] = 1 productoLista (x:xs) = x * productoLista xs (El valor base es 1 y el plegador es (*)) Paradigmas de Programación Grado en Ingeniería del Software GIS 25 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Ejemplos de funciones sobre listas con patrón similar verdad:: [Bool] -> Bool verdad [] = True verdad (x:xs) = x && verdad xs (El valor base es True y el plegador es (&&)) concatenar:: [[Int]] -> [Int] concatenar [] = [] concatenar (sublista:resto) = sublista ++ concatenar resto (El valor base es [] y el plegador es (++)) Paradigmas de Programación Grado en Ingeniería del Software GIS 26 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Esquema básico de la recursión sobre listas es algo como: f [] = valor f (x:xs) = x ’operación’ (f xs) Paradigmas de Programación Grado en Ingeniería del Software GIS 27 Funciones de orden superior • La función foldr hace una abstracción del valor base y el plegador, de forma que: • Recibe como parámetros un operador, un valor inicial y una lista. • Pliega la lista a un único valor colocando el operador entre los elementos de la lista. • Empieza por la derecha con el valor inicial. foldr (+) e [w,x,y,z] es igual al valor de la expresión: (w + (x + (y + (z + e)))) Paradigmas de Programación Grado en Ingeniería del Software GIS 28 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Redefinición de funciones utilizando foldr: sumaLista :: [Int] -> Int sumaLista = foldr (+) 0 > sumaLista [1,2,3] 6 productoLista :: [Int] -> Int productoLista = foldr (*) 1 > productoLista [2,3,2] 12 Paradigmas de Programación Grado en Ingeniería del Software GIS 29 Funciones de orden superior • Función de plegado de listas por la derecha: función foldr • Redefinición de funciones utilizando foldr: verdad :: [Bool] -> Bool verdad = foldr (&&) True > verdad [1<2, False, 3*4<20] False concatenar:: [[Int]] -> [Int] concatenar = foldr (++) [] > concatenar [[1,2],[10],[4,7]] [1,2,10,4,7] Paradigmas de Programación Grado en Ingeniería del Software GIS 30 Funciones de orden superior • Función de plegado de listas por la izquierda: función foldl • Realiza el plegado de la lista de izquierda a derecha • Recibe como parámetros un operador, un valor inicial y una lista. • Pliega la lista a un único valor colocando el operador entre los elementos de la lista • Empieza por la izquierda con el valor inicial foldl op e [x1,x2,x3] ; (((e op x1) op x2) op x3 ModuleName> foldl (-) 3 [2,3,5] -7 Paradigmas de Programación Grado en Ingeniería del Software GIS 31 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 32 Expresiones lambda • Se pueden definir funciones anónimas mediante expresiones lambda (también denominadas – expresiones) x -> x * 2 • En Haskell se escribe \ en lugar de la letra griega lambda \x -> x * 2 ModuleName> (\x -> x * 2) 5 10 • La notación proviene del calculo lambda, en el cual está basado Haskell Paradigmas de Programación Grado en Ingeniería del Software GIS 33 Expresiones lambda • Son muy útiles como argumentos de funciones de Orden Superior dosVeces :: (Int -> Int) -> Int -> Int dosVeces f x = f (f x) ModuleName> dosVeces (\x->x + 1) 20 22 invertirLista :: [Int] -> [Int] invertirLista = foldr (\x lista -> lista ++ [x]) [] ModuleName> invertirLista [1,2,3] [3,2,1] Paradigmas de Programación Grado en Ingeniería del Software GIS 34 Expresiones lambda • Evitan tener que dar nombre a funciones que sólo se van a utilizar una vez impares n = map f [0..n-1] where f x = x * 2 + 1 ModuleName> impares 5 [1,3,5,7,9] odds n = map (\x->x * 2 + 1) [0..n-1] ModuleName> odds 5 [1,3,5,7,9] Paradigmas de Programación Grado en Ingeniería del Software GIS 35 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 36 Polimorfismo • Haskell da la opción de incluir la declaración de cada una de las funciones que definimos en un módulo • Si incluimos la declaración, estamos particularizando el uso de la función a un tipo concreto de dato • Si no incluimos la declaración, la función podrá ser aplicada a todo tipo de dato compatible con las operaciones incluidas en la definición de la función: POLIMORFISMO. • Aumenta la reusabilidad Paradigmas de Programación Grado en Ingeniería del Software GIS 37 Polimorfismo • Se dice que un tipo es polimórfico si en la expresión que lo declara aparece al menos una variable • En Haskell es posible declarar una función usando un tipo genérico que desempeña el papel de cualquier tipo compatible con la definición • Se dice que un tipo es polimórfico si en la expresión que lo declara aparece al menos una variable Paradigmas de Programación Grado en Ingeniería del Software GIS 38 Polimorfismo • Ejemplo: longEntero:: [Int]->Int longEntero []=0 longEntero (_:xs)= 1 + longEntero xs Variable de Tipo (vale cualquier nombre) Paradigmas de Programación Grado en Ingeniería del Software longChar:: [Char]->Int longChar []=0 longChar (_:xs)= 1 + longChar xs longitud:: [a]->Int longitud []=0 longitud (_:xs)= 1 + longitud xs GIS 39 Contenidos 1. Funciones recursivas 2. Funciones de orden superior 3. Expresiones lambda 4. Polimorfismo 5. Bibliografía Paradigmas de Programación Grado en Ingeniería del Software GIS 40 Bibliografía • Haskell: The Craft of Functional Programming (2nd Edition). Simon Thompson. Addison-Wesley. • RAZONANDO CON HASKELL. Un curso sobre programación funcional. Blas Carlos Ruiz, Francisco Gutiérrez, Pablo Guerrero, José E. Gallardo. Ediciones Paraninfo S.A. • Programación Funcional. Jeroen Fokker. Universidad de Utrecht, Departamento de Informática, 1996. • Introducción a la Programación Funcional con Haskell (Segunda edición). R. Bird. Prentice Hall. Paradigmas de Programación Grado en Ingeniería del Software GIS 41