[BLANK_AUDIO].
In this first video on abstraction, we're going to start by going all the way back
to the beginning of the course, to remember the original problem that
functions with parameters solved for us. Then, we're going to see that we can
solve a similar problem in our most recent functions, functions that are
very, very similar in large part because they're based on the same template.
We're going to be able to pull out the common part of the function into an
abstract function, and that's going to make the functions we started writing in
the first place much, much shorter. Okay.
This is going to be fun. I'm in Parameterization Starter and I'm
going to go all the way back to the very beginning of the course, to some of the
very first kinds of expressions that we wrote.
Back at the beginning, we learned how to write an expression like this first one,
which computes the area of a circle of diameter four.
And of course, if you do that for the area of a circle of diameter 4, you could
also do it for the area of a circle of diameter 6.
And then, pretty much immediately, we started to think, wow, this is going to
be cumbersome if every time we want to do something slightly different.
We have to write a whole new expression. And then we learned about functions.
And the idea that because we have two expressions here that vary only in one
position, they vary only in the position where the 4 and the 6 appears, we could
do the following trick. You could take one of the expressions.
Put it up here. Wrap a function definition around it.
Let's call it area. Pick a parameter name for the varying
position. Let's call it r.
[INAUDIBLE] the indentation always, and then replace the specific thing that's in
the varying position with r. And then, these expressions can be
replaced with the more compact, area 4, in this case.
I'll just comment out the other one, and area 6, in that case.
[SOUND] We run it, we get the same values as before.
And we say that this function is more abstract that the specific expressions
because it's more general than the specific expressions.
This does the area of a circle of diameter 4.
This does one for 6. Those are very specific.
This does the area of a circle with any given diameter.
That's more general, or as I'm saying we call that more abstract.
That was Week 1. Later, we learned how to write functions
that operate on lists, and lots of other functions.
And at one point, we were writing these two functions.
The function that is going to take a list of Quidditch teams and see whether it
contains UBC. A function that is going to take a list
of Quidditch teams and see whether it contains McGill.
And, of course, these functions because of the way we design them based on
templates are very, very similar. They only differ in one position.
They differ in their names of course, but they really only differ in one position
where UBC and McGill are. So we can do the same thing.
I'm going to take one of them. And in this case, I'm going to put it
below instead of above, that's just a detail.
[BLANK_AUDIO] I'm going to think of a more general name.
There already is a function here. It's not just an expression, so I'm not
going to wrap a function around it. I'm going to think of a more general
name. I'll just call it contains.
There's one varying position, the position that holds UBC and McGill, so I
need a parameter for that position. I'll call it s.
Since I renamed the function I have to rename the recursive call.
I have to pass the parameter in the recursive call and, and, I have to use
the parameter in the varying position. All I did there was exactly the same
thing I did for area. And now, of course, I can go back to
contains-ubc and contains-mcgill. And I can replace their entire body with
just a call to this contains function. [SOUND] UBC is what's in the varying
position. And all of this can go away.
And I can do the same thing here. And all of this can go away.
And when I test it, should work, those tests are passing.
Now, I didn't really, this isn't really a complete function design, it doesn't have
a signature, it doesn't have a purpose, it doesn't have tests.
Because we started from working code and work systematically this way, we ended up
with working code. This is a different way of arriving at a
function design. A little later, when I show you how to
get the signature purpose, and, and tests.
What you're going to see is that this way of arriving at a working function design,
which is called abstraction from, from examples.
You get the function definition first, then you get the tests, then you get the
purpose, then you get the signature. It's the opposite order.
So, we've got the function definition for now.
Let's go do another one. Here's two functions, squares and square
roots. They're kind of silly.
You might not want these two functions, but what squares does is it takes a
listed number, and it produces a list of the squares of those numbers.
So if you call it with (list 3 4), you get (list 9 16).
And what square roots does is it kind of goes the other way.
If you call it with (list 9 16), you get (list 3 4).
Now let's look at these two functions closely.
They're very, very similar. They differ in their names, but aside
from that they only differ in one position.
This position here. This one calls square in this position.
And this one calls square root in this position.
So let's try the same thing again. We'll make a copy of one of the two.
We'll put it down here. Now we need to think of a more general
name. Now for historical and mathematical and
wonderful reasons the name I'm going to choose is map2.
We never would've chosen map2. I know that.
I'm choosing map2. The reason I'm calling this map2 is that
later we'll see that ISL. Already has a built in function that does
this. And the name of that function is map.
And I'm not allowed to redefine a function name.
So I'm using map 2 here. Now, I need a name for this parameter.
For the thing that goes there or there. What's a good name for the general thing
that those are. When it was two radii, we used r.
When it was two strings, we used s. These are two functions.
I'll just use fn. We could use anything you want of course.
A parameter name can be anything you want.
It could be strawberry. But I'm using fn.
Now, let's see. I also have to rename the recursion, and
I have to pass the parameter in the recursion.
And I have to use the parameter at the point of variance.
And then I have to take these two and replace their bodies with map2, and then
this one is square lon. And here it's map2 and this one is sqrt
lon. Let's try that.
The tests passed. Some of you, especially the one's who've
programmed in other languages. Might be going, wait a minute.
What happened? gee.
Here we've got a function or a function name, at least.
Sqr and sqrt, being passed as a parameter.
That's right. Map2 is what's called a higher order
function. And what it means to be a higher order
function is that it can consume other functions as its arguments.
So that's exactly what we're doing here in squares.
We're calling map two with two arguments. One is name the function square, and the
other is list the numbers And square roots does a similar thing.
The great thing in DSL ISL, the teaching languages, is that the way of writing
this, the notation that we use to write this, is very simple.
You can achieve something like this in almost every programming language.
[INAUDIBLE] But there's almost no other programming language in which the
notation for doing it is as simple as it is here.
That's the first part of the process for producing an abstract function from
examples. In the next video, I'm going to continue
with how you get Signature, purpose and tests.
But this video, we're just going to work on the actual function definition.
I've got one more example here of 2 functions, positive only and negative
only. And I'd like you to go ahead and do just
what I've done here, with those two examples.
And I want you to call your abstract function, filter two, that's filter two.
Go ahead and do that now and I'll see you in the next video.