0:00

Last session we have introduced high order functions as building blocks of programs.

High order functions are essential in many functional programming languages.

So much so that there's a special form to write them.

Which we are going to cover in this session.

So the topic of this session is currying, and I do not mean the food with that.

You'll find out in a second what that is. For our motivation, let's look again at

our summation functions, sumInts, sumCubes, sumFactorials.

We could factor out the body of these functions and now simply pass the function

to apply to each element in the interval. And the two pounds in the intervals.

But there's still repetition. Each of the three functions takes two

parameters A and B and then passes them on to the sum functions.

Can we get rid of these parameters and thereby become even shorter?

1:01

To see how that could be done, let's rewrite the sum functions as you see here.

So that sum function now takes only a single parameter, F, of type n to n as

before, and it returns a function. As its result indicated by this function

type here. So how can it return a function as a

result? Well, it defines a function in this body,

sum F, which takes the two bounds and does the usual computation that you've seen

before. And that function sum F will be returned

from sum. So sum is now a function that returns

another function. In particular, a locally defined function.

1:48

So if you do that, then we can in fact define sumInts to be simply sum of x,

arrow x, sum cubed is sum of the cubing function, and SUM factorial is sum of the

fact function. It turns out that these functions, they

are just exactly the same as the functions we defined before, and they can applied

just like the functions we defined before. So, we could say, SUM cubes one, ten, plus

SUM factorials ten, twenty. Next question.

In the previous example can we avoid the middleman, sum N, sum cubes, and the like.

Can we use directly the general sum function?

Of course. We simply write, sum of, in this case

cube, and then the bounds one to ten. Let's analyze that a, a little bit more.

So sum of cube applies to sum function. To the cube function.

And returns the sum of cube's function. Sum of cube is therefore equivalent to sum

cubes, and that function is next applied to the arguments one and ten.

3:10

This expression returns a function and that function then is applied to one and

ten. So here's another piece of syntactic

sugar. The definition of functions that return

functions is so useful in functional programming that we have a syntax for it

in skylar. So the A previous definition of sum

actually can be written shorter like that. We can just combine the, two parameter

lists of the outer function and the nested function and write them one after the

other. It would say sum of F int and then comes

another parameter list with A and B. And the body of the sum function is very

much like it was before. You might ask, well what's the point of

doing it that way instead of simply writing the function with three parameters

like we did at the beginning? Well the idea is that if you do that then

actually you can write sum of, let's say cube, separately.

That's a valid expression by itself and you can avoid passing the other arguments.

They will arrive in a different parameters list that can be applied later on in a

different context. So I've said that functions with multiple

parameter lists are syntactic sugar. Let's see how they expand.

If you have a function with multiple parameter lists like that, RX1, RXN equals

E, where N is greater than zero, that's, in fact, equivalent to taking the first N

minus one number of parameter lists. And for the last one, you create a fresh

function called G, that takes the last list.

Maps it to the body E, and G is the function that gets returned from F.

That was exactly the definition we did with sum F when we modeled the sum

function that dropped its second parameter list by having the inner function, sum F.

Or for short, we can just write an anonymous function.

So the, the, the definition up here would also be equivalent to the definition that

you see down here, where the last parameter list is, the parameter list of

anonymous function that maps to E. Now, if you repeat that process n times,

then our original n parameter list function is mapped to a function that has

no parameter list at all, but on the right hand side we have n nested anonymous

functions. This style of definition in function

application where essentially every function is mapped to an expression that

consists of anonymous functions, nested anonymous functions, that each take one

parameter, is called currying. It's named after its promoter, Haskell

Brooks Curry, who was a logician in the twentieth century.

It's no coincidence that Haskell Brooks Curry shares his first name with the

Haskell programming language. In fact, the, this idea goes back even

further to Shawn Finkel and probably Fricke, but the term Currying has stuck.

6:31

So let's take one more look at types. Given this function, sum f int and with it

two arguments, what is its type? The answer would be, it first, it is the

function that takes the function's argument, so that would be the argument

pipe. And that returns a function, that takes

