Let's see how this works in an example. We start with sum of squares of three and

two + two. The two + two gets rewritten to a value,

four, and we and, we have sum of squares three, four.

Then we take the definition of sum of squares, that was square of x plus square

of y, and we replace the application by this right hand side, where at the same

time we replace the parameters x and y by the actual arguments three and four.

We then repeat the process with the square applications.

The square of three becomes three times three.

The right turn side of square where three replaces the promidence.

We get an arithmetic simplification, and we do the same thing for the right hand

operators yielding the final value 25. This scheme of expression evaluation is

called the substitution model. The idea underlying this model is that all

evaluation does is reduce an expression to a value.

And that reduction can be expressed by a sequence of simple rewriting steps that

rewrite the expression term itself until it is a value, very similar to what you

would do in algebraic simplification. Simple as it is, this model is very

powerful. In fact it has been shown that it can

express every algorithm, so it's equivalent to what you would call a Turing

machine. This has been shown a long time before

functional programming, in fact, a long time before computers by a logician called

Alonzo Church in the lambda calculus. He did that in the thirties of the last

century. You might have come across lambda calculus

in theoretical computer science, and if you did, then you know how to make the

connection to this model. If you didn't, don't worry.

We won't need the theory for following the course.

What's important though is to know that number calculus as a model, and the

substitution model, can be applied only to expressions that do not have a side

effect. Now, what is a side effect?

A typical side effect would be an expression called.

C++ where c is a variable. And evaluating this expression means that

you return the old value of c, and at the same time you increment the value.

So, at the next time you return the value, you would return the value one larger than

before. Turns out there's no good way to represent

this evaluation sequence by a simple rewriting of this term.

You need something else, like store, where the current value of the variable is kept.

In other words the expression C++ has a side effect on the current value of the

variable. And that side effect cannot be expressed

by the substitution model. So one of the motivations for ruling out

side effects in function programming is that we can keep to the simple model of

evaluation. Once we have the substitution model,

another question comes up. Does every expression reduce to a value in

a finite number of steps? In fact, the answer is no.

Here's a counter example. Let's write simple function def loop int

equals loop. And that's then called, referred to the

name loop. What would happen.

Well, according to our model we have to de evaluate that name which happens by

replacing the name by its right hand side. The right hand side is looped again.

So we have reduced the name to itself and this can go on ad infinitum.

Another way to visualize this reduction sequence is by starting with the loop and

then reducing to the same term again. We've seen that the Scala interpreter

reduces function arguments to values before rewriting the function application.

That's not the only possible reduction strategy.

Alternatively, one could apply the function to unreduced arguments.

For instance, we could start with some of squares three, two plus two, and then go

on as follows. We keep the right hand side.

We don't reduce it to four and we simply pass it as an expression to the square

function. We then simplify the right hand side as

before. And then do the same thing again, pass the

expression, two plus two to this occurrence of square, that gives two plus

two twice in the multiplication. We then simplify the two further steps to

arrive at the final result, 25. Now you've seen two ways to evaluate the

same expression. The first evaluation strategy is known by

core by value. The second is known as core by name.

An important theorem, in fact, of lambda calculus is that both strategies reduce to

the same final value as long as the reduced expression consists of pure

functions and both evaluations terminate. Call-by-value has the advantage that every

function argument is evaluated only once. Call-by-name has the advantage that a

function argument is not evaluated at all if the corresponding parameter is not used

in the evaluation of the function's body. Here's a question, say you're given the

following function definition: Def test of x and y equals x times x.

For each of the following function applications, indicate which evaluation

strategy is fastest, by which we mean, has the fewest reduction steps.

That's for test of two three then test of three plus four eight.

Test seven two times four, then finally, test three plus four, two times four.

Let's see how we would answer this question.

I have the test function here and I have the calls that I want to compare here.

Let's start with the first one, test two, three.