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.
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. The three parts are not quite equal in length: Part A is almost as substantial as Part B and Part C combined.
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.

AL

Great course!\n\nI think this course has just the right balance of theoretical background, formal definitions, and actual examples to make "just right".\n\nThanks Dan, and everybody else involved!

SK

Mar 24, 2017

Filled StarFilled StarFilled StarFilled StarFilled Star

An excellent course! Make sure you really have enough time to take this course. There are a lot of videos, but they worth watching. I'd recommend this course to everyone involved in programming.

À partir de la leçon

Section 4 and Part-A Exam

We finish Part A of the course with this module. As explained in more detail in the welcome message, we discuss type inference, ML's module system, and the fundamental idea in computing of two computations being equivalent. There is no programming assignment -- instead there is an exam covering all of Part A. Finally, there is a brief wrap-up video for the end of Part A that also looks ahead to Part B and Part C -- we have put it after the exam, so don't overlook it.

Enseigné par

Dan Grossman

Professor

Transcription

[MUSIC]. In this segment we'll start our study of ML's module system. This is a pretty big topic, it'll go on for several segments. Even though we're just going to scratch the surface and get the basic ideas of what we can do with the module system. So the motivation here is that so far all of our programs have just been one top level sequence of bindings. We might have helper functions or local bindings inside of functions, but we've just had that one sequence. And this is really not a good organization for larger programs you might write, and ML realizes this, and like many programming languages, it has more support for organizing larger programs. So the main thing we'll focus on are ML's structures. A structure defines a module where you can have a bunch of bindings that are separate from other modules and their bindings. So, in this segment we'll just go over the syntax, and discuss the basics, and then we'll move on from there. The main, construct we'll have in this segment, is the structure binding. So you say structure, the name of your module. It's conventional to start with a capital letter, but it doesn't really matter. Equals, struct, then any bindings you want, any kind of bindings, data types, exceptions, variables, functions, and then n. And then inside a module, that sequence of bindings is just like we've been seeing a top level. You evaluate each in order, later ones can use earlier ones. And then after you've defined the module Outside the module, you can use those bindings, but you can't use them directly. Syntactically, if there's a binding in there called bindingName, you write Module.bindingName. This is probably not surprising to us because we've already been using some of the modules in the standard library, and that's why when used a function like String.toUpper, it was the toUpper function definied in the string module. So what we're learning here is how to define our own modules. So I have an example here that I already had written out. this is a structure that I've highlighted right here, it's just a silly example. I've called it MyMathLib, and in it I've got three bindings, a little factorial function, a variable that's initialized through half of pi, notice I'm using the math library here which has already defined pi. And then a little function that doubles it's arguments. And now that's the end of my module here. And then outside the module I'm continuing my program and I can use bindings in the module. So I could say val pi equals MyMathLib.half_pi plus MyMathLib.half_pi, and val 28 equals mathlib.doubler of 14. So we can evaluate this program just like any other program. We can say name, space, management, dot SML and if we do that, we'll see that the rupple is telling us that there is indeed a structure my math. Lid, that has in it, a fact binding and half pi binding, and a dobbler binding then at top level, we have pi, which turns out to be 3.14159 and 28 which has value 28. I just want to emphasize here what is in our environment. We have, things like MyMathLib and dot fact. That's a function from int to int. We do not have in our top level environment, fact. That's simply not bound. Nor do we have a variable MyMathLib. These structure names are not variables. They're different thing and we have the modules but we have to use the bindings in them. We can't use the whole binding at once like you see here. There is no such thing as my math lib. That's just part of the module system. Which is a little bit different from the rest of the language. Okay, and of course, we can you know, say MyMathLib, mat, [LAUGH] MyMathLib.half_pi plus 1, and that will work just fine. except that I have to say 1.0 and then it will work just fine. Okay? So, what we have done so far is what I'll call namespace management. By using modules, we can keep the names for different bindings separate and this makes it much easier when you have a large number of functions and variables in your program. You can even have a whole hierarchy ML supports defining modules inside of other modules. And this is great so that a list library could have a map function and the tree library could have a map function. And they don't have to worry about calling them list map and tree map, each one can have a map in its module. Now this is very important for larger programs, but it's just not very interesting. this segment is only a few minutes long and it's kind of all I have to say about it. Yes you should use name spaces and we're glad that language is have them, okay. So, to finish up this segment just one optional feature because people always ask about it sometimes people want to know is there a way to say I want to to be able to use everything in a module without having to type out the module name. And you can. It's with this Open feature that is supporting the mail. You can put this inside of modules, you can put it in the REPL. I'm not a huge fan of it, because it tends to take all those well named things that were nicely in a name space and then open the whole module, which often has more than just what you want. But nonetheless, let me show how it works and how it's really not very necessary. For example, if I thought I was going to call half_pi a lot, I could just say val_hp equals MyMathlib.half_pi. And this works totally fine, and now we can say half_hp plus 1.0, and it works fine. Now, if you really did want everything in the module, then you can say open MyMathLib, and now, I have a top level binding for fact half_pi in doubler. In fact, is now in my environment. I think this is really useful for REPL when you are testing outer module, but other than that, I don't find it particularly useful, especially if you are thinking oh I really want to use fact a lot and you forgot that the module also has the binding doubler. You're actually, when you say open, going to shadow any doubler that might already be in your environment, None the less, if you want to use open, you can. It's in ML, it's in there for a reason. People find it convenient. I consider it an optional topic. And that's our introduction to module systems and using them for name space management.