Expresiones Lambda a cholón

De los creadores de las clases Anónimas llega…..funciones anónimas. O como les llaman los amigos: expresiones lambda. Las funciones anónimas, como ya vimos en un post anterior, son funciones que no es necesario declarar previamente. Vamos a ver un ejemplo: Una función que devuelva la longitud de un String eliminando los espacios en blanco la podemos definir de la siguiente forma:

  def length(s: String): Int = s.replaceAll(" ", "").length

Su equivalente en función anónima será la siguiente:

  (s: String) => s.replaceAll(" ", "").length

El tipo de esta expresión será: String => Int

¿Dónde podemos usar funciones anónimas?

Lo más usual es utilizarlo en funciones que, como parámetro, aceptan otras funciones. A este tipo de funciones se les llama Funciones de Orden Superior (o Higher Order Function). También son funciones de orden superior aquellas que como resultado devuelven una función. ¿Pues muy bien. Mu rico….¿un ejemplo? Gracias a una imaginación desbordante, vamos a crear una calculadora de números enteros muy simple. Podemos definir una calculadora de la siguiente forma:

  object Calculator {
    
    def sum(n1: Int, n2: Int): Int = n1 + n2

    def subtract(n1: Int, n2: Int): Int = n1 - n2

    def multiplicate(n1: Int, n2: Int): Int = n1 * n2

    def divide(n1: Int, n2: Int): Int = n1 / n2
  }

Mmmmm, guay. Una clase con varios métodos. Funciona. Pero…¿y si probamos a darle un giro más genérico? meme-functions Realmente lo que queremos es aplicar una operación binaria. Dicha operación, dado dos enteros, devolverá un nuevo entero. Podemos decir que necesitamos un método como este:

  def calculate(n1: Int, n2: Int)(operation:(Int, Int) => Int) =
    operation(n1, n2)

Como se puede ver, estamos pasando realmente una función como parámetro. Estamos utilizando una función anónima. Para hacerlo más legible, podemos crear un nuevo tipo que represente la operación binaria de enteros: (Int, Int) => Int.

  type Operation = (Int, Int) => Int

Y lo aplicamos a nuestro método calculate:

  def calculate(n1: Int, n2: Int)(operation: Operation) =
    operation(n1, n2)

Este método puede ser llamado de varias formas:
1) La facilita: le inserto una función definida anteriormente:

  def addition(n1: Int, n2: Int) = n1 + n2

calculate(1, 2)(addition) //returns 3

2) No tengo una función definida. Además, la función es simple y no se volverá a usar en ningún otro punto del código. Pues nada, meto una expresión lambda

  calculate(1, 2)((n1: Int, n2: Int) => n1 + n2) //returns 3

Como se puede observar, en este caso se utiliza una función anónima para definir la operación que queremos aplicar a los dos enteros. Es una forma ágil y rápida de definir funciones. Pero no se queda aquí. Gracias a la inferencia de tipos, nos podemos saltar marcar el tipo de los parámetros de entrada:

  calculate(1, 2)((n1, n2) => n1 + n2) //returns 3

Y si aplicamos un poco de sintatix sugar….

  calculate(1, 2)(_ + _) //returns 3

¿Qué ventajas tenemos respecto a la implementación orientada a objetos?

  • Nuestro código se reduce de manera significativa:
  object Calculator {

    type Operation = (Int, Int) => Int
    
    def calculate(n1: Int, n2: Int)(operation: Operation) =
      operation(n1, n2)
  }
  • No estamos atados a utilizar solo las operaciones que hemos definido a fuego en nuestra implementación. Podemos hacer otras operaciones más complejas al vuelo:
  calculate(1, 2)((n1, n2) => (n1 + n2) * (n1 - n2))

Como siempre pasa en Scala, su mal uso puede provocar problemas algo desagradables. En futuros post veremos el lado oscuro de las expresiones lambda. Mientras tanto viviremos felices.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s