Skip to main content

Programación funcional

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/functional-programming-kt
Si quieres seguir el código del tutorial puedes comenzar desde este punto

Si tienes gh instalado, puedes obtener el código haciendo:

gh repo clone r8vnhill/functional-programming-kt
cd functional-programming-kt || exit
git checkout base

Si quieres tener tu propia copia del código, puedes hacer un fork del repositorio y clonarlo desde tu cuenta de GitHub.

gh repo fork r8vnhill/functional-programming-kt
cd functional-programming-kt || exit
git checkout --track origin/base
Cambia la propiedad group en gradle.properties
Recuerda cambiar la propiedad .group en el archivo gradle.properties por tu nombre de dominio.

Comencemos por definir una tarea base para esta unidad...

Primero definiremos una tarea reutilizable para esta unidad, no te dejes intimidar por la cantidad de código, es solo una plantilla para crear módulos en el proyecto que ya viene incluido en el repositorio. Sin embargo, comprender cómo funciona puede ser útil como práctica y repaso sobre tareas de Gradle.

abstract class ModuleSetupTask @Inject constructor(
private val layout: ProjectLayout
) : DefaultTask() {
init {
group = "setup"
}
}
¿Qué acabamos de hacer?

Esta clase define una tarea personalizada que hereda de DefaultTask, como es habitual en Gradle.

Justo después del nombre de la clase, aparece una sección que empieza con @Inject constructor(...). Esto indica que la tarea necesita ciertos datos para funcionar, y que Gradle se encargará de proporcionarlos automáticamente. A esto se le llama inyección de dependencias.

En este caso, lo que Gradle entrega es una instancia de ProjectLayout, un objeto que ofrece una forma segura de acceder a carpetas y archivos dentro del proyecto.

Usar ProjectLayout en lugar de acceder directamente con project.file(...) es importante porque mejora la compatibilidad con el configuration cache, una característica de Gradle que permite acelerar las compilaciones.

Finalmente, la línea group = "setup" simplemente indica que esta tarea forma parte del grupo de tareas de configuración, lo cual ayuda a organizarla mejor cuando se listan las tareas con gradle tasks.

La programación funcional es un paradigma de desarrollo de software que se centra en construir programas mediante la aplicación y composición de funciones puras. A diferencia de la programación imperativa, que se enfoca en el cómo realizar una tarea a través de la modificación de estados y el control de flujo, la programación funcional adopta un enfoque más declarativo, especificando qué debe hacerse sin detallar los pasos exactos. En lugar de modificar el estado del programa, se utilizan funciones que transforman datos inmutables, facilitando el razonamiento y la predictibilidad del código.

Conceptos Clave

  • Funciones Puras: Son funciones que, dado el mismo input, siempre producen el mismo output y no tienen efectos secundarios ni dependen de estados externos.
  • Inmutabilidad: Una vez que se crea un dato, no cambia. En lugar de modificar estructuras existentes, se crean nuevas con las modificaciones necesarias.
  • Funciones de Orden Superior: Funciones que pueden recibir otras funciones como argumentos y/o retornarlas como resultados.
  • Composición de Funciones: Técnica para combinar funciones simples y construir operaciones más complejas de manera modular.
  • Evaluación Perezosa: Las expresiones se evalúan solo cuando su valor es necesario, lo que puede mejorar la eficiencia y permitir estructuras de datos infinitas.

Orígenes

Este paradigma tiene sus raíces en el cálculo lambda, un sistema formal desarrollado por Alonzo Church en la década de 1930 que trata las funciones como entidades de primera clase. Aunque inicialmente no fue tan popular como la programación imperativa, hoy en día la programación funcional es ampliamente utilizada tanto en la industria como en la academia debido a sus beneficios en claridad, mantenibilidad y facilidad para la paralelización del código.

Lenguajes Funcionales Populares

Algunos lenguajes diseñados específicamente para la programación funcional incluyen:

  • Haskell: Conocido por su fuerte sistema de tipos estático y la pureza de sus funciones.
  • Lisp y sus dialectos como Scheme y Clojure: Pioneros en la programación funcional con una sintaxis basada en listas.
  • OCaml y F#: Lenguajes que combinan programación funcional con características imperativas y orientadas a objetos.
  • Erlang y Elixir: Utilizados especialmente en sistemas distribuidos y concurrentes, enfatizando la tolerancia a fallos y la escalabilidad.

Influencia en Otros Lenguajes

Muchos lenguajes de programación no funcionales han incorporado características funcionales en sus últimas versiones:

  • JavaScript: Soporta funciones de primera clase, clausuras y funciones de orden superior, permitiendo un estilo funcional.
  • Python: Incluye funciones anónimas (lambdas) y funciones integradas como map, filter y reduce.
  • Java: Desde la versión 8, introdujo expresiones lambda y el API de Streams para procesamiento funcional de datos.
  • C#: Incorpora expresiones lambda y LINQ para consultas y transformaciones de datos de manera declarativa.
  • Kotlin: Soporta funciones de primera clase, lambdas y una rica biblioteca funcional, promoviendo la inmutabilidad y la programación funcional.

Incluso lenguajes tradicionalmente imperativos como C++ han adoptado características funcionales, como funciones lambda y expresiones funcionales, para mejorar la expresividad y modularidad del código.

Beneficios de la Programación Funcional
  • Código Más Predecible: Al evitar efectos secundarios, es más fácil razonar sobre el comportamiento del código.
  • Facilita el Paralelismo y la Concurrencia: La inmutabilidad reduce problemas asociados con estados compartidos en entornos concurrentes.
  • Reutilización y Composición: Las funciones puras y la composición facilitan la creación de código modular y reutilizable.
  • Menor Propensión a Errores: Al minimizar cambios de estado y efectos secundarios, se reducen los bugs difíciles de detectar.

¿Qué Aprendimos?

En esta lección, exploramos la programación funcional, un paradigma que se centra en la aplicación y composición de funciones puras para evitar efectos secundarios y cambios de estado. Vimos cómo este enfoque declarativo contrasta con la programación imperativa al priorizar la transformación de datos inmutables y la creación de funciones previsibles.

Aprendimos también sobre:

  • Funciones puras: Garantizan el mismo resultado para un input dado sin alterar estados externos.
  • Inmutabilidad: Los datos no cambian una vez creados, lo que mejora la predictibilidad.
  • Funciones de orden superior: Permiten tratar las funciones como valores, facilitando la composición.
  • Evaluación perezosa: Optimiza el rendimiento evaluando expresiones solo cuando es necesario.

Además, exploramos los lenguajes funcionales más destacados como Haskell y Clojure, y vimos cómo lenguajes tradicionales como JavaScript y Python han adoptado características funcionales.

Finalmente, discutimos los beneficios clave de la programación funcional, tales como su capacidad para facilitar el paralelismo, reducir errores, y mejorar la modularidad y reutilización del código.

Bibliografías Recomendadas

  • 📚 "What is functional programming?". (2023). en Functional programming in Kotlin, (pp. 3–16.) Manning Publications Co.
  • 📚 "Styles". (2024). en API Design for C++, (Second edition, pp. 179–207.) Morgan Kaufmann.

Bibliografías Adicionales