Programación Funcional: Qué es y en qué se diferencia de otros paradigmas

Una bienvenida funcional

De seguro has escuchado hablar acerca de programación funcional, y lo primero que se te ha venido a la mente son funciones.

!Genial, estás en buen camino!

La programación funcional es un paradigma de programación que muchos de nosotros usamos, incluso sin darnos cuenta.

Se trata de cómo estructuramos nuestro código, y la inmutabilidad de un mundo puro, aunque a veces no tan práctico. 

Se relaciona con:

  • matemáticas y ecuaciones,
  • con efectos secundarios,
  • e incluso viene con un delicioso curry

Veamos en qué se diferencia la programación funcional de la forma en que has estado programando hasta ahora.

Los paradigmas: Imperativo y Declarativo

¿Qué es exactamente un paradigma de programación?

Para responder a eso, te presento a este árbol.

Paradigma imperativo vs declarativo

No es cualquier árbol.

Es uno que muestra cómo los lenguajes de programación se ramifican en diferentes familias, al igual que los lenguajes hablados.

Al mirar las dos ramas más grandes, tenemos:

  • Paradigma imperativo.- Consiste en dar instrucciones explícitas. Básicamente, describe el cómo.
  • Paradigma declarativo.- Consiste en describir nuestro objetivo. Básicamente, el qué queremos lograr.

A medida que avanzamos por cada rama, pasamos de paradigmas de programación más genéricos a paradigmas más específicos.

Cada lenguaje de programación, sigue una receta de 1 o más paradigmas de programación disponibles.

Clasificación de los paradigmas de programación

Y en realidad, existen muchos más paradigmas, además de estas 2 ramas principales.

El paradigma funcional

Aproximadamente a mitad de camino en la rama declarativa, tenemos el paradigma funcional, que describe los conceptos o estilos que diferencian a la programación funcional de otros paradigmas comunes, como:

  • el orientado a objetos, o
  • el procedural.

Funciones como variables

En el núcleo del paradigma funcional tenemos funciones, obviamente.

Y estas funciones deben poder usarse sin restricciones, lo que significa que:

  • podemos pasar funciones a otras funciones, y
  • devolver funciones desde otras funciones.

También podemos mantener referencias a ellas, para su uso posterior.

Closures

También necesitamos poder crear closures, que son funciones que pueden acceder y recordar el ámbito que las rodea.

En una pila de funciones típica, el ámbito de una función se olvida al salir de ella. Pero cuando se crea un closure, ese ámbito permanece en memoria mientras el closure exista.

Esto significa que podemos devolver un closure desde una función principal y seguir teniendo acceso a todos los argumentos y datos a los que también tenía acceso la función principal.

Incluso si llamamos al closure desde un ámbito completamente diferente más adelante.

Más sobre Closures

Los closures son simplemente funciones anónimas que definimos dentro de otras funciones

Lo que hace que los closures sean especiales es el hecho de que siempre pueden acceder a los datos de la función principal que los creó, incluso si los devolvemos y la función principal desaparece. 

Debido a que siempre pueden acceder a su ámbito principal de esta manera, podemos volvernos locos y poner closures dentro de closures, para acceder de regreso a la función que originalmente creó al primer closure.

Su capacidad para almacenar datos de esta manera significa que a veces los closures se asemejan a los objetos.

Ejemplo de Closure en código

Uso funcional

¿Cómo podemos utilizar estas características de manera funcional?

Higher order functions

Podemos comenzar creando algunas funciones de orden superior, que son funciones que trabajan con otras funciones para básicamente realizar una acción. 

Como ejemplos tenemos a filter, sort, y map

Estas funciones de orden superior nos ayudan a crear módulos reutilizables e independientes, que podemos usar en conjunto para escribir nuestro código de manera más declarativa.

Inmutabilidad y side-effects

Los side-effects (o efectos secundarios) ocurren cuando:

  • permitimos que un estado impredecible desde fuera del ámbito de una función lo afecte de alguna manera, o
  • cuando permitimos que una función realice cambios fuera de su ámbito. 

Al eliminar los posibles efectos secundarios, nuestras funciones se vuelven puras, en el sentido de que si los mismos datos ingresan a una función, siempre podemos garantizar que el mismo resultado saldrá sin afectar nada más.

Esto generalmente se hace eliminando la variabilidad de las variables.

Currying y múltiples closures

Por último, podemos usar closures como una forma de encapsular datos y estado.

Hay un concepto importante en la programación funcional llamado "currying". 

Esta técnica divide los múltiples argumentos de una función en sus propias llamadas de función y las encadenamos.

Esto se logra utilizando la memoria de ámbito que tienen los closures, donde cada argumento permanecerá en memoria hasta que se complete la cadena, y obtengamos nuestro resultado.

Ejemplo de Currying en programación funcional

De manera similar, podemos usar closures para crear algo parecido a un objeto.

