From the course: Learning Functional Programming with JavaScript ES6+
Currying and partial application - JavaScript Tutorial
From the course: Learning Functional Programming with JavaScript ES6+
Currying and partial application
- [Instructor] All right. So the next thing that we're going to talk about here, now that we've gone through the basics of data manipulation and first-class functions, we're going to move on to what I would consider to be some more advanced functional concepts. And the first one that we're going to talk about here is something called partial application. Now, there is a special version of partial application called currying that we'll take a look at shortly. But first, let's start with the basics. So partial application, in order to demonstrate this concept, what I'm going to do is let's just imagine that we have a simple function called add that takes three numbers. This might seem a little bit odd, but you'll see why I'm doing this in a minute. And returns the sum of those three numbers, right? Now, calling this function is pretty straightforward. You already know how to do it, of course. All you do is you say add, and after that you put a pair of parentheses with three arguments inside of it, right? The same number as the number of parameters that we defined the function with. So if we run our code here by saying node examples/partial-application.js, sure enough, we see that that gives us the result. All right, now, so far, whenever we've seen our functions, and we've seen quite a lot of them in this course, one notable thing about them has been that when we call them, we have to specify all of the arguments in the same time and place. In other words, when we want to call our add function, we have to have all three numbers right then and there, ready to pass into it, to get the result, right? Now, that might seem like kind of a given, but there are actually many situations where it would be very beneficial to be able to specify the arguments not all together, right? Either one at a time or in groups. So to give you an idea of what this might look like, let me show you what partial application would allow us to do. Basically, it would allow us to do things like this. It would allow us to call our add function with a single argument, right? One. Or two arguments, right? You know, some number of arguments less than the total number of arguments. And create a function where those two arguments have been fixed to a given value, right? So we could call this something like const add1 =, and then we call the add function with x equal to 1. And then later on we could call add1 with maybe the two remaining arguments, right? That is what partial application allows us to do, right? It allows us to create a sort of pre-configured version of a function, where one or more of the arguments have been fixed to some specific value. So to show you what partial application looks like in code and how to actually make it possible, let's take this add function that we have here. And what I'm going to do is I'm going to create a new function here called addPartial. Now, this addPartial function is going to allow us to partially apply the first argument of the add function, x. And here's how it's going to do that. addPartial is simply going to be a function that takes one argument. And guess what it's going to return? It's going to return another function, which I'll put in another line so that you can kind of see it a little bit better here. It's going to return another function that takes the other two arguments. And then once we have all three arguments, we're simply going to call add, the original function, with those three arguments that we've accumulated, right? Now, again, this looks a little bit funny, perhaps, at first. And maybe it would be better if I put it all on one line, or maybe not. But the point here is that we can now call this addPartial function, and we get to pass in the arguments in different times and places in our code. So here's how we can use this thing now. We can say const add1 = addPartial. And then we're going to call that with the first argument, x, set to 1, right? Look what this is doing. This is pre configuring this x argument to be 1, so that we only have to specify the other two arguments, right? So let's just go back to there. All right, we'll change that back to x and x. And now, right, now that we have the add1 function, we can just log out add1 called with any other two arguments, right? We could say 10 and 11, for example. And if we run our code, sure enough, that gives us 22. 10 plus 11 plus 1, right? So in other words, what's happening here is we're specifying the first argument here, 1 as x, and then when we call the return function, right, this function here with the other two arguments, it has all of the arguments in the same place, and it simply calls whatever function we wanted to partially apply with those three arguments. Now, this might seem a little bit abstract right now, but there are actually a lot of different situations where partial application can be helpful. For example, let's imagine that we have another function. I'm just going to sort of draw a divider line here to keep things separate. Let's imagine that we have a function here called something like getPropertyWithDefault. And what this does is it takes an object, it takes a property name, we'll just call that key, and then it takes a default value to return if the object doesn't have that key. All right? Well, here's what this is going to look like. It's pretty straightforward. We're just going to say if (obj[Key]), then we're going to return obj[Key]. Otherwise, what we'll do is we're going to return the default. And oops, we need to name that defaultValue here, because default is actually a JavaScript keyword. And that's our getPropertyWithDefault function. Now, what you can probably imagine is that there are going to be a lot of situations where this getPropertyWithDefault function is going to be called with the same arguments for key and defaultValue, right? So you might have a situation where you want to get, let's say, the 'name' property of different objects with the same defaultValue, right? So maybe we have a person object here, and we have the key 'name,' and then we have the default value of maybe like 'N/A.' And then later on, we do the same thing with a different object, maybe person2, 'name,' 'N/A.' Then, later on, maybe we do the same thing with a third object. Maybe this one's a building or something like that, instead of a person. Same thing. 'name' and 'N/A. And so on, so forth, right? Now, in this case there's a lot of repeated code. And if we decided to, let's say, change the name of the 'name' key in our objects to maybe something like 'displayName,' we would have to go through all of these references to 'displayName' and make that change. We'd have to change this to 'displayName,' this to 'displayName,' this to 'displayName.' You know, we'd have to make that same change in a lot of different places. Same thing if we wanted to change the default value for all of these things. Now, here's an alternative. Because of what we now know about partial application, we can actually just create a partially applied version of this like so. What we're going to do is we're just going to say const, and we'll say something like getPropertyPartial. And we get to decide which arguments and in which order they're passed. So for example, we might want to allow the calling code to specify the key and defaultValue here. And then we simply have to return another function. All right? I'll put that down another line here, again, just to make it a little bit easier to read. That takes the object and simply calls getPropertyWithDefault with all three of those arguments put together. All right, so we're going to say object, key, and defaultValue like so. And now we can simply create our own getName function automatically by just saying getPropertyPartial and passing 'name' and 'N/A.' And now we can simply use this getName function in all of these cases instead of having to specify the 'name' and 'N/A' over and over again. And this is a lot easier now than what we had before. Because if we want to make a change to, let's say, the 'name' property, here, let me just finish doing that real quick. getName(building). If we want to make a change to what the name of this property is, we can just say, you know, 'displayName.' And if we want to make a change to the default value, we can just change that in one place. So that is the power of partial application. And by the way, currying, in case you're wondering about that word, is simply a specific case of partial application where all of the arguments are passed in one by one. So you end up with something that looks a little bit like this. And it looks strange, but what it lets you do... Here, let's just change it back to there. There we go. What it lets you do is choose exactly how many arguments you want to partially apply at any given point in time, right? So if we only wanted to specify the 'name' property here, like so, we could just say getPropertyPartial('displayName'). If we then wanted to say getNameWithDefault =. And then we could say getName, and we provide the defaultValue. And now we could use getNameWithDefault each time. All right? So that's the basic idea of currying there. You can choose whether or not you want to use currying. I usually stick to using just plain old partial application, like what you see here. But the choice is up to you. So that is the basics of partial application in functional programming.