El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

¿Qué es la programación funcional? Una guía práctica

La programación funcional consiste en utilizar las funciones de la mejor manera posible para crear un software limpio y fácil de mantener.

· 7 min de lectura
¿Qué es la programación funcional? Una guía práctica

Este artículo ilustra los conceptos del paradigma funcional con ejemplos prácticos en JavaScript y Java.  Este artículo examina los conceptos en los que se basa la programación funcional y ofrece una comprensión práctica con ejemplos en JavaScript y Java.

Definición de la programación funcional


Las funciones son fundamentales para la organización del código; existen en todos los lenguajes de programación de orden superior. En general, la programación funcional significa utilizar las funciones de la mejor manera posible para crear un software limpio y mantenible. Más concretamente, la programación funcional es un conjunto de enfoques de codificación, que suele describirse como un paradigma de programación.

La programación funcional se define a veces en oposición a la programación orientada a objetos (POO) y a la programación procedimental. Esto es engañoso, ya que estos enfoques no son mutuamente excluyentes y la mayoría de los sistemas tienden a utilizar los tres.

La programación funcional ofrece claras ventajas en determinados casos, se utiliza mucho en muchos lenguajes y marcos de trabajo, y ocupa un lugar destacado en las tendencias actuales del software. Es una herramienta útil y potente que debería formar parte del conjunto de herramientas conceptuales y sintácticas de todo desarrollador.

Funciones puras


El ideal en la programación funcional es lo que se conoce como funciones puras. Una función pura es aquella cuyos resultados dependen únicamente de los parámetros de entrada, y cuya operación no inicia ningún efecto secundario, es decir, no hace ningún impacto externo además del valor de retorno.

Una función pura se reduce únicamente a los argumentos y al valor de retorno (es decir, a su API), puede considerarse un callejón sin salida de la complejidad: Su única interacción con el sistema externo en el que opera es a través de la API definida.

Esto contrasta con la programación orientada a objetos, en la que los métodos de los objetos están diseñados para interactuar con el estado del objeto (los miembros del objeto), y con el código de estilo procedimental, en el que el estado externo suele manipularse desde la función.

Sin embargo, en la práctica real, las funciones a menudo terminan necesitando interactuar con el contexto más amplio, como lo demuestra el hook useEffect de React.

Inmutabilidad


Otro principio de la filosofía de la programación funcional es no modificar los datos fuera de la función. En la práctica, esto significa evitar la modificación de los argumentos de entrada a una función. En su lugar, el valor de retorno de la función debe reflejar el trabajo realizado. Esta es una forma de evitar los efectos secundarios. Hace que sea más fácil razonar sobre los efectos de la función mientras opera dentro del sistema más grande.

Funciones de primera clase


Más allá del ideal de la función pura, en la práctica de la codificación, la programación funcional depende de las funciones de primera clase.

Una función de primera clase es una función que se trata como una "cosa en sí misma", capaz de mantenerse sola y de ser tratada independientemente.

La programación funcional busca aprovechar el soporte del lenguaje en el uso de funciones como variables, argumentos y valores de retorno para crear un código elegante.

Dado que las funciones de primera clase son tan flexibles y útiles, incluso los lenguajes fuertemente OOP como Java y C# han pasado a incorporar el soporte de funciones de primera clase. Ese es el impulso que hay detrás de la compatibilidad de Java 8 con las expresiones Lambda.

Otra forma de describir las funciones de primera clase es la de funciones como datos. Es decir, una función de primera clase puede ser asignada a una variable como cualquier otro dato. Cuando escribes
let myFunc = function(){} estás usando una función como dato.

Funciones de orden superior


Una función que acepta una función como argumento, o que devuelve una función, se conoce como función de orden superior: una función que opera sobre una función.

Tanto JavaScipt como Java han mejorado la sintaxis de las funciones en los últimos años. Java añadió el operador de flecha y el operador de dos puntos dobles. JavaScript ha añadido el operador de flecha.

Estos operadores están diseñados para facilitar la definición y el uso de funciones, especialmente en línea como funciones anónimas. Una función anónima es aquella que se define y utiliza sin que se le dé una variable de referencia.

Ejemplo de programación funcional: Colecciones


Tal vez el ejemplo más destacado en el que brilla la programación funcional es el de las colecciones. Esto se debe a que ser capaz de aplicar trozos de funcionalidad a través de los elementos de una colección es un ajuste natural a la idea de función pura.

Considera el Listado 1, que aprovecha la función map() de JavaScript para poner en mayúsculas las letras de un array.

Listado 1. Uso de map() y una función anónima en JavaScript

let letters = ["a", "b", "c"];
console.info( letters.map((x) => x.toUpperCase()) ); // outputs

El código está muy centrado. No se requiere ningún tipo de pipe, como un bucle y la manipulación de matrices. El proceso de pensamiento de lo que se está haciendo es expresado limpiamente por este código.

Listado 2. Uso de map() y una función anónima en Java

