While exploring Cats I learned about Monads and its different instances available for use and now I’m here sharing all of that with you all. 😊 In today’s blog, we will be exploring Eval Monad in Cats.
Model of Evaluation
From the model of evaluation, I am referring to the way that the value will be evaluated. Generally, we have two of them i.e. Eager and Lazy.
In Eval, there is one more, i.e. Memoized.
- Eager: computations happen immediately.
- Lazy: computations happen on access.
- Memoized: computations happen on first access only and then the results are cached.
- val in Scala are eager and memoized.
- lazy val in Scala is lazy and memoized.
- def are lazy and not memoized.
This monad helps us to abstract over different models of evaluation. We will soon discover what does it mean.
Eval Monad has three subtypes, i.e. Now, Later and Always. These are the Eval’s model of evaluation.
It’s very easy to construct these, using the constructor methods.
Also accessing the value is also easy by using ‘value’ method.
- Now: It’s evaluation model is similar to val i.e. eager and memoized. It captures the value right now.
Here we can see that the value is captured even before accessing same as what I said. Also, it does not change on each call, showing it’s memoized.
- Later: It’s evaluation model is similar to lazy val i.e. lazy and memoized. It will capture the value on it’s first access.
Here we can see that the value is not captured before accessing instead it’s evaluated when it is accessed. Also, it does not change on each call, showing it’s memoized.
- Always: Its evaluation model is similar to def i.e. lazy and non-memoized. It will capture the value on its access.
Here we can see that the value is captured on accessing. Also, on each access, the value is different showing it is re-evaluated and thus non-memoized.
Note: Although, Now, Later and Always have the similar model of evaluation as in val, lazy and def but keep in mind that they have features of a Monad and that creates a big difference between the two.
map and flatMap on Eval Monad
Similar to every other Monad, Eval also has map and flatMap which are helpful in adding methods to a chain. The chain here is stored explicitly as a list of functions and mapping functions are always evaluated lazily(on demand).
Here we can see that Calculating A is printed before accessing the answer’s value but Calculating B is printed after accessing the value. This is because the first print statement is in now block(evaluated right away) and the other one is in always block. From the output, we can see that the evaluation model for Now and Always is maintained.
memoize in Eval Monad
Normally, in map and flatMap every method in the chain is evaluated every time when it is accessed but with memoize method, you can cache the result up to that point.
Here you can see on first access, it prints “Step 1 Step 2 Step 3” but on second access it only prints “Step 3” because the part till the first map is memoized.
Eval’s map and flatMap are tampolined i.e. they are stack-safe. But still, there could be cases of StackOverflow.
Look at simple factorial program :
This is because the call to Eval’s map is after the recursive calls.
We can make this work by simply using Eva.defer. This method takes an existing instance of Eval and defers it’s evaluation. In that way recursive calls will be deferred.
That’s all about Eval Monad. It can help you write simple methods but with more features and in a more efficient manner. I hope the blog was helpful to you. Leave your feedback in the comment section and see you in the next blog. 😊
Also here are my previous blog in this series, check them out as well.