[As described below, this is Part B of a 3-part course. Participants should complete Part A first -- Part B "dives right in" and refers often to material from Part A.]
This course is an introduction to the basic concepts of programming languages, with a strong emphasis on functional programming. The course uses the languages ML, Racket, and Ruby as vehicles for teaching the concepts, but the real intent is to teach enough about how any language “fits together” to make you more effective programming in any language -- and in learning new ones.
This course is neither particularly theoretical nor just about programming specifics -- it will give you a framework for understanding how to use language constructs effectively and how to design correct and elegant programs. By using different languages, you will learn to think more deeply than in terms of the particular syntax of one language. The emphasis on functional programming is essential for learning how to write robust, reusable, composable, and elegant programs. Indeed, many of the most important ideas in modern languages have their roots in functional programming. Get ready to learn a fresh and beautiful way to look at software and how to have fun building it.
The course assumes some prior experience with programming, as described in more detail in the first module of Part A. Part B assumes successful completion of Part A.
The course is divided into three Coursera courses: Part A, Part B, and Part C. As explained in more detail in the first module of Part A, the overall course is a substantial amount of challenging material, so the three-part format provides two intermediate milestones and opportunities for a pause before continuing. The three parts are designed to be completed in order and set up to motivate you to continue through to the end of Part C.
Week 1 of Part A has a more detailed list of topics for all three parts of the course, but it is expected that most course participants will not (yet!) know what all these topics mean.

Avis

KR

I'm a pretty experienced C/C++ programmer and this course has been a brilliant introduction into functional programming and the underlying philosophies underpinning programming languages in general.

JM

May 09, 2018

Filled StarFilled StarFilled StarFilled StarFilled Star

DO THIS COURSE. It brings together everything in part A. In particular, the final shorter week on the differences between Statically and dynamically typed languages is mind-bending and brilliant.

À partir de la leçon

Section 5 and Homework 4 (First Module with Racket)

Let's get started programming with Racket and then learning idioms related to delaying evaluation. The welcome message has a few additional comments about picking up a new language and how to approach the homework assignment, so let's get started...

Enseigné par

Dan Grossman

Professor

Transcription

