Story
Software
Programacion

¿Qué es la programación funcional?

Álvaro Rojas | 18 de noviembre de 2020

De un tiempo a esta parte, los profesionales del mundo IT, han comenzado a trabajar con la programación funcional o lenguaje funcional. El paradigma de la programación funcional nos presenta una nueva forma de programar de manera declarativa, por la cual esto se parecerá más a escribir donde su premisa principal es que el código sea más intuitivo que nunca.

Qué significa programación funcional

Entendemos por programación funcional un lenguaje de programación declarativo donde el programador especifica lo que quiere hacer, en lugar de lidiar con el estado de los objetos. Es decir, las funciones estarían en un primer lugar y nos centraremos en expresiones que pueden ser asignadas a cualquier variable.

¿Todo esto qué significa? Al escribir el código de forma declarativa, se busca que no juegue con los objetos y sea más legible. Lo normal sería que un desarrollador tuviera que hacer un bucle, iterando y crear una lógica pero, con el lenguaje funcional, este te da funciones que hace que se parezca más a leer y escribir que a programar.

El origen del modelo de programación funcional, pese a ser algo de relativa reciente aceptación, tiene su origen en en el cálculo lambda. El cálculo lambda es un sistema desarrollado en la década de los 30 del siglo XX, donde buscaban investigar la naturaleza de las funciones y la computabilidad.

Entonces, aprendiendo a escribir con lambdas podremos hacer uso de la programación funcional. Antes de continuar, debemos dejar claro que las lambdas no es la única forma de lenguaje funcional pero sí la más extendida y que, por ejemplo, Javascript es la que acepta.

Puedes pensar en una expresión lambda como un método anónimo. Tiene parámetros y un cuerpo como los métodos completos, pero no tiene un nombre como un método real. Las expresiones lambda se conocen como lambdas a secas.

Veamos un ejemplo más claro de cómo funcionan las lambdas. Tenemos un listado de animales, con unas características. Hemos especificado la clase y sus propiedades aquí:

}
class Animal {
   private String species;
   private boolean canSwim;
   private boolean canHop;
   public Animal(String species, boolean canSwim, boolean canHop) {

this.species = species; this.canSwim = canSwim; this.canHop = canHop; } public String getSpecies() { return species; } public boolean canSwim() { return canSwim; } public boolean canHop() {return canHop; } }

Creamos una lista donde añadimos algunos objetos de ejemplo que nos ayudarán a dar forma al código que queremos mostrar.

List<Animal> animals = new ArrayList<>();
   animals.add(new Animal("Fish", true, false));
   animals.add(new Animal("Eagle", false, false));
   animals.add(new Animal("Dog", true, true));
   animals.add(new Animal("Turtle", true, false));
   animals.add(new Animal("Duck", true, false));

Si sobre esta lista de animales, quisiéramos obtener aquellos cuyo nombre comienza por la letra D, podríamos resolver este problema escribiendo un bucle, o de forma funcional en una sola línea. La primera parte del siguiente código, hace todo por nosotros. En ella se hace uso de la función removeIf() que toma un String y devuelve un booleano.

animals.removeIf(s -> s.getSpecies().charAt(0) != 'D');
   animals.forEach(s -> System.out.println(s.getSpecies()));

De esta manera, en un solo paso quitamos todos los elementos que no nos interesan, y en la siguiente línea recorremos todos los elementos restantes para pintar su nombre.

Otra forma de trabajar con programación funcional son los streams. Los streams son, básicamente, una forma por la cual, conseguimos una fuente de datos, realizamos cero o más operaciones intermedias y obtenemos un resultado.

Las partes de un stream pueden separarse en tres grupos:

  • Obtención del stream (la fuente)
  • Hacer el trabajo (las operaciones intermedias)
  • Obtener un resultado (operación finalizada)

Con los streams, podemos obtener de una manera más simple y optimizada cosas que de otra manera nos llevarían más código e iteraciones sobre los datos. Por ejemplo, de nuestra lista de animales anterior ¿cómo obtendrías los 2 primeros elementos que pueden nadar pero no saltar ordenados por nombre?.

