Perezosidad
By laparca
Algo que me ha sorprendido mucho de haskell y, que aún me cuesta mucho lidiar con ello, es el hecho de que sea perezoso.
¿Y eso qué significa?
Significa que no va a ejecutar las cosas sin más, sino que se esperará hasta que no le quede más remedio.
Por ejemplo, si tenemos algo como esto:
Como se puede ver, se «crea» una lista de infinitos elementos que empiezan en 1 (intinite_list). Como no accedemos a ningún elemento, el compilador en realidad no crea nada en memoria.
Luego indicamos que queremos elevar todos los elementos al cuadra para después quedarnos con aquellos que no son múltiplos de dos ni de tres. Eso lo almacenamos en values. En haskell esto significa que values representa esa operación, no que contenga dichos valores, así que aquí tampoco ha hecho nada: no ha elevado los infinitos elementos al cuadrado ni ha filtrado después.
Lo último que hacemos es un take 10. En este momento (si utilizamos ghci), en este momento intenta mostrar los 10 primeros elementos, lo que fuerza a hacer todo lo anterior. ¡Pero sólo lo hace sobre los 10 primeros! Ni elevamos la lista entera al cuadro, ni comprobamos los infinitos elementos. Sólo vamos a hacer esto las veces justas.
Esto lo hace todo el compilador por su cuenta.
¿A dónde quieres ir a parar?
Pues estaba hace poco mirando documentación de Rust y me he encontrado con algo muy parecido:
Básicamente hace lo miso y me sorprendió mucho porque Rust no es un lenguaje que haga evaluación perezosa.
¿Entonces cómo lo hace?
Pues simulando la evaluación perezosa. Para ello lo que hace es jugar con iteradores personalizados. Cada iterador tiene información de qué es lo que va a hacer cuando se llame a su función next. Así que cuando llamamos a map lo que hace es crear en memoria la información necesaria para hacer la operación, pero no la ejecuta. Lo mismo sucede con los filtros. Cuando llamamos al next de iterador resultante, este ejecuta el next del iterador que contiene y luego comprueba o ejecuta la condición que tenga definida.
Conclusión
Sinceramente me ha encantado ver esta aproximación. Es una modo fantástico de lidiar con el problema de infinito de un modo sencillo. Esto permite tratar muchas cosas como iteradores que, aún dando listas potencialmente infinitas, no tengan un gran impacto en rendimiento (o sí, todo dependen de como esté diseñado).
Si quieres saber más sobre evaluación perezosa quizá te interese ver la entrada en Wikipedia.