Principios de la Programación Funcional y ¿Cómo lo maneja Scala?

Contenido

  • Introducción
  • Inmutabilidad
  • Funciones puras
  • Funciones de primera clase y de orden superior

Introducción

A través de esta entrada quiero explicar los principios de la programación funcional y cómo son manejados en Scala. Los principios es una regla que se cumple si se pretende tener cierto estado de hechos en la programación funcional estos principios nos ayudan a mantener un orden y cohesión entre diferentes paradigmas.

Inmutabilidad

Empecemos por definir esta propiedad partiendo de la creación de un objeto cuya principal característica esta dada por la inmutabilidad entonces podemos decir que este objeto esta protegido contra cualquier cambio de estado a partir de su creación y mientras exista el objeto. Ante esta situación podemos prever que un entorno multi-hilo obtendremos la capacidad de proteger nuestro objeto de cambios no deseados y mantener un estado manejable eliminando la necesidad de bloqueos (locks) permitiendo que nuestro código sea paralelo por naturaleza.

En Scala tenemos las palabras clave var y val las cuales nos permiten declarar variables y valores respectivamente. La palabra clave var se utiliza para declarar variables las cuales permiten modificar el estado del objeto al que hacen referencia en contraposición la palabra clave val declara valores que y no permiten modificar el estado del objeto al que hacen referencia.

Por otro lado Scala tiene dedicado un apartado completo a colecciones inmutables dentro del paquete scala.collection.inmutable. En estas clases en cada operación que realizan retorna un nuevo objeto de la misma clase pero con el elemento nuevo que se agregó a la colección.

Jerarquía de clases. collections.immutable

Funciones puras

Las funciones puras son aquellas funciones que reciben una serie de parámetros y retornan un valor bajo ciertas condiciones por ejemplo son deterministas esto es que con una misma entrada siempre retornan el mismo valor y no tienen efectos secundarios como cambiar el estado de una variable global, leer los datos desde un archivo o llamada a una base de datos.

Sin duda los beneficios de una función pura es la facilidad para hacer pruebas unitarias ya que no se tienen que implementar objetos mock dentro de la función que se quiere probar.

Funciones de primera clase y de orden superior

En los lenguajes funcionales las funciones son tratadas como valores de primera clase. Esto significa que, como otro valor, una función puede ser pasada como un parámetro y retornada como un resultado. Esto provee una flexibilidad a la hora de componer programas. Las funciones que toman funciones como parámetro o que retornan funciones son llamadas funciones de orden superior (Higher Order Functions).

Pero momento, ¿una función que retorna otra función?. Entonces tendríamos que hablar de currying. Currying sucede cuando rompemos la función que tiene múltiples argumentos en una serie de funciones que toman un subconjunto de esos argumentos.

object Product extends App {

  def product(f: Int => Int)(a: Int, b: Int): Int = combinal(f, (x, y) => x * y, 1)(a, b)

  def factorial(n: Int) = product(x => x)(1, n)

  def combinal(f: Int => Int, combine: (Int, Int) => Int, zero: Int)(a: Int, b: Int): Int =
    if (a > b) zero
    else combine(f(a), mapReduce(f, combine, zero)(a + 1, b))

  println(product(x => x * x)(3, 4))
  println(factorial(5))
}

En este bloque de código definimos las siguientes funciones:

  • combine
  • product
  • factorial

Empecemos por explicar la función combinal: el primer parámetro de entrada es una función que acepta un entero y retorna un entero, el siguiente es una función de combinación que es utilizada para combinar las entradas de la función f y las subsecuentes llamadas recursivas, el parámetro zero es usado como retorno en el caso base y finalmente los últimos dos parámetros son el rango sobre el cual opera la función. El uso que se le da esta función es abstraer el comportamiento de la función product pero también podríamos implementar una función add o una función subtract.

En la función product utilizamos la función combinal usando una función anónima en el parámetro combine con la multiplicación de ambos parámetros.

Por último en la función factorial usamos la función product para calcular el factorial de un número.

Conclusiones

Scala es un lenguaje de programación multiparadigma que soporta tanto la programación funcional como la programación orientada a objetos esto nos permite situar a este lenguaje en un punto intermedio haciéndolo un lenguaje versátil y potente permitiéndole destacar en entornos de alto paralelismo. Un ejemplo de uso es en entornos Big Data en específico con el framework Apache Spark donde la API de Scala es claramente predominante versus otros lenguajes.

Referencias

https://subscription.packtpub.com/book/application_development/9781786461483/1/ch01lvl1sec8/principles-of-functional-programming
https://www.freecodecamp.org/news/an-introduction-to-the-basic-principles-of-functional-programming-a2c2a15c84

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.