So we've seen how to use non-mutating sequence algorithms. And we saw in some instances that we wanted as an argument a predicate argument or function argument. And here comes a new, very exciting, very interesting, to my great surprise a feature that got included in the latest version of language, lambda expressions. So lambda expressions are an idea that come from Lisp. Lisp is the original major AI language. It was based on Church's lambda calculus. So it was sort of a logician's idea of doing computing. It wasn't worried about efficiency. It was initially implemented with a compiler or interpreter, not a compiler, but an interpreter. So it was typically very slow, an order of magnitude slower than the hardware. So in some some sense, lambda expression came from a language computing milieu that was the opposite to the milieu, the system implementation language idea behind C. So these two things are strikingly different. So to find that the, in effect, furthest away idea from what initially was C, as a system implementation, get added into the new version of the language, lambdas, was just striking to me. But it makes perfect sense. You almost can fall in love with the feature, even if you don't have Lisp experience, or in more modern terms, functional languages such as Haskell, which also make very strong use of it. So if we go back to what we just saw where in for each, you need a function, lambda expressions give you a way to write a function in place. An unnamed function can be written in place. So here's old style. Let's look at an old style for each. We have two named functions, this is a named or ordinary function. It's pretty easy to see what they do. Increment takes call by reference an integer, has a local static variable. You have to remember what static means in this context. And you recall, if you were all here in my classroom, I'd ask this as a question for whoever could get it first. Static means when the call to increment exits, the value is retained. So we start with n=1. But notice, n is going to change. So on the next call, n is going to start at 2, and each in turn is going to change by plus 1. So each call is going to have a different starting value of n, that's what static means there. For those of you who are aficionados of programming languages, this concept was in Algol 60 first as what was called an owned variable. The second thing is this outvec, which is just putting out a value, right. It's non-mutating, it just sticks out a value into cout, the value i. So now, let's look at what these do. Here's an integer vector, it's got six elements. Here's for_each. And the for_each over the vector range does an increment. So what is it going to do? It's going to shove into, because it's call by reference, a sequence of values. And they're going to be the values, I believe, 1 through 6. So we're going to get those values shoved into this container, into this sequence, okay? And then this for_each which uses outvec, so here's the two functions. They're being applied to the sequence. One of the functions does the initialization. And the other function does the output, old style. So what got printed, that's for you to decide. Think about that a second. The answer is, static keeps the value on exit, so the print outs are 1 through 6. Now, what if we substitute instead of the named functions, a lambda expression? First off, we have to know how to write a lambda expression, an unnamed function. I'll guess I'm not that happy about the syntax, but this bracketing syntax is like saying lambda. So in that context, again, here's a place where I'm not completely sympathetic to the C ethic, but the C ethic, reuse symbols, let context decide their meaning. In some ways, that makes the language subject to readability constraints. Because many cases, the empty brackets are really intended to mean array declaration. If you find them contextually in a function call, they mean a pointer in old C. So the fact that they chose not to define something that would make it clear, like lambda, which would make it very clear, is just habitually something that the C community does. In a nice way, it makes us all feel cognoscente, that we are into all this esoterica. Okay, so it was taken from Lisp, it's a unnamed function. Here is in effect the parameter list for the unnamed function. And here is the executable. So the executable and the parameter list look pretty much the same. So it's not like you're going to have to learn a lot, you just have to learn to use it, and then, contextually, you drop it in where you need it. Now, that's frequently local functions. Here are some lambdas, just very simple ones. The first one is something that does a calculation. And you get the value of an integer value times a double value, and that means that it's going to return double. And the compiler understands that, so it's as if it would have double lambda argument list, here. So you don't have to specify the return type. The compiler makes sure you get it right, it's a deduction. That's nice, that's a convenience. And it's also a type safety issue. And here, again. You're going to deduce that it's an integer value, but here we've also said it explicitly. You might want to read more about lambdas. Where do we say it explicitly? We said it explicitly with this notation, so we can also have said arrow double, showing arrow again. Think about arrow, arrow occurs lots in old C, it's the pointer operation in old C. Here, contextually, it's used to say, the return value is double. Again, it sort of gives you a little bit of conciseness and mysteriousness which is also very clever. So we've seen templates. And you should be able to with those templates, and with things like those predicates, you should be able to turn them into lambda expressions. So you could have rewritten the old style for_each that I just showed you and rewritten it with dropping in a lambda expression where needed. Mutating functions, that's sort of the next. Mutating functions, a traditional prototype archetypal mutating function is copy. In copy, we have three iterator ranges. We have. So b2 is telling us, take a copy, take these elements, and make a copy starting at wherever b2 is, this is the copy. This is the original. Why don't I specify an e2? Because e2 is deduced, right? If I'm going to copy these many elements, I know how many elements I'm copying without having to specify an e2. And then we return a position at the end of the copy. So we could copy over, and that's why it's mutating, and also it's directly mutating, because we may be adding to something like a vector or a deque.