Introducci贸n a programaci贸n funcional

Introducci贸n a programaci贸n funcional

Origen

El origen de la programaci贸n funcional data del a帽o 1936, cuando un matem谩tico llamado Alonzo Church necesitaba resolver un problema complejo, del cual no hablaremos aqu铆, pero Alonzo cre贸 una soluci贸n, el c谩lculo lambda. De esta forma naci贸 la programaci贸n funcional, incluso mucho antes de la primera computadora digital programable y de los primeros programas escritos en ensamblador.

La programaci贸n funcional es mucho m谩s antigua que la programaci贸n estructurada y la programaci贸n orientada a objetos. Te recomiendo tambi茅n revisar esta informaci贸n sobre el paradigma de programaci贸n funcional.

Sin efectos colaterales

Todo lo que necesitas saber sobre programaci贸n funcional es que "No tiene efectos colaterales", es decir, que sus elementos (funciones) son inmutables.

Lo anterior significa que una funci贸n no se mete en lo absoluto con datos que existen fuera de ella, si puede utilizar los datos enviados como par谩metros, pero no debe modificarlos, todos los datos deben ser inmutables, 驴Por qu茅?, pues porque as铆 hacemos las cosas m谩s simples y con menos errores, m谩s adelante tenemos un ejemplo. A este comportamiento se le llama puro.

Sin efectos colaterales nos permite entender todas las dem谩s caracter铆sticas de la programaci贸n funcional, por mencionar algunas principales:

  • Funciones puras
  • Inmutabilidad
  • Funciones de alto nivel
  • Funciones currificadas
  • Recursividad
  • Menos errores de programaci贸n porque no realiza efectos colaterales.

Toda funci贸n teniendo ciertos par谩metros, cuando se ejecuta, obtendremos un resultado basado en esos par谩metros, y si volvemos a utilizar los mismos parametros, entonces la funci贸n regresara el mismo valor. Esto es debido a que una funci贸n no depende de m谩s datos externos que puedan ser modificados, as铆 tendremos m谩s seguridad y nuestro c贸digo se vuelve m谩s entendible.

Javascript es un lenguaje de programaci贸n muy potente y multiparadigma, soporta el paradigma funcional y lo utilizaremos para nuestros ejemplos.

Funciones puras e inmutabilidad

Bueno, realmente ya explicamos de manera indirecta que es una funci贸n pura en los p谩rrafos anteriores, pero veamos una definici贸n formal. Una funci贸n pura es la que cumple con estas dos caracter铆sticas:

  1. Siempre obtendremos el mismo resultado dado los mismos par谩metros de entrada.
  2. No tiene ning煤n efecto colateral observable, no modifica el estado de los datos externos, por lo que todos los datos deben ser inmutables.

Un ejemplo de como cambiar el nombre de una objeto persona usando primero una funci贸n con efector colaterales:

function cambiarNombre(nombre) {
  persona.nombre = nombre;
}

const jaime = { nombre: 'Jaime', edad: 30 };
cambiarNombre('Juan')
console.log(jaime); // { nombre: 'Juan', edad: 30 }

En la anterior funci贸n notamos que se cambia objeto jaime, el cual supongamos que es parte del estado de nuestra aplicaci贸n, pero puede haber otras funciones que utilicen este objeto, por lo que se puede generar problemas si alguien m谩s espera que la propiedad nombre del objeto siga siendo 'jaime'.

Ahora veamos la versi贸n funcional de la funci贸n:

function cambiarNombre(nombre, persona) {
  return {
    nombre: nombre,
    edad: persona.edad
  }
}

const jaime = { nombre: 'Jaime', edad: 30 };
const juan = cambiarNombre('Juan', jaime);

console.log(jaime); // { nombre: 'Jaime', edad: 30 }
console.log(juan); // { nombre: 'Juan', edad: 30 }

En la versi贸n funcional, cambiarNombre no modifica el objeto jaime, m谩s bien crea un nuevo objeto con la misma edad que jaime y con la propiedad nombre igual a 'Juan', con esto evitamos efectos colaterales por si el objeto jaime es utilizado por otra funci贸n u otro programador.

Con esta funci贸n sin efecto colateral, nos damos cuenta de que los datos se manejan sin ser modificados, es decir, inmutables, los par谩metros persona y nombre nunca fueron cambiados.

Funciones de alto nivel y currificadas

Una funci贸n de alto nivel es una funci贸n que implementa al menos una de las opciones siguientes:

  • Recibir como par谩metro una o m谩s funciones
  • Regresar como resultado una funci贸n

