In this section, we're looking at a somewhat larger example using higher-order functions in interesting ways. The example is about finding fixed points of functions. A number x is called a fixed point of a function, if f of x equals x, so f maps x to itself. For some functions f, we can find the fixed points by starting with an initial estimate and then applying f repetitively. So it's x, f of x, f of f of x, and so on until the value does not vary anymore or the change is sufficiently small. It doesn't work for all functions, but for quite a few it does. That leads to the following set of functions for defining a fixed point. The idea is we take a function from double to double in that case, and first guess. Then we iterate until we're close enough, so iteration means we define the next function but as the application of f to the guess. If we're close enough with the next value, then return the next value and otherwise iterate recursively. To find a fixed point, we then iterate from the first guess. The only thing to do is define the function is close enough, so the idea of is close enough was that the difference between x and y divided by x should be smaller than some tolerance. The absolute value of x minus y divided by x should be smaller than some tolerance which is some small double value. That definition of is close enough is quite similar to what we did for square roots, but it answers the question that I asked when we did the square root example that we want a definition from for is close enough that's robust for very small as well as very large number, so this one is better than what we had before. Let's return to square roots. We can actually use the fixed point function to come up with a new and more principled definition of what the square root function is. The idea is that if we look at the specification of the square root function, then square root x is just the number y such that y times y equals x. We can also divide both sides of the equation with y, so that means square root x is a number y such that y equals x divided by y. That means that square root x is a fixed point of the function that takes a y and gives you x divided by y. Indeed, that function would map square root x to x divided by square root x. Well, that's just square root x, so a square root x is a fixed point of that function. Now that we know how square roots can be expressed as fixed points, we can try to calculate square root of x by iteration towards a fixed point, so we could try this to say square root of x is simply the fixed point of this function that we've developed previously and 1.0 as a first guess. Unfortunately, if we try that in a worksheet or Apple, it doesn't converge, it will loop forever. I've copied the fixed point program to a program with a main method tests that run square root of two. Let's try to run that. Nothing happens, so we stop it. Let's see what goes on. We can try to find out what goes on by putting a strategic println statement here. So for each iteration, we want to print the value that it just computed at that iteration. To see what comes out of the printIn statement, I have to add a debug console here. Okay, let's run the program. We've seen that, okay, it's an infinite sequence of 1s followed by 2s. So it doesn't converge, it always oscillates between one and two. Here I've written the same thing. If we do add the println to the iterate, then square root of two produces as output two followed by one, followed by two, followed by one, and so on. One way to control those oscillations is to prevent the estimation from varying too much. A good idea to do that is by averaging successive values of the original sequence. What we could try to do is take the fixed point, not of the function x divided by y, but y plus x divided by y divided by two, so it's the average of the previous value y and the new value x divided by y. Let's do that and run the program again. Okay, so now we see something much nicer. After four iterations already, we are close enough, so it converges very rapidly. In fact, if we expand the fixed point, replace this call to fixed point by the body, by its definition, then we'll find a square root function that's quite similar to what we developed last week. So in a sense, fixed-point really captures the essence of what we did with square root and generalizes it to other functions as well. You've seen in the previous examples that the expressive power of a language is greatly increased if you can pass function arguments. Sometimes it's also useful to return functions as results. For instance, if we look at the iteration towards a fixed point, we began by observing that square root of x is a fixed point of this function. Then we noted that we need to average successive values and this technique of stabilizing by averaging is quite general. It's general enough to merit being abstracted into its own function. What would this function look like? Well, average damp would take a function from double to double and an argument of type double. It would return the average of the previous value x and a new value f applied to x. Now that we have average damp, let's rewrite the square root function using it and the fixed point function that we've seen before. What would that look like? Well, here's the answer. Square root of x would be the fixed point of the function y maps to x divided by y subject to average damping. It's fixed point of average damp of the function y goes to x divided by y. I believe you'll agree with me that this expresses the elements of the algorithm. Y square root computes what it computes and why it has to be written this way as clearly as possible. To summarize, we saw last week that functions are essential abstractions because they allow us to introduce general methods to perform computation as explicit and named elements in our programming language. This week, we've seen that these abstractions can be combined with higher-order functions, function parameters, and function results to create new abstractions. As a programmer, one should always look out for opportunities to abstract and reuse. The highest level of abstraction is not always the best, but it's important to know the techniques of abstractions so as to use them when appropriate.