After learning more and more about functional programming, a lot of the operations that we usually do in Java, or JavaScript, and other imperative languages, are implemented recursively.

There are some pros and cons about writing code around immutability - you think more functionally.

In Scala, recursion is usually implemented with stack underneath. For most of the operations that you do, recursion works fine. However, if you want to process a massive amount of data in sync - that needs to loop through the data to transform to another always - it can blow up your stack and said stack overflow.

How would you defer this situation for programming a vast data set functionally?

My friend, the answer is using Eval. It is a cats data type for controlling synchronous data evaluation.

Before we get into that, let me tell you a little bit about the three mechanisms of the Scala modifier and how it is essential to leverage them to optimize the performance of your application.

## What is Eager?

Eager computations happen when you declare the computation, it evokes it right away. For instance, `val`

in Scala evokes the value inside that computation right way when you declare it.

## What is Lazy?

Lazy computation is the opposite of Eager. It evokes the computation when you evoke them. For instance, if you define `def`

in Scala, that computation is not evoked right away. The function gets called when you evoke the function the second time.

## What is Memoized?

Memoize computation is like a cache that stores the result of your initial call on that computation so that next time when you call that computation, it retrieves it from the cache.

For instance, when once you declare a `val`

in Scala, and when you retrieve the computation again, it will memoize it.

```
val x = {
println(s"hi, I am eager and memoized!")
math.random
}
// hi, I am eage and memoized!
// x: Double = 0.09227668662578081
// first access
x
// res0: Double = 0.09227668662578081
// second access
x
// res1: Double = 0.09227668662578081
```

## Eval as a Monad

Cats `Eval`

has 3 types: `now`

, `always`

, `later`

, that behaves the same as the `scala`

models of evaluation.

The way you import and the define the constructor parameter like this, it creates a instance of `eval`

type:

```
import cats.Eval
val now = Eval.now(math.random + 1000) // this will evaluate right away
val always = Eval.always(math.random + 2000)
val later = Eval.later(math.random + 3000)
```

You can extract the result of the `Eval`

instance that you created by evoking the `value`

method.

```
now.value
```

`Eval.now`

is equivalent to `val`

- it is eager and memoized.`Eval.always`

is equivalent to `def`

- it is lazy, and not memoized.`Eval.later`

is equivalent to `lazy`

- it is lazy, and it is memoized.

Knowing this, you can construct `map`

and `flatMap`

through `Eval`

because it is a Monad.

```
val greetings = for {
hi <- Eval.now {
println("hi is evoke.")
s"hi with random math : $math.random"
}
world <- Eval.always {
println("always is evoke.")
"world -- $math.random"
}
} yield hi + world
// first access, which one gets evoke? What will the value?
greetings.value
// second access, which one gets evoke what will the value?
greetings.value
```

The code above, `Eval.now`

first gets printed, and calculate. However, the first access, and other access, the `world`

is evaluated and goes to the `yield`

section to evaluate the `hi+world`

.

Which one,`hi`

or `world`

, will the `math.random`

be evaluated each access?

Eval has a `memoize`

functionality that able to memoized all the computation leading up. Let me give you an example:

```
val x = Eval.always{println("First step")}
.map(_ => println("Second Step"))
.memoize
.map(_ => println("Third Step"))
// first access
x.value
// First Step
// Second Step
// Third Step
// second access
x.value
// Third Step
```

**Note to takeaway** : If you have a computation sequence, which there is only 1 step that is continuously changing, you can do memoize in the computation to increase its performance.

Usually, when we compute recursive calls in a large number of numbers, we encounter `stack-overflow`

. `Eval.defer`

can help you defer your computation from the stack and store them in the heap so that you can compute a large amount of computation recursively.

Simple example of a factorial:

```
def factorial(x:BigInt) : BigInt = if(x == 0) {
1
} else {
factorial(x-1) * x
}
factorial(500000) // this will blow up your stack
```

With a little twist of `Eval`

you can compute your `BigInt`

factorial

```
def factorialEval(x: BigInt): Eval[BigInt] = if(x == 0) {
Eval.now(1)
} else {
Eval.defer(factorialEval(x-1).map(_ * x))
}
// incorporate in your original factorial method
def factorial(x:BigInt):BigInt = factorialEval(x).value
```

### One practice item:

Can you transformed foldRight to Eval?

```
def foldRight[A,B](as:List[A], acc:B)(fn:(A,B) => B):B = as match {
case head::tail =>
fn(head, foldRight(tail,acc)(fn))
case Nil =>
acc
}
```

## Main Takeaway:

- There are 3 terms of computation - eager, lazy, memoized
- Eval has the same 3 terms as Scala - Eval.now, Eval.always, Eval.later
- You can memoize your computation sequence and also create a (not entirely) stack free computation using Eval to optimized your computation on extensive data and data structure.

## Top comments (0)