Channels ▼
RSS

Open Source

Currying and Partial Functions in JavaScript


In some purely functional programming languages, a function is not described as being called or invoked, but rather it's applied. In JavaScript, we have the same thing — we can apply a function using the method Function.prototype.apply(), because functions in JavaScript are actually objects and they have methods.

Here's an example of a function application:

// define a function
var sayHi = function (who) {
     return "Hello" + (who ? ", " + who : "") + "!";
};
// invoke a function
sayHi(); // "Hello"
sayHi('world'); // "Hello, world!"
// apply a function
sayHi.apply(null, ["hello"]); // "Hello, hello!"

As you can see in the example, both invoking a function and applying it have the same result. apply() takes two parameters: The first one is an object to bind to this inside of the function; the second is an array of arguments, which then becomes the array-like arguments object available inside the function. If the first parameter is null, then this points to the global object, which is exactly what happens when you call a function that is not a method of a specific object.

When a function is a method of an object, there's no null reference passed around (as in the previous example). Here the object becomes the first argument to apply():

var alien = {
     sayHi: function (who) {
          return "Hello" + (who ? ", " + who : "") + "!";
     }
};
alien.sayHi('world'); // "Hello, world!"
sayHi.apply(alien, ["humans"]); // "Hello, humans!"

In the preceding snippet, this inside of sayHi() points to alien. In the previous example, this points to the global object.

As the two examples demonstrate, it turns out that what we think of calling a function is not much more than syntactic sugar, equivalent to a function application.

Note that in addition to apply(), there's a call() method of the Function.prototype object, but it's still just syntax sugar on top of apply(). Sometimes it's better to use the sugar: When you have a function that takes only one parameter, you can save the work of creating arrays with just one element:

// the second is more efficient, saves an array
sayHi.apply(alien, ["humans"]); // "Hello, humans!"
sayHi.call(alien, "humans"); // "Hello, humans!"

Partial Application

Now that we know that calling a function is actually applying a set of arguments to a function, is it possible to pass just a few of the arguments, not all of them? This is actually similar to how you would normally do it, if you were dealing with a math function manually.

Say you have a function add() that adds two numbers together: x and y. The following snippet shows how you can approach a solution given that x is 5 and y is 4:

// for illustration purposes
// not valid JavaScript
// we have this function
function add(x, y) {
     return x + y;
}
// and we know the arguments
add(5, 4);
// step 1 -- substitute one argument
function add(5, y) {
     return 5 + y;
}
// step 2 -- substitute the other argument
function add(5, 4) {
     return 5 + 4;
}

In this snippet, the steps 1 and 2 are not valid JavaScript, but this is how you would solve that problem by hand. You take the value of the first argument and substitute the unknown x with the known value 5 throughout the function. Then repeat with the same until you run out of arguments.

Step 1 in this example could be called "partial" application: We only applied the first argument. When you perform a partial application, you don't get a result (a solution), but you get another function instead.

The next snippet demonstrates the use of an imaginary partialApply() method:

var add = function (x, y) {
     return x + y;
};
// full application
add.apply(null, [5, 4]); // 9
// partial application
var newadd = add.partialApply(null, [5]);
// applying an argument to the new function
newadd.apply(null, [4]); // 9

As you can see, the partial application gives us another function, which can then be called with the other arguments. This would actually be equivalent to something like add(5)(4), because add(5) returns a function that can then be called with (4). Again, the familiar add(5, 4) may be thought of as not much more than syntactic sugar instead of using add(5)(4).

Now, back to Earth: There's no partialApply() method and functions in JavaScript don't behave like this by default. But you can make them, because JavaScript is dynamic enough to allow this.

The process of making a function understand and handle partial application is called currying.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Comments:

Video