Este sería el resultado con un procesamiento de datos simple iterando en un bucle:

List<String> result = new ArrayList<>();
   for (Animal animal : animals) {
       if (!animal.canSwim()) {
           continue;
       }
       if (animal.canHop()) {
           continue;
       }
       result.add(animal.getSpecies());
       if (result.size() == 2) {
           break;
       }
   }
  Collections.sort(result);

Este código es equivalente:

List<String> result =
           animals.stream()
                   .filter(Animal::canSwim)
                   .filter(Predicate.not(Animal::canHop))
                   .limit(2)
                   .map(Animal::getSpecies)
           .sorted()
                   .collect(Collectors.toList());
   System.out.println(result);

}

Tenemos menos código, operaciones más claras, no se apilan bucles y sin variables temporales. De este modo nuestro código refleja lo que queremos hacer con los datos y ya no necesitamos preocuparnos de iteraciones.

Características de la programación funcional

En el lenguaje de programación funcional, contamos con algunas características clave que lo diferencian de otros paradigmas de programación. Algunas de sus características ya las hemos visto pero, en resumen son las siguientes:

  • No existen efectos colaterales: Una función, si tiene todos los parámetros definidos por valor y no se hacen asignaciones a variables globales, no tendrá efectos colaterales.
  • El valor de una lambda no depende de nada más que de los valores de sus subexpresiones, si las tuviera.
  • Tiene una semántica limpia:

    • Únicamente significa lo que dice, es decir, estamos ante un lenguaje declarativo y siempre devolverá el mismo resultado, mientras que el lenguaje imperativo no es así.
    • El almacenamiento de datos es implícito, por lo que las operaciones asignan almacenamiento solo cuando es necesario y luego se libera automáticamente si se vuelve inaccesible.
    • Como señalamos al comienzo, las funciones se vuelven valores de primera clase y estarán al mismo nivel que cualquier otro valor. Una función podrá ser el valor de una expresión, pasarse como argumento y colocarse en una estructura de datos.

Qué lenguajes de programación funcional existen

En la actualidad contamos con un buen puñado de lenguajes funcionales y paradigmas de programación que los aceptan. Aquí te dejamos un listado con los principales lenguajes de programación funcional:

  • LISP
  • ML
  • Haskell
  • OCaml
  • F#
  • Erlang
  • Clojure
  • Scala

Además, existen muchos lenguajes de programación conocidos con los que podremos aplicar modelos de programación funcional entre sus paradigmas:

  • Perl
  • Ruby
  • Visual Basic .NET
  • Dylan
  • Javascript.
  • Python.

Ventajas y desventajas de la programación funcional

Como casi todos los lenguajes, este tiene sus ventajas y desventajas, por ahora ya hemos mencionado alguna de ellas, pero veamos más en detalle:

  • Los programas no cuentan con estados.
  • Es una forma de programar muy adecuada para la paralelización.
  • Es un código fácilmente testable y verificable, incluso en las funciones que no cuentan con estado.
  • Se trata de un código más corto, sencillo, legible y preciso.
  • Fácilmente combinable con la programación orientada a objetos e imperativa.

Ahora veamos los inconvenientes, que también existen algunos importante a tener en cuenta a la hora de adoptar el modelo de programación funcional.

  • Los datos no pueden modificarse, es decir, las variables.
  • No es recomendable usarlo para conexiones de bases de datos y/o servidores. Además, no cuenta con un acceso eficiente a grandes cantidades de datos.
  • No es la mejor opción para recursiones de la misma pila.
  • Podemos tener errores graves en la programación recurrente.

Conclusiones

En definitiva, el lenguaje de programación funcional se trata de una forma de trabajar muy útil en casos determinados, como por ejemplo, si estamos desarrollando un proyecto en el que trabajan varias personas o que heredará otro equipo, porque es una forma muy intuitiva y sencilla de programar.

Opciones para compartir

Álvaro Rojas

Álvaro Rojas es consultant en Incentro España

Póngase en contacto con Álvaro.

siguiente story

Migrando a la nube con Commercetools y Google Cloud. Whitepaper

Ricardo Gala | 11 de noviembre de 2020