two integers as arguments that would both be those two, and that returns finally an

int. So note that functional pipes associate to

the right. Here I could have written also.

Type like this. So, we take the intuitive function and we

return this function, but this blue parenthesis here are actually redundant.

Because, in general, at types such as int, arrow int, arrow int is read as int arrow,

and then the second pairs of ins are in parenthesis.

So we put the parenthesis for function types on the right.

7:50

As a second exercise, once you have product can you write factorial in terms

of it? And the third part of the exercise would

be, can you think of a more general function which generalizes both sum and

product? So let's see how we would answer that

exercise. I have already opened a new worksheet and

given you the product function and the parameters and results it takes.

So that's analogous to some product would take a function that goes from end to end

into two pounds, which are in ints, and we would return an int.

How would we define it? So we would go analogous to sum function.

First ask, well, if the bounds are empty, then we want to return the unit value for

multiplication. So for sum, the unit value was a zero, but

for multiplication, it's a one. So we return a one here.

And otherwise, we take f of a, and now times product of f and a, plus one, and b.

9:05

Let's test it. Oh, forgot the function.

Let's take the squares of all. Ints between three and seven.

That gives us a value which is hard to check, so let's do a smaller, 144.

That looks correct. Let's come to the second part of the

exercise. Second part of the exercise was, can we

define factorial in terms of product? So let's see how we would do that.

9:47

You have the factorial, which takes an int.

And what would that be? So it would be, the definition would be,

it's a multiplication of all numbers between one and m.

So it's a product where we pass as the function parameter the identity, and the

balance would be one and N. Again let's test that.

Factorial of five, would be 120, which is also correct.

The third part of the exercise was, can we find a function that generalizes sum and

product? Using that function we should be able to

express both sum and product. What could that be?

Well that function would then be parametrized in the type of mapping that

we want to apply, because that was something that was common in some end

product, plus the two bounds, plus the two things that differ.

The two things that differ were, what was the unit value and what was the combining

function with which we combined individual values of f?

In fact that what, what we are after is a version of map reduce.

We want to have a function, the function f would map values in the interval to new

values, and reduce, then would combine them.

So let's call this new function map reduce.

And what should we get as parameters? Well, it needs to get the f parameter and

it needs to get a new parameter called det combine that takes two ints and returns an

int. And finally, it needs to have a unit

value. We'll call it a zero value, which is an

int. So that's the value to return if the

interval is empty. And after that, we would have the same

thing as before. So we would have the two values of A and

B. How would we define it?

Well, let's take the definition of product as a template.

So if A is greater than B, then what do we return?

The zero value. Otherwise, we take F of A, and what we do,

we do with F of A, we're neither summing nor multiplying, but we now combine it

with the map reduce value of the same three parameters that we had initially.

And a + one and b. And it seems I'm missing, apparently.

12:37

Good. So that was the map reduce example.

Let's test it. Well a good way to test it actually would

be to say well let's define product in terms of map reduce, because after all, we

wanted a function that generalizes both sum and product.

So product then would be map reduce. Off.

What's the function, the given function? F is the mapping function.

The combining function would be a function that takes x and y and returns the product

of x and y. And the zero would be one for a product.

And we pass the parameters like this. And we delete the previous version of

product. Oops.

I had, had a problem here, where, let's see what it says.

In fact what happened here, we get two errors, which says we have a forward

reference, that extends over two definitions of values, reds zero and reds

one. If you remembered off the worksheet so

far, reds zero and reds one, where the values that named these individual

parameters. What happens here is that if you define a

function then in fact that function can refer to other functions but only as long

as there, that there are no definitions or expressions between two, the two

functions. So what we need to do then is move the map

reviews up in front of the product. So that we wouldn't have a forward

reference anymore. So now the program compiles.

And we would get the same value of factorial of 520.

So that means that we have substituted a correct definition, or seemingly correct

definition, for product. You've seen currying as a way to define

functions piecewise, one parameter section after the other.

In the next session we are going to take what we've learned with high order

functions, in another concrete example.