La creación de software es un proceso muy técnico y desafiante que requiere planificación y elaboración de estrategias para formular la forma correcta de resolver un problema utilizando el software.
En este sentido, considerar el paradigma de programación elegido antes de desarrollar cualquier software es un paso importante.
Un paradigma de programación es un modelo o enfoque hacia la programación que proporciona características, patrones, principios, reglas y estilos de diseño, estructuración y escritura de programas informáticos.
Algunos ejemplos de paradigmas de programación populares son la programación orientada a objetos (POO), la programación procedimental, la programación dirigida por eventos y la programación funcional, entre otros.
La programación funcional, en particular, ha estado recibiendo mucha atención en los últimos tiempos, ya que promete un código con menos errores, altamente reutilizable y fácil de mantener. Entonces, ¿qué es la programación funcional?
La programación funcional es un subparadigma del paradigma de la programación declarativa. La programación declarativa es un paradigma que se centra en escribir código que describa lo que debe hacer un programa en lugar de cómo debe hacerlo el programa.
Un ejemplo de esto puede verse cuando se consultan datos en bases de datos SQL. En lugar de decir explícitamente cómo quiere que se recuperen, lo único que especifica son los datos que quiere que se recuperen.
La programación funcional propiamente dicha es un paradigma para construir programas informáticos utilizando expresiones y funciones puras que se aplican en secuencia para resolver problemas o lograr los resultados deseados.
En la programación funcional, toda la funcionalidad de un programa se divide en funciones puras reutilizables y de responsabilidad única. Todo en el programa ocurre mediante el uso de funciones puras.
Una función pura es una función determinista que, cuando se le dan los mismos valores de entrada, devolverá la misma salida y no afectará a ninguna otra parte de las aplicaciones.
Por tanto, el resultado de una función pura depende únicamente de su entrada y no de una variable global de la aplicación que pueda alterar los resultados de la función.
Estas funciones puras reciben entradas, las procesan localmente y producen una salida sin alterar ninguna otra parte del programa.
La programación funcional utiliza datos inmutables, es decir, que no pueden modificarse una vez creados, y también evita los estados compartidos, en los que los mismos datos pueden ser accedidos y modificados por distintas partes de un programa.
Dado que la programación funcional se basa en gran medida en funciones, éstas se denominan ciudadanos de primera clase, lo que significa que pueden pasarse como argumento, guardarse en una variable y también devolverse desde otra función.
Además, la programación funcional se basa en gran medida en expresiones en lugar de sentencias y, por lo tanto, evita las sentencias de bucle como for y while. Esto se hace para que la lógica del programa sea fácil de seguir y depurar.
Tipos de lenguajes de programación funcional
Existen dos tipos principales de lenguajes de programación funcional. Entre ellos se incluyen:
- Lenguajes puramente funcionales – Son lenguajes de programación que apoyan, imponen y promueven el uso de paradigmas funcionales como el uso de funciones puras de primera clase, la inmutabilidad de estados y datos, y funciones que no tienen efectos secundarios en otras partes del programa. Algunos ejemplos de lenguajes puramente funcionales son Haskell, Agda, Clean, Idris, Futhark y Elm, entre otros.
- Lenguajes funcionales impuros – Son lenguajes que tienen soporte para paradigmas de programación funcional pero que también permiten el uso de funciones impuras, mutaciones del estado de un programa y operaciones que tienen efectos secundarios. Algunos ejemplos de lenguajes funcionales impuros son Javascript, Rust, Erlang, Python, Ruby, Java, Kotlin y Clojure, entre otros.
Tanto los lenguajes puramente funcionales como los funcionales impuros son utilizados por los desarrolladores. Sin embargo, pasarse a un lenguaje puramente funcional puede llevarle mucho tiempo y esfuerzo si nunca antes ha utilizado la programación funcional.
Lenguajes y bibliotecas de programación funcional
Algunos lenguajes y bibliotecas de programación funcional populares son:
#1. Haskell
Haskell es un lenguaje de programación estáticamente tipado, perezoso y puramente funcional que se considera la encarnación del paradigma de programación funcional.
Además de la inferencia de tipos, el lenguaje ofrece soporte para la evaluación perezosa, en la que las expresiones sólo se evalúan cuando se necesitan sus resultados. Haskell también ofrece soporte para la programación concurrente, y su compilación viene con un recolector de basura de alto rendimiento y una biblioteca de concurrencia ligera.
Gracias a su uso y a su estricto cumplimiento de los principios de la programación funcional, Haskell puede facilitar la construcción de sistemas de software complejos y también su mantenimiento.
Entre muchos actores de la industria, Haskell es el lenguaje al que se acude cuando se construyen sistemas autónomos o lenguajes específicos de dominio. También tiene un amplio uso en el mundo académico y en la investigación. Algunas empresas que utilizan Haskell son Microsoft, Github, Hasura y Lumi, entre muchas otras.
#2. Ramda
Ramda es una biblioteca de programación funcional para el lenguaje JavaScript. Ramda simplifica la construcción de lógica compleja a través de la composición funcional y proporciona un conjunto de funciones de utilidad que fomentan y apoyan el uso de los principios de programación funcional en JavaScript.
Ramda también proporciona una forma sencilla de utilizar objetos inmutables y funciones sin efectos secundarios, que son conceptos clave en la programación funcional.
Dado que JavaScript no es un lenguaje de programación puramente funcional como Haskell, mediante el uso de una biblioteca como Ramda, puede utilizar la programación funcional y cosechar los beneficios de rendimiento de la programación funcional mientras utiliza JavaScript.
#3. Elixir
Elixir es un lenguaje de programación funcional, concurrente y de propósito general que está diseñado para ser escalable, fácil de mantener y también tolerante a fallos. El lenguaje fue creado en 2011 por José Valim, se ejecuta en la máquina virtual BEAM, y es utilizado por empresas como Heroku, Discord, change.org, y Duffel, entre otros.
Al ser un lenguaje de programación funcional, Elixir fomenta la inmutabilidad de estados y datos, el uso de funciones puras al escribir código y la transformación de datos.
Conceptos clave de la programación funcional
#1. Funciones puras
La programación funcional hace un uso extensivo de las funciones puras. Las funciones puras tienen dos características principales. En primer lugar, producen la misma salida para la misma entrada independientemente de cualquier factor externo, lo que las hace deterministas por naturaleza y, por tanto, predecibles.
En segundo lugar, las funciones puras no tienen efectos secundarios. Es decir, no modifican en modo alguno el entorno externo fuera de su ámbito.
Algunos ejemplos de funciones puras son
//función para calcular el cuadrado de un número
función cuadrado(x) {
devuelve x * x
}
//función para sumar dos variables
función sumar(a, b) {
return a b
}
Las funciones anteriores devuelven la misma salida para las mismas entradas y no tienen efectos secundarios fuera de su ámbito.
#2. Inmutabilidad
En la programación funcional, los datos utilizados son inmutables. Esto significa que una vez que las variables han sido inicializadas, no pueden ser modificadas. Esto garantiza la conservación del estado de una variable a lo largo de todo el programa.
En caso de que quiera hacer alguna modificación en la variable o realizar una operación sobre ella, puede crear una nueva variable para almacenar los datos actualizados sin alterar la variable inicial.
#3. Funciones de orden superior
Las funciones de orden superior son funciones que aceptan una o más funciones como argumentos y/o devuelven una función.
Las funciones de orden superior son útiles en la programación funcional ya que permiten combinar múltiples funciones para crear nuevas funciones, permiten el uso de retrollamadas, permiten la abstracción de patrones comunes en funciones reutilizables y, por último, las funciones de orden superior permiten escribir código más conciso y expresivo.
A continuación se muestra un ejemplo de función de orden superior:
// Una función de orden superior que devuelve una función que multiplica
// un número por un factor dado
función multiplicador(factor) {
return función (número) {
devuelve número * factor;
}
}
const doble = multiplicador(2)
const triple = multiplicador(3)
const cuádruple = multiplicador(4);
console.log(doble(5)); // Salida: 10
console.log(triple(5)); // Salida: 15
console.log(cuádruple(5)); // Salida: 20
#4. Recursión
Dado que la programación funcional se basa en expresiones en lugar de sentencias, en este paradigma se evitan las sentencias de flujo de control como los bucles for y while. Estas sentencias de bucle se sustituyen, a su vez, por la recursión, que es lo que se utiliza para realizar iteraciones en la programación funcional.
La recursividad consiste en que una función se llame a sí misma repetidamente hasta que se cumpla una condición de salida. Utilizando la recursividad, un problema complejo se descompone en subproblemas más pequeños y sencillos que se resuelven de forma recursiva hasta que se alcanza un caso base que proporciona una solución al problema complejo mayor.
#5. Programación declarativa
La programación funcional es un subparadigma dentro del paradigma más amplio de la programación declarativa, que engloba los paradigmas de programación que se centran en escribir código en términos de lo que hay que hacer en lugar de indicar explícitamente cómo hacerlo.
En ese sentido, cuando se utiliza el paradigma de programación funcional, su código debe describir lo que hay que conseguir o el problema que hay que resolver.
La forma de lograrlo depende del lenguaje de programación que utilice. Esto ayuda a escribir un código más conciso y fácil de leer.
#6. Sin estado
La programación funcional hace hincapié en el código sin estado, en el que el código no mantiene un estado global que pueda ser modificado por las funciones. Los resultados de las funciones dependen únicamente de la entrada pasada y no pueden verse influidos por dependencias de otras partes del código.
Las funciones utilizadas no pueden modificar un estado o variable del programa que esté fuera de su ámbito.
#7. Ejecución paralela
Dado que la programación funcional utiliza estados inmutables, usa funciones puras y datos inmutables, permite la ejecución en paralelo de múltiples cálculos simultáneamente.
Dado que cada función sólo tiene que tratar con una entrada determinada sin preocuparse de incurrir en efectos secundarios de otras partes del programa, los problemas complejos pueden dividirse en subproblemas más pequeños y ejecutarse simultáneamente en paralelo, lo que permite mejorar el rendimiento y la eficiencia.
Ventajas de la programación funcional
Algunos de los beneficios de la programación funcional son
Menos errores de software
Aparte de que el código que implementa el paradigma de la programación funcional es más legible y fácil de entender debido al uso de funciones puras, la programación funcional permite escribir código con menos errores.
Dado que la programación funcional trabaja con estados inmutables, nunca hay varias partes de un programa que alteren el estado de una variable o de todo el programa. Esto, a su vez, se traduce en menos errores que podrían haber surgido por la modificación de datos desde múltiples áreas debido a los estados compartidos.
Mejora la legibilidad del código
La programación funcional es un subparadigma del paradigma declarativo, que hace hincapié en escribir código que describa lo que hay que hacer en lugar de cómo hacerlo. Esto, unido al uso de funciones puras, da como resultado un código que se explica por sí mismo, más fácil de leer y comprender, y fácil de mantener.
Mejora la reutilización del código
La aplicación de la programación funcional requiere dividir los problemas complejos en subproblemas más pequeños y resolver estos problemas utilizando funciones puras. Estas funciones pueden componerse y reutilizarse fácilmente para resolver otros problemas complejos. Mediante el uso de funciones puras y estados inmutables, la programación funcional permite escribir código altamente reutilizable.
Pruebas y depuración más sencillas
La programación funcional utiliza funciones puras que no tienen efectos secundarios, sólo dependen de sus entradas y producen salidas deterministas consistentes para el mismo conjunto de entradas.
Esto hace que la programación funcional sea intrínsecamente fácil de probar y depurar, ya que no es necesario realizar un seguimiento de una variable y de cómo cambia a lo largo de las diferentes partes de un programa.
Dado que no existen dependencias en la programación funcional, la depuración y las pruebas resultan más sencillas, ya que puede dirigirse a partes específicas de un programa.
Admite la concurrencia y el paralelismo
Dado que la programación funcional fomenta la ausencia de estado y la inmutabilidad de los datos, hace posible la ejecución segura de múltiples funciones puras en paralelo o de forma concurrente. La capacidad de ejecutar múltiples operaciones en paralelo se traduce en una mayor velocidad de procesamiento y un mejor aprovechamiento de los procesadores con varios núcleos.
Como paradigma de programación, la programación funcional puede ayudar a escribir un código más legible y fácil de entender, con menos errores y un excelente soporte para el paralelismo, lo que permite un uso eficiente de los procesadores multinúcleo. La programación funcional permite construir sistemas de software más fiables y fáciles de escalar.
Limitaciones de la programación funcional
Aunque la programación funcional tiene mucho que ofrecer, viene con una curva de aprendizaje que requiere que los desarrolladores inviertan mucho tiempo y esfuerzo en aprender a utilizar el paradigma. Esto se debe a que introduce nuevas formas de estructurar el código y nuevos conceptos de programación.
La codificación mediante programación funcional puede ser extremadamente compleja y difícil, ya que no utiliza características más intuitivas como los bucles for y while. Escribir programas de forma recursiva no es fácil.
Como resultado, los desarrolladores pueden tardar más en dominar la programación funcional, sobre todo cuando proceden de lenguajes que utilizan estados mutables, como en la programación orientada a objetos.
Otra limitación de la programación funcional surge de su principio básico de inmutabilidad. Dado que los datos y los estados son mutables, y que se crean nuevas estructuras de datos en lugar de modificar las existentes, esto hace que la programación funcional utilice más espacio de almacenamiento. La naturaleza inmutable de la programación funcional también puede traducirse en un menor rendimiento de las aplicaciones.
Conclusión
Aunque la programación funcional existe desde hace mucho tiempo, se ha convertido en un paradigma de moda en los últimos tiempos. Por mucho que pueda resultar un poco difícil de asimilar, los desarrolladores pueden beneficiarse enormemente del aprendizaje de este paradigma y de las distintas formas en que pueden implementar la programación funcional al escribir programas.
Dado que no necesita utilizar lenguajes de programación puramente funcionales como Haskell, puede implementar conceptos de programación funcional en lenguajes como Javascript, Java, Python y Kotlin y cosechar los beneficios de la programación funcional en sus proyectos.
También puede explorar algunos recursos para aprender Python para principiantes.