So in this section, you learn about a particular way to compose and abstract functions that's called currying. Look again at the summation functions, sumInts, sumCubes, SumFactorials. Noted a and b get passed unchanged in each case, to the sum functions. Now, whenever there's a common pattern like this one, you should ask yourself whether it's possible to eliminate the repetition. So, can we be even shorter by getting rid of the a and b parameters? At first this looks difficult, but here's an idea. Let's use the fact that in our language functions can return other functions. Let's redefine some as follows. So here we have to sum function and it takes now a single parameter, the function F. And it returns a function that takes two Ints, which are the bounds a and b, and gives you back the final value. How can we formulate f? Well, f has to return a function. Let's call that sumF. And to sumF function it takes the bounds, and then it has the usual pattern. So if the lower bound is bigger than the upper bound, it returns 0, and otherwise it returns f(a) + and now we have the sumF function applied to (a + 1, b). So that function captures the common pattern where, the two are bounds, a and b are still left open, they're parameters to the function sumF. So all sum then returns is, this sumF function. Sum is now a function that returns another function. So how do we apply sum? Sum now returns a single argument. So we can define a function sumInts, that apply sum to the identity functions. SumCubes to the cubing function and so on. So, what's the type of sum x to x? Its type is, hint and hint to hint. So that's the return type of sum function. So since these things are functions, they can be applied in terms. So one could write then, sumCubes(1, 10) + SumFactorials(10, 20). All this is possible, because we have returned a function that takes the bounds separately. Okay, so you've seen we have now proceeded in two steps. We first define the intermediate functions, sumInts, sumCubes and SumFactorials, and then we apply them to the actual bound arguments. You might ask, can we cut out the middleman and avoid sumInts, sumCubes and so on intermediate functions? And the answer is, of course, you can write sum apply to (cube) apply to (1, 10). Well, let's analyze that a bit further. So we have first function, sum(cube) then applies sum to the cube function and it returns another function. one that takes two integers, which are the bounds. So this sum of cubes function gets intern applied to the two bounds 1 and 10. So sum(cube) is equivalent to sumCubes that we've seen previously. And that function gets applied to the arguments. Generally, function application associates to the left. So if you write sum(cube)(1, 10) that means you first apply ( sum (cube)) the parents go like this and then you apply the result to (1, 10). Now, this might look quite weird too many of you, but in fact there's something that you probably know, that is quite close to that and behaves in exactly the same way. What is that? Why would I have in mind is arrays, in a language like Java or C Sharp. You write array, selection with a single argument, and if you have several dimensions and you write them one after the other with brackets. So a[i][j] would be a selection into a two dimensional metrics, within this, is i and j. In fact, you can think of an array, as a function from the index to the element type of the array. So here you have the first function application and here you have the second. Now you might ask yourself, well, if arrays are like functions, and why do we write array application or array indexing with brackets, instead of parentheses? And the answer is, no good reason. It's really historical reasons only. So in fact, in scalar when we will introduce arrays at some later point, you will find that in Scala, we will write array selection with parentheses like this. Because after all, arrays are morally just functions and so you should write array indexing as functional applications. But we will not see arrays for quite a while, because they are immutable concept and we want to concentrate on the purely functional aspects of the language first. Now one downside of this new way of writing functions with arguments given one after each other, in separate parameter section, is that defining a function like that is a bit clumsy. So this thing is a bit scary, the way we set up these functions. But in fact the definition of functions that return functions is so useful in functional programming that has a special syntax for it in Scala in many other functional languages. So for instance the following definition of sum is equivalent to the one with the nested sumF function, but clearer and shorter. Here you just write two parameter sections. You write sum text first, the function as a parameter. And then you follow immediately with the second parameter section a and b, and the result is intent. The body is just what you've written before. So what that implicitly defines is, a function that takes a single parameter f, and with that returns a function that takes the two following parameters, a and b. But you don't have to invent a name, and an inner function to do it, if you can write it all in one line. So let's play with this a little, and let's say you have a function that takes a number of parameter lists. That function would be equivalent from what we've seen, to a function where the last parameter list becomes essentially this nested function. That's how we have defined this idea of writing many parameter lists on one line. They expand to essentially defining nested functions, with arbitrary names here. The name is g. Or for short, this thing here is just an anonymous function, as we've also seen. So the function definition that you saw up here would be equivalent to a function definition with one fewer parameter lists. That has an anonymous function on the right hand side. Now we can repeat the process and do that for every parameter list of the function, and that will end up in a function with no parameters at all. That is an anonymous function of the first parameter list. That returns an anonymous function of the second parameter list and so on. Finally, that returns a function of the last parameter list, and that returns a body. So that means that theoretically, you wouldn't need function parameters in defs at all. All you would need is anonymous functions like that. And that style of definition function application, has a name, it's called currying. Named for its instigator, Haskell Brooks Curry, who was a logician in the twentieth century. So it's no coincidence that Haskell is a very well known functional programming language. It was named after the same logician. In fact, this idea that you can write every function, is essentially a sequence of anonymous functions that each take a single parameter. It goes back even further to Schonfinkel and Frege. But the term currying has stuck. So let's look at the sum function again. Given this function here, what is the type of sum? Where we can read it off the parameter lists, it takes a parameter, of type Int Int. Then it takes two parameters which are both Ints, and turn it to a result of type Int. So if you're picky, you might want to right parenthesis around here, because the thing in the red parenthesis is the result type of the sum function. But in fact functional types associate to the right. That means that Int, Int, Int, is in fact equivalent to putting the parenthesis here, the way you see it here. So these red parenthesis can also be left out. So here's an exercise. Write a product function, that calculates the product of the values of a function for the points of a given interval, similar to what we did to see sum function. As a second step, write the factorial function in terms of product. And as a third step, can you may be write a more general function, that generalizes both sum and product? Okay, so to solve this exercise, I'm going to make use of a new tool, which is called worksheets. So, a worksheet is like a regular thing where you can type in definitions and expressions, but it's more like an complete editing surface, and you will see that the answers together with the expressions that you type. So to start a worksheet, we select a new Scalar file, of type worksheet, and we give it a name, let's call it products, okay. So how would I define product? Well a similar way to how I define sum. If a is greater than b then the product is empty, so I give you back the unit for products. And otherwise I apply f to a, and I multiply that with product(f) (a + 1, b), okay. So let's test this, let's say write product of the square function, and rebounce of 1 and 5. So they were actually responds and says well, you have to find an integer and it is 14400, once more. Okay, so let's use that to define factorial. So what would factorial be? It's a product of the identity function. So that extracts, and 1 up to n. So it's 1 multiplied by 2, multiplied by and so on until then. Okay, so factorial 5, just to test it, would be 120. Okay, so, what about the third question? Can we write a more general function that generalizes both product and some. So what would this function do? Well, essentially it would say well, we want to abstract over the way we combine things. So we had a plus for sum and a times for product. And also we have to obstruct over the case which should be returned when this interval is empty. It was 1 for products and 0 for sums. So let's find a function that keeps both of these values as parameters. So I called this function mapReduce, because it takes a map function. I think that gets applied to every element, that those things, we usually call a map. We call this f here, and it takes a reduce function which is called combine here, that takes two of the results of maps and combines them into a single end. And it also takes a 0, that's the thing to return in case the interval is empty. And that function returns a second function that essentially takes our interval of pounds from a to b. So define mapReduce with the help of function that's called, recur(a). That takes essentially the next value in the reduction to apply. So the pattern of recur is very much like what we've seen before. It says if a is greater than b, then we return to 0, whatever the 0 is. And otherwise we combine the application of f to a. So that's my next value, and the result of recurring with the next step value. Then the result of my produce would simply be, recur with the current lower bound a, this one here. So now that I have mapReduce, how can I redefine sum? So the sum function would take a function f, and its mapReduce (f). The combined function, is the function that takes two integers and sum them and two zero is 0. So let's try it. Let's say we want sum of factorial between 1 and 5. Here you go. So one thing which is interesting for sum is that, I haven't bothered writing the two arguments for the bounds. And I don't need to pass them on to mapReduce either, because both determined mapReduce, carried functions. That means what we do here, is we just compute the final function, that then works on interval, and we don't need to mention that interval yet. Interval will be mentioned only later when we apply the result of sum in fact. So how would you define a product function using mapReduce? So let's delete the body here, and just take the signature, and drop the a Int b. We don't need them anymore. So product would be mapReduce of the function f. Now our combination function is multiplication, and our zero is 1. Let's put that to the test. That's a product(identity, 1, 6) 7 20. Good, so you've seen how we can become very abstract and very concise, defining functions that take functions as arguments, and that return functions as values.