[MUSIC] In this segment, I want to introduce the cond construct into Racket. It's useful in place of nested if, then, else expressions. It's better style and it's not very hard to learn. I just put it off to get us started with the bigger ideas in Racket. But you do want to use this. Whenever you have a bunch of nested ifs where your else branch, your false branch is another if. And then the else branch of that is another if, cond is definitely better style. You can think of cond as just syntactic sugar for nested if, then, else expressions. Or if you prefer to think of if then else as syntactic sugar for a cond with just two branches, that's just fine too. So here's how cond works. It's just a special form, C-O-N-D, so of course it has a parenthesis at the beginning and at the end. We then have in parentheses n pairs of expressions, right? So I have a bracket because that's the convention. Semantically it doesn't matter, just syntactically it's better style to have the bracket. It doesn't matter, you can use round parentheses if you want. Then one expression, then another expression. End that branch, another one, another one. And the way this works is all of these first ones are tests. And all the second ones are what to do if that test is true. So if the first one is true, then do the second one. Else, if this is true, do this one. Else if this one. And you stop, and your result is the first branch where the thing on the left was true. And then you evaluate the thing on the right and that's your answer. Now as a matter of style it's very important that your last branch typically be just true which we write in bracket #t. This is your default case, this is saying in any other case I want to evaluate this last expression and that's my answer. If you do not do this, and your last test expression also evaluates to false. Then cond will return some strange void object which is a bad idea in Racket. It will not produce an error here. But probably it's going to return some result that someone else doesn't want to use, and you'll end up confusing yourself. So always make your last branch have its test a true, okay? So, let's go over here to DrRacket. Here are the sum functions that I wrote in the previous segment. So this first one works on a list of numbers that could have nested within them other lists of numbers and so on as deep as you want. And it's an error to have anything in there that's not a list or a number. And then the second version, that if there's some non-list or non-number nested somewhere in a list, we just skip over it. And we can rewrite each of these using cond. And so I'm going to do that just in a different file here. There we go. And this will not be very difficult, so I'll call these sum3 and sum4, to continue what we were doing in the previous section. And I can have a cond, which of course can have any number of branches I want. And the first branch will be that if the input xs is the null list, the empty list, the result should be zero. Otherwise, if the first element is a number so number of car of xs then add the car of xs to the recursive sum of the cdr of xs. That will end that branch. Notice you can type round parentheses and if they match square brackets, DrRacket will turn it into a square bracket for us. And then, any other case for this version. So for #t, I'll go ahead and assume that the first element of xs is itself a list. So I know how to sum a list. I call sum3s and then I need to sum3 the cdr of xs. Close that, and this should all be correct. If we compare it to our other version, I'm going to flip that over here, you'll see that we have the same three cases. If it's null zero, the first thing in the list is a number, do this addition. Otherwise do this addition. But you'll probably agree with me that it's easier to read laid out as this cond. And we can see the three tests, null, number and true quite easily. And then what to do in each case by the expression that follows the test. Okay, so that's sum3. Now let me quickly do sum4. It's the same idea. I'll have a cond and if the list is empty, then return zero. If the first thing in the list is a number then, number car of xs. And in fact it's exactly the same as before, car of xs, sum4 now cdr of xs. Right, otherwise I have another test in this version. Where I ask, well, is xs a list? Because if it is, then I want to do what I used to do just by the default assumption. But this time I checked that it was a list so you can see the difference between the two versions quite easily. And in any other case, skip the car of xs and just sum the cdr of xs. And if you look back this is exactly like sum2, just laid out nicely with the cond construct. So that's our example, now what I want to do is go back to the slides and talked about one other issue, okay? As before, sorry, here is where I want to go, okay. So for both if and cond, I just didn't tell you this for if and now I'm telling you for both. The test expression, that first expression does not have to be true or false, #t or #f. It turns out it can be anything, it's never an error and it's fine. So what is the semantics? The semantics in Racket is that anything other than false counts as true. So the only way to take the false branch is if you have #f. But to take the true branch, you do not need #t, you just need anything that is not #f. This is fairly common in dynamically typed languages. Some dynamically typed languages make other things false. Things like the empty list or the empty string, or things like this. It's not true in Racket. In Racket there is exactly one thing that's false, and that's #f. Everything else counts as true. Now this makes no sense in a statically typed language. In a statically typed language, we would insist that a conditional expression take something of type bool for its first argument. Since everything has exactly one type, there's no point in allowing anything to be in that first position. But in a language like Racket, you can do this. Now, a lot of people consider this bad style. A lot of people consider this convenient and okay. And some people are kind of in between and say it depends on the situation. I'm not a huge fan of this construct, but since it reinforces the idea that Racket supports dynamic typing, I thought I would show it to you. So let's do a couple quick examples here. So first of all, let me just click run and do something at the here. So what if I said if 34 then 14 else 15. Well, since 34 is not false, it must be true and I get 14, okay? So it's just that simple, and I could say, if, empty list, 14 else 15 and I will get 14 and so on. But if I say #f, then I get 50. So now let just paste in a quick example of where this is useful, I don't want to take the time to type it all out. And you don't need this, okay? You could get pi and racket without this feature There we go. So what this function does is it takes in a list. Just a list, no nested list or anything. And counts how many falses are in it. Okay, so let me just run this so we can see it in action. And so if I count falses of the list 34 true and high. I should get zero, but if I add in here a couple falses, maybe one at the beginning. One there and how about a couple at the end, then I get four. And that's all it does. It counts how many falses there are. Use cond, which we introduced here, and we say that if the list is empty, then there are zero falses in it. If the car of xs is not false. Well, here is one way to do that, right? If car of xs is anything other than false, then this test will be true. And so we'll counts the falses in the. And in any other case, the only case that's left is that the first thing on the list was false, and then we would add one to count falses of cdr of xs, okay? So that is an example of using this feature that everything that is not #f is true. The only thing that is false is #f. But the main idea in this segment was using cond for better style. And now we can use it in all of our homework problems in Racket programming rather than nested if, then, else.