Resumen Orden Superior en Funcional

Orden Superior

Tanto en matemática como en informática, se definen las funciones de orden superior como funciones que reciben funciones por parámetro o bien devuelven una función como resultado. Este concepto, como veremos a lo largo de la materia, es de los que tildamos como trasversales, ya que no se da únicamente en el paradigma funcional.


Supongamos que volvemos al dominio de los alumnos y tenemos lo siguiente:

aprueba notas = (notas !! 0 >= 4) && (notas !! 1 >= 4) && (notas !! 2 >= 4)


(recordemos que
lista !! indice 
me devuelve el valor de la lista en ese índice)

El objetivo de esa función es saber si todas las notas son mayores a 4. Si bien hace lo que queremos la solución es bastante criticable porque repite mucho código (sumado a que está limitado a 3 elementos, qué pasa si hay una cantidad variable de elementos?). Lo que podemos hacer es separar el algoritmo de saber si cada nota cumple con la condición que queremos de la condición en sí. Para eso podemos usar una función de orden superior que trae Haskell:


aprueba notas = all esNotaAprobada notas

esNotaAprobada nota = nota >= 4


Iterar la lista para aplicar la función a cada elemento ya no es nuestro problema, de hecho, iterar nunca es un fin sino un medio, se lo podemos delegar al motor y dedicarnos a pensar cosas más interesantes.


Hay muchas funciones de orden superior que nos van a servir para nuestros programas. Algunos ejemplos:

filter: Recibe un criterio y una lista y retorna la lista con aquellos elementos que cumplan el criterio

map: Recibe una función de transformación y una lista y retorna la lista con los resultados de aplicar cada elemento a la transformación

any: Recibe un criterio y una lista y retorna true si algún elemento cumple con el criterio.


Conclusiones de Orden Superior:


  • Puedo aislar y reutilizar comportamiento común.

  • Puedo partir mi problema, separando responsabilidades, entre el código que tiene orden superior, y el comportamiento parametrizado.

  • Puedo tener un código con partes incompletas, esperando rellenarlos pasando comportamiento por parámetro, y no sólo datos.

  • ¡Puedo generar abstracciones más jugosas! Más allá de las abstracciones de orden superior que ya me proveen los lenguajes, la mayoría de los mismos me dan la posibilidad de armar mi propio comportamiento de orden superior

  • Con abstracciones más adecuadas, con responsabilidades repartidas, y sin repetición de lógica, genero un código más expresivo (porque en general es más fácil de leer), y más declarativo (porque en general al usar orden superior oculto detalles algorítmicos)


Variables de tipo

Cuál será el tipo de all? En base al uso vemos que recibe una función como primer argumento y una lista como segundo. Además de eso notamos que existe una relación entre el tipo de los elementos de la lista y el dominio de la función esNotaAprobada, y además el all me pide que la función retorne un Bool, entonces el tipo de all es algo así:


all :: (a -> Bool) -> [a] -> Bool


Las funciones las ponemos entre paréntesis, por ende, por más que haya 3 flechitas, la cantidad de parámetros de all es 2, la función y la lista.


Por qué ponemos a y no Int por ejemplo? nuestras notas no son enteros? Sí, pero el all funciona para listas de cualquier cosa! Lo único que nos pide es que la función que le pasemos reciba algo del tipo de esos elementos para poder pasárselos.


Cuál es el tipo de filter y map en base a lo que sabemos?

filter :: (a -> Bool) -> [a] -> [a]

map :: (a -> b) -> [a] -> [b]


Este grado de libertad hace que sea posible trabajar con cualquier tipo de lista que se nos ocurra sin tener que volver a definir el algoritmo general. A las funciones de este estilo vamos a decir que son polimórficas.
Comments