Un ejemplo muy com煤n usado en nuestro navegador web es agregar escuchadores de eventos:

<button id="boton">Soy un bot贸n</button>

const boton = document.querySelector('#boton');
boton.addEventListener('click', function () {
  alert('Click sobre el boton');
});

En el c贸digo pasamos como segundo par谩metro del m茅todo addEventListener una funci贸n an贸nima (sin nombre) que mostrar谩 un alerta al dar click sobre un bot贸n con id igual a 'bot贸n'. Dado que pasamos por par谩metro una funci贸n, entonces se dice que es una funci贸n de alto nivel.

Otro ejemplo de funci贸n de alto nivel lo podemos observar en los m茅todos de arreglos en Javascript, el c贸digo de abajo toma un arreglo de n煤meros y crea otro arreglo con los valores aumentados al doble.

See the Pen Funciones de alto nivel by Jaime Cervantes Velasco (@jaime_cervantes_ve) on CodePen.

La funci贸n map retorna un nuevo arreglo, no cambia el arreglo original, por lo que decimos que no existe un efecto colateral.

Las funciones currificadas son funciones de alto nivel que como resultado regresan otra funci贸n, de tal manera que el acto de currificar es convertir una funci贸n de m谩s de un par谩metro en dos o m谩s funciones que reciben parcialmente esos par谩metros en dos o m谩s invocaciones currificadas.

See the Pen Funciones de alto nivel y funciones currificadas by Jaime Cervantes Velasco (@jaime_cervantes_ve) on CodePen.

Las funciones flecha o arrow functions nos permiten acceder al contexto de los par谩metros, es por eso que seguimos teniendo acceso al par谩metro a de la primera invocaci贸n de summaryCurry. De esta manera cuando se les define un valor, una arrow function puede ver ese valor. Para lograr lo mismo sin funciones flecha se debe utilizar la variable arguments que existe como variable local dentro de todas las funciones en JavaScript. Para mantener las cosas simples, de momento no veremos como hacerlo con arguments.

Funci贸n recursiva

Para crear una funci贸n recursiva, primero se define un caso base, luego a trav茅s de la divisi贸n del problema en pedazos m谩s peque帽os se encuentra un patr贸n, este patr贸n llamado caso recursivo se repite muchas veces, es aqu铆 donde la funci贸n se llama as铆 misma y acumula los resultados, la ejecuci贸n se detiene hasta llegar a su caso base.

  1. El caso base, el cual permite detener la ejecuci贸n de subsecuentes invocaciones de la funci贸n recursiva.
  2. El caso recursivo, el cual permite que una funci贸n se llame a s铆 misma hasta llegar al caso base.

El factorial de un n煤mero positivo es la multiplicaci贸n de ese n煤mero por el n煤mero inmediato menor y as铆 sucesivamente hasta llegar al n煤mero 1, su notaci贸n es n!, donde n es un n煤mero positivo. Por ejemplo el factorial de 5 es 120, 5! = 5 x 4 x 3 x 2 x 1 = 120.

// caso base: 1! = 1 = 1 // caso recursivo, ejemplos: 2! = 2 x 1 = 2 x 1! 3! = 3 x 2 x 1 = 3 x 2! 4! = 4 x 3 x 2 x 1 = 4 x 3! 5! = 5 x 4 x 3 x 2 x 1 = 5 x 4!

Con estos datos, podemos crear nuestra formula factorial(n) = n * factorial(n-1), lo cual seria nuestro caso recursivo, pero debemos de a帽adir nuestro caso base para que se detenga, cuando n=1 debemos obtener como resultado 1.

Veamos como quedar铆a nuestra funci贸n recursiva en javascript:

See the Pen Funciones recursivas by Jaime Cervantes Velasco (@jaime_cervantes_ve) on CodePen.

Con esto cubrimos las cualidades principales de la programaci贸n funcional, pero recuerda, lo m谩s importante es que NO existen efectos colaterales.

Podr铆a interesarte

驴C贸mo crear un servidor web en 5 minutos con Node.js?

Para crear un servidor web en node.js, primero, 驴Qu茅 es node.js?, tomando la definici贸n del sitio oficial, es un entorno de ejecuci贸n para JavaScript construido con el motor de JavaScript V8 de Chrome. Node.js usa un modelo de operaciones E/S sin bloqueo y orientado a eventos, que lo hace liviano y eficiente. El ecosistema de paquetes de Node.js, npm, es el ecosistema m谩s grande de librer铆as de c贸digo abierto en el mundo.