domingo, 11 de mayo de 2014

La ventaja de ser perezoso


Si buscamos en la wikipedia “lazy evaluation”, podemos encontrar este concepto como lazy evaluation o call-by-need. Los dos nombres le quedan muy bien pero personalmente opino que call-by-need explica mejor lo que sucede. Lazy evaluation permite que un bloque de código sea evaluado luego o mejor dicho sólo cuando se lo necesite, esto nos permite realizar código que tiene un rendimiento superior en ciertas situaciones.

Veamos un ejemplo, supongamos que tengo la función multiplicación

mult(a, b) = a * a

Si llamara a esta función con los parámetros 8 y 5+2 de forma tradicional o eager sucedería lo siguiente :
mult(8, 5+2)
mult(8,7)
8*8
64

Pero si ejecutamos el código de forma perezosa:
mult(8, 5+2)
8 * 8
64

En este caso la ejecución perezosa fue más eficiente que la forma tradicional o eager.

Para poner otro ejemplo si tengo la función loop

loop(x) = loop(x)

Esta función nunca termina, veamos que pasa si ejecutamos mult(2, loop(2))

mult(2, loop(2))
mult(2, loop(2))
mult(2, loop(2))
mult(2, loop(2))
... hasta el infinito y más allá...

Pero si ejecutamos de forma perezosa

mult(2, loop(2))
2 * 2
4

Termina y nos da el resultado.

Si piensan bien, los programadores c (y sus derivados) utilizamos dos funciones que son lazy por cuestiones de rendimiento. Te acordas?

Vamos no es tan difícil...

Pensa...

mmm...

Si, si lo operadores and y or.

Estas funciones son diferentes pero trabajan similar. Vamos a analizar el and. El and es una función que si un parámetro es falso, retorna falso y si los dos son verdaderos devolverá verdadero. Como ustedes ya saben no necesita analizar los dos parámetros, si el primero es falso. De esta forma podemos hacer lo siguiente:

(a != null && a.nombre == “Peperino”)

Si a es nulo nunca ejecutara la expresión: a.nombre == “Peperino”

Scala es un lenguaje que se puede indicar que un parámetro sea manejado de forma perezosa, para esto se debe utilizar “=>” cuando se declara el parámetro. Vamos a hacer una función “and” en Scala:

def and(x:Boolean, y: => Boolean) = if (x) y else x

De esta forma si “x” es verdadero devolvemos “y” y si “x” es falso, ni siquiera ejecutamos “y”.

Podemos probarla con la función loop:

def loop : Boolean = loop   //> loop: => Boolean

and(false, loop)    //> res1: Boolean = false

La evaluación perezosa proviene del paradigma funcional, es una característica de Haskell y otros lenguajes funcionales, pero también podemos usarla en lenguajes multiparadigma como Scala.