This course has been updated! We now recommend you take the Functional-Light JavaScript, v3 course.
Transcript from the "Exercise 1 Solution Part 1" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Kyle Simpson: We said in the slides, before I introed the exercise, we said in the slides portion that one of the ways to turn a stateful program, a side effect program into a pure program, is to pass in the entire universe of state. Now there's lots of different ways to do that.
[00:00:21] You can pass it in as an object, of course. Here, we're just being very simple to illustrate the concept. There's a couple of variables that represent the state. So what are those variables that represent the state, and let's look closely. Does x represent the state of our program?
[00:00:37] Not really. x is a parameter to the universe, but it's not really part of the state. So we don't necessarily need to represent x in some stateful fashion, although we're gonna need x. So it's gonna need to be one of our arguments. Well, what about y? y clearly is something that changes over time.
[00:00:55] It's incremented there on line 2. Something that changes over time, it is part of our state. So we're gonna need to pass in that initialization of that state, initializing it, of course, to 5, like we do on line 6. So, y is part of our state. And z, is z part of our universe?
[00:01:13] Does z change over time? Well, z is an output of our program, but it's not something that is reused each time. It's reset, and we just assign it on line 3, and it doesn't matter whatever value it previously had. So, z is not actually something we need to import as part of the state of our universe, it's just something that's going to represent an output, okay?
[00:01:36] So, all of that notion is just to help you with the concept. The syntactic things aren't gonna look very much different from what we already do. So, let's use a bar, and I used, by the way, these function boo bar sorts of things, because if I gave you too heavy of something that was kind of a specific problem domain, then it starts to get a little bit like your brain has to not only wrap your head around these concepts, but your brain also has to wrap your head around that particular problem domain.
[00:02:06] And if it's one you're familiar with, great, if not, well, now you have two things to learn. And I want you to have as few things to learn as possible. So that's why I use the foo and the bar thing. But we will, to whatever extent possible, try to make these things a little bit more concrete as we go along.
[00:02:21] All right, so, one thing I'm gonna do, and this is just a complete pure side note, but I have taken recently in my programming to inverting the way I normally used to write the functions at the top and the executable code at the bottom of any particular scope, any particular file, or any particular function.
[00:02:37] And I now do the reverse. And the reason I do that is because it's much easier, I've found this maintenance wise to be much easier to open up a file or to look at a function, and at the very top, be able to see everything that it's doing.
[00:02:49] And then I rely upon function decorations and the fact that function decorations are hoisted to, that they'll be definable soon. So I can call foo before it's technically been declared, because JavaScript is compiled and the scope is gonna take care of that with the shorthand way of talking about that is hoisting.
[00:03:07] I talk more about that in the books and in the advanced training video, if you're more interested in that. But I'm gonna move the function to the bottom just because I'm trying to practice that more as a discipline for myself. I find that to make code a little bit easier to understand.
[00:03:18] So why is it going to be a variable like a local variable? It's gonna be something that's passed in for sure. And in fact, we're also gonna pass in x. Cuz we need that x value to be used. So I'm not gonna declare y or x as variables, but I do need a z because I'm gonna need to be able to return a z.
[00:03:42] So the foo function, as we know it, takes an x. Now I don't have to pass the x in. I could take the x out, and just simply reference it. You'll notice there that on line 8, I have an x, and I can reference that. That's gonna be called closure.
[00:03:56] But we're not getting to the closure point yet. So I'm gonna formally pass in the x. And that means the x needs to be passed in here. Whatever the x was given to my universe, I'm gonna pass that in to this inner impure function. Now you notice that I'm changing a y.
[00:04:11] That, of course, is changing it as a result of that lexical scope, that closure over the y. And also the z, it's changing the z. So I'm gonna call the function foo. And then I know that my y and my z have been set to their proper values for the end of my program.
[00:04:30] So what I need to do, just simply return them, and I'm gonna encapsulate them in something, and a functional programmer usually turns to an array when they wanna encapsulate some value. Lists are particularly convenient, and we'll get more to lists later. So, I'm just gonna simply return my y and my z.
[00:04:45] Now, you notice I'm not returning x. I could, but x isn't something that's changing as a result of any of what we're doing. It's just simply an input to my universe. It's a starting state, it's an initial state, so I don't really need to return it. So I really only need to return that which changed, that which would be something that somebody wanted to observe.
[00:05:03] Now, if somebody didn't care about observing y, for example, of course, this program changes y, so you probably do. But if you didn't care about changing y, you wouldn't even wanna return that. You only wanna return that which somebody would wanna observe. Okay, so that's our bar function.
[00:05:18] And it's gonna execute the foo function, and then return the result of whatever those values are. Clearly on the inside, this function is as impure as it gets, okay? Hopefully, everybody can agree with that. But from the outside perspective, now, bar takes in a universe, and it returns back a result.
[00:05:37] And nothing on the outside of bar changes a result of calling bar, which means we can call bar over and over and over again with the same inputs and get the same outputs. That's how we've made it pure. So just to illustrate that, instead of calling these foo variables down here, I'm gonna call a bar.
[00:05:53] I'm gonna pass in an x, which in this case, was the 20, and I'm going to pass in a y. You remember, I've taken it out now, but remember, our initial value state that we cared about with y was 5. So if I pass in the value 20 and ask for the value 5 back, what am I getting?
[00:06:11] Well, let's run through it just to make sure, and then you can, of course, execute this in the console of your browser if you care. But if I pass in 20 as x, 20's gonna come in as x. If I pass in 5 as y, 5 is gonna become 6.
[00:06:26] And then I'm gonna say 6 * 20 which is 120, and that's gonna be my z. So what am I expecting back as my return value? I'm expecting back an array with 6 and 120. And if you try it, you'll notice that you get that value back, okay?
[00:06:41] Now, if I called bar(20, 5) again, I'm gonna get the exact same state back because now I'm dealing with a pure function. There are no side effects, it's a pure function, okay? And of course, if I call bar with 25 and I call it with 6 now because 6 was my new state that I'm observing from y.
[00:07:02] If I take that state and I pump that back in as the starting point for my second run of this universe, now 6 is gonna become 7. 7*25, we're gonna get, y is gonna be what now?
>> Speaker 2: 7.
>> Kyle Simpson: 7, and we're gonna get 125 back, okay.