0:00

[MUSIC] Let's talk some more about parentheses, and let's particularly

understand that parentheses are not optional in Racket.

They are common, but every time we use them they have a meaning.

So this is a habit you have to break yourself of.

In languages that don't have a syntax like Racket, you're used to just putting

in extra parentheses to help you understand something, and if something

isn't working, maybe you'll just put in more parentheses and then it will start

working. It doesn't work in Racket.

The parentheses always have a meaning. In particular, in most places, if you

write in, something in parentheses that means evaluate e To a result, and then

call it as a function with 0 arguments because the way we do a function call is

parenthesis, thing you want to call, and then argument.

So if there are no arguments, this is call it with 0 arguments.

So, look at this one with 2 parentheses. This says evaluate e, call the result as

a function with 0 arguments. Get back a result and call that as a

function with zero arguments. This makes perfect sense.

We might even do things like this, but if it's not what you mean, you're going to

get an error message. You're going to try to treat something as

a function that is not a function. Now without static typing, this sort of

thing will work just fine when you save your file, when you click run, but once

you actually execute the code, maybe it's inside a function body somewhere, then

you can get an error message. It can be hard to diagnose and your first

reaction is to just start playing with the parentheses,

and it's only going to get you into more trouble.

So let's work through some examples to give you some practice with this.

And the moral of the story is always, slow down, think about your parentheses.

If you're confused why they're there, delete them and start over.

Indent your code well, it'll always work fine.

So what I'm going to do is just show you a bunch of versions of a factorial

function, 1 of my favorite little functions for examples.

And I'm going to start by getting it correct, okay.

So, so far what I've written while I was talking to you is In factors of one

argument function, so these parenthesis have to be here.

Then, I have an if, and I need 3 arguments.

This is the first one. It's a call to the equals function.

This is the second one, which is 1. And then this is the third one, which is

multiplication of n. And then another call.

Always put a parenthesis before the call, a fact, to get the argument to that I

need to call minus with n and 1, close, close, close, close close.

And let's run this, and if I do fact of 5, I get 120 in, and if I do fact of 10 I

think I get about 300,000. Oh, 3, 3.6 million excuse me.

Okay? So, that version was right. Now, let's do a bunch of versions that

are wrong, and try to figure out why. So let me do, I'll call it fact 1.

N if equal n 0, then 1, else n fact 1 of -n1,

close everything, and run it. It all seems to be fine.

I call fact one with five, [COUGH] and I get procedure application expected

procedure given one. No arguments, and that's exactly right.

If you look up here, what I did while I was talking to you and typing is I put

this 1 in parentheses, and as an expression, that means call 1 as a

function with no arguments. There's no type checker to separate our

functions from our integers, but when we went execute this in the base case when 1

was 0 That's when we got the error. So, we had already made about five

recursive calls, and then we got the error.

And we would fix this us by deleting these parentheses.

We can just leave this in here, because As long as we don't call that function,

it won't be a problem. Let me show you a small variant is

fact1b. Suppose I made the same mistake.

Alright, just like this. Alright, so you might think, if you're

not paying very careful attention, that this fact1b is exactly like the first

line, and yet it totally seams to work. In fact, this will work for almost every

argument. The only argument it won't work for is 0.

So what's going on here? well here I, I, I actually made a totally different

mistake, this is wrong. If you call fact1b with a 0 you will try

to apply 1 with 0 argument, but I'm not actually using fact1b recursively here,

I, I wrote fact here, right. I didn't write fact1b I wrote fact, and

so in fact pardon the pun, when I call fact1b with 5 I end up not calling fact1b

again but going up to this first correct version.

And so that's why we didn't get the error unless we called fact1b originally with

0, okay. Good, let's try another 1 how about fact2

excuse me. I need this parenthesis here.

how about if = n 01. Otherwise, n of fact 2.

I will remember, now, to call the correct thing recursively.

[SOUND]. And like that, and click run.

