So the last video ended on kind of an amazing note.
Functions can consume other functions as arguments.
And letting us do that, makes it possible to easily write abstract functions.
And then we can use those abstract functions to write, other functions that
are very short, very simple to write. That's pretty great.
As I said in the last video, you can do this kind of abstraction in any language,
and that's why we're covering it in this course.
But it's almost never going to look as clean and simple as it does in this
language so enjoy it while you got it. What we're going to do in this video is
we're going to take the next couple of steps in the design recipe.
We're going to do now the check-expects and the purpose for these abstract
functions. Remember we're working through the recipe
backwards starting from the working abstract function heading back towards
the signature. [INAUDIBLE] I'm in parametrization-v2,
and I'm where I left off last time where we had gotten the working definition of
contains question mark by abstracting it out of contains-ubc, and contains-mcgill.
Let's work on check-expects. Well, the easiest way to get the
check-expects is to abstract them also from the examples.
One way to do it is to take the check-expects for both other functions.
Copy them all down, and we're not going to use all of them, of course.
Now these calls to contains-ubc and contains-mcgill and the check-expects
have to be replaced with a call to contains.
That's the function we're doing now. Now, I'm going to end up deleting a bunch
of these, but because it can be really troublesome to have a call to one of the
concrete functions, I'm going to go ahead and take the time to rename all of these.
And of course, this is going to have to be a string argument inserted in that
position for all of these. So let's see a base case test contains,
it doesn't matter what we look for, but let's look for UBC in empty, that's still
false. And I only need one base case test, so
that one will go away. [INAUDIBLE] Now, let's look for ubc in
cons McGill empty. That one produces false.
Here we can look for ubc in Cons UBC empty and that one is going to produce
true. And let's see let's get rid of these
other one long cases and let's get a couple of two long cases.
This is, let's see, both of those are one long.
So let's see, if we're looking in there, we produce true that means we were
probably looking for, let's say we were looking for UBC and here let's also be
looking for UBC. But let's have a too long case where we
fail. Let's look for Toronto in that list and
there it will produce false. Now all I did here was to just take the
existing examples and work on them a bit to turn them into examples for the new
function. Another thing you could have done was to
generate examples for the new function kind of from scratch from first
principles. But, in cases particularly where perhaps
the examples are complicated. Taking existing examples that work and
revising them might be a better way to be sure your examples work.
But both approaches would be fine. Well, let's try running these examples,
make sure they do work, and they do. So now, again, working backwards through
the HtDF recipe, we've got, we started with a working function Now we've done
the check-expects. Let's do the purpose.
Well, you know, these were the two less abstract purpose statements we started
out with. And oftentimes that's a good way to
figure out the purpose for a more abstract function.
Although sometimes it's harder to get a purpose for an abstract function.
The reason we're going through the recipe backwards is that paradoxically as we go
back towards the signature each step gets harder and harder with abstract
functions, and the fundamental idea of the recipe was always to do the easiest
thing first. In this case, the purpose is going to
come quite easily for us. It's just going to be produce true if los
includes what? It isn't UBC or McGill.
It's s. [INAUDIBLE] if los contains s, we produce
true, so then I'm done with both of those.
[INAUDIBLE] Okay. Now I would normally do the signature,
but I'm going to save all my signatures to do at the end.
Okay, in video three of this three part series is when we'll do the signature.
I'm going to jump down here and do the map2 case.
Let's see. Let me grab some examples.
You know, this time what I'll do is I'll actually do the examples more from first
principles just so you also see that approach.
It's a recursive function operating on a list.
So base case test is going to come first, check-expect, map2.
Now look in this case even though I'm kind of typing then from scratch, I'm
still going to look at the previous. Concrete uses of map2, okay?
Here, map 2 is being called to square numbers.
Here, map 2 is being called to take the square root of numbers.
So those look like things that map 2 can do.
I'll call it with square and the base case test empty.
I get empty. I'll test that right away.
It's working, let me try another one. Map2 of square, and here we'll say, list
2 and 4. Well that's going to produce list four
and 16. Those are about 14.
It's also good to have a test where we make sure that Map2 uses the function we
gave it. So, let's say, check-expect map2 sqrt.
List 16 and 9 is going to be list. The square root of 16 is 4 and the square
root of 9 is 3. Let's try that.
Now you might be tempted at this point to put in some other examples.
You might be tempted at this point to put in some very different examples.
We'll come to that in the next video when we do signatures.
What we need to do now is to go ahead and do the purpose.
Now let's see. Here.
I'm going to copy the two existing purpose statements but they're not
going to help us as much. [NOISE] If, if I just base it off of
those I might be tempted to write a purpose like
[INAUDIBLE].
Produce list of square root or, ooh, this was [INAUDIBLE].
I copied the wrong one here. This was actually square, never mind.
Produce list of square root or square of every number in lon.
And maybe that is the first purpose you write.
But then you say to yourself, gee, could this function, is that all it can do?
Can it be more abstract than that? If you look at the body of this function,
the body of map2, you know, it doesn't say square or square root anywhere in it.
It probably can do more things than that, and maybe here you do an experiment.
Check-expects map2. I don't know.
Let's take the absolute value of list 2 minus 3 4.
That would be list 2 3 4. It does that.
So this isn't it. No.
Let me show you a really good purpose statement for the abstract function map2.
And before I type it let me tell you, the thing about purpose for abstract function
is that it usually a lot of tries to get them right.
This one I'm about to write, I guarantee you the first person who invented map
didn't come up with this on the first try.
What I'm going to write is given FN and list N zero N one dot dot dot.
Produce list FN of N zero FN of N one dot dot dot.
That seems very abstract, and it is. It seems almost mathematical.
Sorry about. Bout that, but, let's look at it, if we
call map2 with sqr and list 2 4 we get back list square of 2, that's 4, and
square of 4, that's 16. If we call map2 with square root and list
16 9 we get back List square root of 16 is four.
Square root of nine is three. If we call map2 with abs, the absolute
value function, and two minus three four we get back the absolute value of two is
two. The absolute value of minus three is
three. The absolute value of four is four.
It is doing exactly this, given a fn and a list of numbers.
It produces the list of the result of calling fun on each number in the list.
So that is a much better purpose statement for the abstract function,
map2. So I'm going to end this video the same
way I ended the last video. Here's filter two.
I want you to do the check-expects and the purpose for filter2, and I'll see you
in the next video.