Lambda Expressions Everywhere

From the makers of ‘Anonymous classes’ comes… anonymous functions. Or as friends call them: lambda expressions. Anonymous functions, as we already saw in a previous post, are functions that don’t need to be declared previously. Let’s see an example: A function which returns the length of a String removing any blank space in it could be defined as:

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

Its equivalent anonymous function would be:

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

The type of this expression is: String => Int

Where can we use anonymous functions?

The most common way to use them is in function that accept other functions as parameter. This type of functions are called Higher Order Functions. Functions that return a function as result are also known as higher order functions. Fantastic, extraordinary… an example, please? Thanks to our unlimited imagination, we’ll create a simple integer calculator. Let’s define our calculator in the following way:

  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
  }

Hmmmm, cool. A class with some methods in it. It works but… what if we try and take a more generic turn?
meme-functions

What we really want is to apply a binary operation. That operation, given two integers, will return a new integer. We could say that we need a method like this:

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

As can be appreciated, we are actually passing a function as parameter. We are using an anonymous function. In order to make it more readable, we can create a new type that represents the integer binary operation: (Int, Int) => Int.

  type Operation = (Int, Int) => Int

And if we apply this to our calculate method:

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

This method can be used in several ways:

1) The easiest one: we insert a previously defined function.

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

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

2) There is no function defined. Besides, the function is pretty simple and it won’t be used elsewhere in the code. All right then, we can use a lambda expression:

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

As can be seen, in this case, an anonymous function is used to define the operation we want to apply to the two integers. It is a nimble and quick way to define functions. But that’s not all. Thanks to the type inference, we can avoid writing the type of the input parameters:

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

And with a spoonful of syntactic sugar…

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

What advantages do we have when compared to the object oriented implementation?

  • Our code is significantly reduced:
  object Calculator {

    type Operation = (Int, Int) => Int
    
    def calculate(n1: Int, n2: Int)(operation: Operation) =
      operation(n1, n2)
  }
  • We are not bound to use only the operations that we have hardcoded in our implementation. We can create more complex operations on the fly:
  calculate(1, 2)((n1, n2) => (n1 + n2) * (n1 - n2))

As it always happens in Scala, its misuse might lead to unpleasant consequences. In future posts, we’ll take a look at the dark side of lambda expressions. In the meantime, we shall remain naively happy.

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