La primera función en la cadena actúa como una especie de constructor de objetos, y aquí es donde definiríamos la mayor parte de nuestros datos internos. 

Estos datos tienen un ámbito privado para la función constructora y, por lo tanto, están encapsulados en ella. 

Luego podemos devolver un closure para proporcionar acceso externo a estos datos. 

Esto se puede usar para realizar algún cálculo, y almacenar el resultado de operaciones costosas, para no tener que repetirlas. Esto se conoce como memoization.

Podemos incluso, llegar a devolver múltiples closures con nombres, para acceder y manipular los datos internos, de formas más complejas, lo que los hace comportarse aún más como objetos.

Ejemplo de Closure usado como objeto

Un paradigma puramente funcional

De todos modos, estas son solo técnicas que utilizamos en el paradigma funcional. 

Veamos ahora los fundamentos de lo que significa ser puramente funcional.

Entramos en un mundo donde todo es declarativo, determinista, e idealmente inmutable. 

Esto puede no parecer muy útil a primera vista, pero lo cierto es que tiene sus raíces en el mundo matemático y, allí, en realidad tiene mucho sentido. 

Paradigma funcional tiene sus raíces en las matemáticas

En el paradigma puramente funcional, trabajamos principalmente con tipos y expresiones, donde se aplican las siguientes reglas.

Evaluación vs. Ejecución

El código generalmente se evalúa en lugar de ejecutarse, lo que nos brinda algunas formas de optimización interesantes, como la evaluación perezosa (lazy evaluation) y la paralelización automática.

Inmutabilidad estricta

La inmutabilidad se aplica en todas partes, lo que significa que cuando queremos hacer cambios en nuestros datos, lo hacemos calculando una nueva constante, basada en una constante existente.

Mónadas

Y para mantener las funciones puras, el simple hecho de pensar en efectos secundarios es castigable con el tormento más horrible que puedas imaginar. ¡Tener que aprender... MÓNADAS!

Hacemos lo que podemos

Este mundo funcional es hermoso, pero realmente no tanto para los débiles de corazón. 

La mayoría de nosotros, tomamos los frutos más pequeños y accesibles, que cuelgan de la rama puramente funcional, y tratamos de usarlos lo mejor que podemos 🙂.

Beneficios y desventajas

Con todas estas diferencias en mente, ¿por qué usaríamos el paradigma funcional? 

En realidad, aporta muchos beneficios. 

  • La inmutabilidad del paradigma funcional nos obliga a pensar de manera más estricta, sobre cómo pasamos los datos, ayudando a garantizar que los cambios no ocurran inesperadamente. 

  • También nos guía en escribir código legible, que es altamente modular y, por lo tanto, más fácil de mantener.

Sin embargo, esto puede venir con el costo de ser un poquito más difícil de optimizar, dependiendo de dónde estemos usando lo funcional en nuestros proyectos.

Mantén abierta tu mente

Puede ser un desafío interesante hacer la transición a un enfoque más declarativo, si ya estamos acostumbrados a estilos de programación imperativos.

De todos modos, ya sea que te consideres un programador funcional, uno orientado a objetos, o simplemente te guste la simplicidad básica del código procedural:

  • siempre mantén tu mente abierta, y
  • nunca tengas miedo de aprender más. 

Incluso si no terminas usando lo funcional, aprender algo nuevo nunca es una pérdida de tiempo.

Programación y más

¡Esta información también se encuentra disponible en formato de video!

Para apoyar a que continúe compartiendo contenido interesante sobre programación, te agradecería mucho que compartas este artículo. 

Así mismo, si estás interesado en:

  • aprender a desarrollar tu primera página web,
  • aplicación móvil, o en
  • escribir tu primer programa, te invito a registrarte y explorar nuestros cursos.

Ya que llegaste hasta aquí, puedes usar este cupón y acceder a todos los cursos a un precio especial.

Despedida

Espero que te haya parecido interesante aprender más sobre el paradigma funcional, tanto como a mí.

¡Gracias por leer hasta el final!

Si tienes alguna pregunta, recuerda que todas tus dudas son bienvenidas.

# closure # javascript

Logo de Programación y más

Comparte este post si te fue de ayuda 🙂.

Regístrate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Aprende Javascript

Aprende Javascript

Domina JS con este curso práctico y completo! Fundamentos, ejemplos reales, ES6+, POO, Ajax, Webpack, NPM y más.

Iniciar curso
Imagen para el curso Aprende Vue 3

Aprende Vue 3

Nuevo curso! Aprende Vite, Pinia, Vuetify, Vue Router y TypeScript. Desarrolla un eCommerce desde cero.

Iniciar curso
Imagen para el curso Laravel y Vue

Laravel y Vue

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Iniciar curso

Espera un momento ...

¿Te gustaría llevar mi curso de Laravel, gratis?

Sólo debes ingresar tus datos: