DEV Community

Cover image for Repasando Artículos: Why Functional Programming Matters
Gustavo Preciado
Gustavo Preciado

Posted on • Updated on • Originally published at gitlab.com

Repasando Artículos: Why Functional Programming Matters

D. Turner, Addison-Wesley, 1990

Con el tiempo el software ha aumentado en complejidad y cada vez es mas evidente la importancia de la modularidad para garantizar la calidad y facilitar el mantenimiento del código, debido a que un modulo pequeño es mas fácil de desarrollar, reusar y probar; sin embargo la modularidad genera una nueva necesidad que consiste en mejorar el "glue code" que consiste en el código utilizado para unir los diferentes módulos. Las principales ventajas de la programación funcional apuntan a mejorar la modularización haciendo que cada modulo sea mas fácil de reusar y de probar gracias a la transparencia referencial y uniéndolos mas eficientemente con la implementación de funciones de orden superior y evaluación perezosa.

Los ejemplos de código están escritos en JAVA utilizando la librería de VAVR que implementa una gran parte de las características de la programación funcional.

Transparencia referencial

En la programación funcional las funciones comparten su definición con las funciones matemáticas, una de las principales características de estas es que para un parámetro de entrada determinado siempre retornara el mismo valor en otras palabras eliminan los efectos colaterales presentes en otros paradigmas de programación. Esto tiene como resultado que el llamado a una función pueda ser remplazado por su valor sin tener consecuencia por el orden de ejecución u algún otro factor implícito del contexto de ejecución, esto fuerza la creación de módulos mas fáciles de comprender, reusar y probar.

Funciones de orden superior

Las funciones de orden superior son aquellas que reciben o retornan una o mas funciones, esto permite la reutilización de código y la generalización de algunos comportamientos para diferentes tipos de datos, los cuales solo deberán reescribir las funciones base que definan su comportamiento especifico, así como un "glue code" mas corto y facil de comprender. Un ejemplo básico de las funciones de orden superior es la función foldLeft que permite combinar todos los elementos de una lista en unico elemento resultado de la aplicar repetidamente una función cualquiera que reciba como parámetro objetos del tipo de los elementos de la lista.


  public static void main(String[] args) {
      List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
      Integer r = list.foldLeft(0, Integer::sum); // 45
  }


  //codigo de la funcion foldLeft tomado del código fuente de vavr
  default <U> U foldLeft(U zero, BiFunction<? super U, ? super T, ? extends U> f) {
        Objects.requireNonNull(f, "f is null");
        U xs = zero;
        for (T x : this) {
            xs = f.apply(xs, x);
        }
        return xs;
    }

Evaluación Perezosa

Uno de los beneficios de la ausencia de los efectos colaterales es que los programadores pueden hacer uso de la evaluación perezosa sin tener que prever infinidad de escenarios posibles, esta consiste en definir valores como resultado de una función que no serán calculados hasta que la ejecución del programa no lo requiera lo que permite crear comportamientos como arreglos de longitud teóricamente infinita, en la mayoría de los casos llamados streams. Un ejemplo del uso de evaluación perezosa es el calculo de la raíz cuadrada de un numero utilizando un sucesión infinita de candidatos que se evalúa hasta encontrar uno que cumpla con la precisión requerida.


  public static Function1<Double, Double> siguienteCandidato(Double n){
      /**
       * Formula para calcular la sucesión de candidatos a para la raíz cuadrada de n según el método de Newton-Raphson
       */
      return Function1.of((anterior) -> (anterior + (n / anterior)) / 2d);
  }

  public static Double calcularRaizCuadrada(Double n){
      Stream<Double> s = Stream.iterate(1d, siguienteCandidato(n));
      Double epsilon = 0.0001d; // Se utiliza para especificar la precisión
      return s.takeUntil(candidato -> Math.abs((candidato * candidato) - n) < epsilon).last();
  }

  public static void main(String[] args) {
      System.out.println(calcularRaizCuadrada(25d)); // 5.000023178253949
  }

En el ejemplo anterior también se puede observar el segundo caso de funciones de orden superior, representado por siguienteCandidato que consta de una función que retorna otra función.

Top comments (0)