Como todas las mónadas, los métodos map y flatMap de Eval agregan cálculos a una cadena. En este caso, sin embargo, la cadena se almacena explícitamente como una lista de funciones. Las funciones no se ejecutan hasta que llamamos al método de valor de Eval para solicitar un resultado:
val greeting = Eval.always{ println("Step 1"); "Hello" }.map{ str => println("Step 2"); s"$str world" }
// greeting: Eval[String] = cats.Eval$$anon$4@496b9f25
greeting.value
// Step 1
// Step 2
// res16: String = "Hello world"
Si bien se mantiene la semántica de las instancias de Eval de origen, las funciones de map siempre se llaman de forma perezosa bajo demanda:
val ans = for {
a <- Eval.now{ println("Calculating A"); 40 }
b <- Eval.always{ println("Calculating B"); 2 }
} yield {
println("Adding A and B")
a + b
}
// Calculating A
// ans: Eval[Int] = cats.Eval$$anon$4@6e0e633
ans.value // first access
// Calculating B
// Adding A and B
// res17: Int = 42 // first access
ans.value // second access
// Calculating B
// Adding A and B
// res18: Int = 42
Eval tiene un método memoize que nos permite memorizar una cadena de cálculos. El resultado de la cadena hasta la llamada para memorizar se almacena en caché, mientras que los cálculos posteriores a la llamada conservan su semántica original:
val saying = Eval.always{ println("Step 1"); "The cat" }
.map{ str => println("Step 2"); s"$str sat on" }.memoize
.map{ str => println("Step 3"); s"$str the mat" }
// saying: Eval[String] = cats.Eval$$anon$4@77e677ee
saying.value // first access
// Step 1
// Step 2
// Step 3
// res19: String = "The cat sat on the mat" // first access
saying.value // second access
// Step 3
// res20: String = "The cat sat on the mat"