And this is actually a syntax error. So this, it will not allow.

To start. I don't have to test it out to get an

error. Dr.

Racket will detect that, with a good error message here.

If has five parts after the keyword. If is always supposed to have three

parts, and yet clearly, syntactically, it has five,

equal n zero, one, and this multiplication.

And that makes no sense, If has to have three and what happened is I forgot the

parenthesis around the function call to equal, ok? How about if I do it this way?

If, so I'm going to get almost all of this right.

Three terms multiplied by N fact of minus N one.

Just like this, click run, and I get bad syntax multiple expressions after

identifier, indeed I do. So if I say define in a variable, notice

I forgot this parenthesis after the fact3, then it's expecting like a val

binding in ML, right, that I evaluate something here.

But I have 2 things after the variable, this is the first one, this is the second

one, right. I messed up 1 parenthesis, this left

parenthesis is supposed to be over here before the name of the function, not

before the argument. Okay, parenthesis matter, I know I am

typing fast in order to keep the video short but you should think which concerts

am I using. And in this case if you are defining a

function you put a parenthesis before the function name.

You do not put a parenthesis before the argument list.

Look how it up here in the correct version I have this and then I have my

function buddy. Ok, alright lets do another one this one

oh so I need to comment these out these ones so I can get the other ones to go

ahead and click run so I can test them out.

Here is my fourth version of fact how about if equals zero one other wise

Multiply n by my recursive call to fact 4, with -n and 1.

[SOUND]. Click run.

This compiles just fine. Call fact 4 was zero.

I get the right thing, 1. But if I call fact 4 with 5, I get an

error message. And it says that * expects type number as

second argument, given procedure fact4. That's exactly right.

So, it turns out, that multiplication, we saw back in our first or second segment

on Racket, can take any number of arguments, and here I'm passing it three

arguments, n, the function fact4, and n - 1.

Functions are first class, so you can pass them to other functions, but then

the body of multiply says wait a minute, I don't have a number.

I'm going to raise an error. A typechecker in a language like ML would

catch this. In Racket, we have to test our functions

to test this sort of error, then we need to fix up our parentheses.

we need an extra parenthesis before fact4.

And then a after it in order to call multiply with two arguments not three.

OK let's do a couple more here's fact five n if equal n zero one otherwise

multiply n by fact five minus N one. So here, we saw in fact four we had too

few parenthesis. It made us annoyed.

We just wanted to get our homework done so we added some more.

The problem of course is this still works, but we added too many.

And what it says is Procedure Fact five expects one argument given zero.

That's exactly right, right here. I'm calling fact 5 with zero arguments.

Fact 5 which I'm defining recursively right here, expects one argument.

You are not allowed to call functions with the wrong number of arguments, and

we get an error. And then let's do one last one, just

because it's good practice. n times, so this is a very natural thing

to do, because we've all grown accustomed to writing arithmetic a certain way.

And you can probably see the error this time.

I wrote * second. That's supposed to be the function I'm

calling. Instead, what do you think would happen

here? Well, again, the base case is fine, but if n is not 0, then I'm going to try

to treat n as a function. So it expects some sort of error message

where the number I called fact 6 with is trying to be called with some arguments,

alright? When you look at your code carefully you

can sometimes come up with a better error message then you would get from a system

that has no idea what it is your trying to do.

Here I think it will actually do a pretty good job.

So the procedure application, expected procedure given one arguments where

procedure times 1. And, what actually happened is, you would

think this happened when n would be 5. Why, why does it say given 5? Well, it

never got to this call. It went ahead and did the recursion, and

that did the recursion, and that did the recursion, and it's on the way back out

of the recursion that it first detects the error.

When it tries to say, 1 times, and the recursive result, 1.

And if, I'm going to write this out here in Racket, you have 1*1, that's going to

give the exact same error message, because it's going to say that it

expected a procedure in that first position, and you have a 1.