import java.util.*; 
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
//...
List lower = Arrays.asList("a","b","c");
System.out.println(lower.stream().map(s -> s.toUpperCase()).collect(toList())); // outputs ["A", "B", "C"]

El listado 2 hace uso de la biblioteca de flujos de Java 8 para realizar la misma tarea de poner en mayúsculas una lista de letras. Observa el operador de flecha principal es prácticamente idéntica a la de JavaScript, y que hacen lo mismo, es decir, crear una función que acepta argumentos, realiza la lógica y devuelve un valor. (Es importante señalar que si el cuerpo de la función así definida carece de llaves alrededor, entonces el valor de retorno se da automáticamente).

Siguiendo con Java, considere el operador de dos puntos dobles en el Listado 3. Este operador permite referenciar un método de una clase: en este caso, el método toUpperCase de la clase String.

El listado 3 hace lo mismo que el listado 2. Las diferentes sintaxis son útiles para diferentes escenarios.

Listado 3. Operador Java Doble Colon

// ...
List upper = lower.stream().map(String::toUpperCase).collect(toList());

En los tres ejemplos anteriores, se puede ver que las funciones de orden superior están en juego. La función map() en ambos lenguajes acepta una función como argumento.

Dicho de otro modo, se podría considerar el paso de funciones a otras funciones (en la API de matrices o de otro tipo) como interfaces funcionales. Las funciones proveedoras (que consumen las funciones parámetro) son complementos de la lógica generalizada.

Esto se parece mucho a un patrón de estrategia en OOP (y de hecho, en Java, una interfaz con un solo método se genera bajo el capó), pero la compacidad de una función hace un protocolo de componentes muy ajustado.

Como otro ejemplo, considere el Listado 4, que define un manejador de rutas en el framework Express para Node.js.

Listado 4. Manejador de ruta funcional en Express

var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('One Love!');
});

El listado 4 es un buen ejemplo de programación funcional en el sentido de que permite una definición limpia de lo que se requiere exactamente para mapear una ruta y manejar las peticiones y las respuestas, aunque se podría argumentar que la manipulación del objeto respuesta dentro del cuerpo de la función es un efecto secundario.

Funciones currificadas


Consideremos ahora la noción de programación funcional de funciones que devuelven funciones. Esto es menos comúnmente encontrado que las funciones como argumentos. El listado 5 tiene un ejemplo de un patrón común de React, donde se encadena la sintaxis de la flecha gorda.

Listado 5. Una función currificada en React

handleChange = field => e => {
e.preventDefault();
// Handle event
}

El propósito de lo anterior es crear un manejador de eventos que acepte el campo en cuestión, y luego el evento. Esto es útil porque puedes aplicar el mismo handleChange a múltiples campos. En resumen, el mismo manejador es utilizable en múltiples campos.

El listado 5 es un ejemplo de una función currificada. "Función curada" es un nombre un poco frustrante. Hace honor a una persona, lo cual es agradable, pero no describe el concepto, lo cual es confuso. En cualquier caso, la idea es que cuando tienes funciones que devuelven funciones, puedes encadenar llamadas a ellas, de una manera más flexible que creando una única función con múltiples argumentos.

Al llamar a este tipo de funciones, te encontrarás con la distintiva sintaxis de "paréntesis encadenados": handleChange(field)(event).

Programación en lo grande


Los ejemplos anteriores ofrecen una comprensión práctica de la programación funcional en un contexto concreto, pero la programación funcional pretende aportar mayores beneficios a la programación a gran escala. Dicho de otro modo, la programación funcional pretende crear sistemas a gran escala más limpios y resistentes.

Es difícil dar ejemplos de esto, pero un ejemplo del mundo real es el movimiento de React para promover los componentes funcionales.

El equipo de React ha observado que el estilo funcional más conciso de los componentes ofrece beneficios que se agravan a medida que la arquitectura de la interfaz aumenta.

Otro sistema que hace un gran uso de la programación funcional es ReactiveX. Los sistemas a gran escala construidos sobre el tipo de flujos de eventos que utiliza ReactiveX pueden beneficiarse de la interacción de componentes de software desacoplados. Angular adopta completamente ReactiveX (RxJS) en todos los ámbitos como reconocimiento de este poder.

Ámbito y contexto de las variables


Por último, una cuestión que no forma parte necesariamente de la programación funcional como paradigma, pero a la que es muy importante prestar atención cuando se hace programación funcional, es la del ámbito y el contexto de las variables.

En JavaScript, el contexto se refiere específicamente a lo que la palabra clave this resuelve.

En el caso del operador de flecha de JavaScript, se refiere al contexto que lo rodea. Una función definida con la sintaxis tradicional recibe su propio contexto.

Los manejadores de eventos en objetos DOM pueden aprovechar este hecho para asegurarse de que la palabra clave this se refiere al elemento que se está manejando.

Espero que esté articulo pueda haber sido de gran interés para ti y sobre todo de gran ayuda.

Fuente

Plataforma de cursos gratis sobre programación