Книга: Functional Programming in JavaScript
Назад: Partial function application and currying
Дальше: Partial application

Function manipulation

Actually, before we go any further and explain just how to implement partial application and currying, we need a review. If we're going to tear JavaScript's thick veneer of C-like syntax right off and expose it's functional underbelly, then we're going to need to understand how primitives, functions, and prototypes in JavaScript work; we would never need to consider these if we just wanted to set some cookies or validate some form fields.

Apply, call, and the this keyword

In pure functional languages, functions are not invoked; they're applied. JavaScript works the same way and even provides utilities for manually calling and applying functions. And it's all about the keyword, which, of course, is the object that the function is a member of.

The function lets you define the keyword as the first argument. It works as follows:

console.log(['Hello', 'world'].join(' ')) // normal way console.log(Array.prototype.join.call(['Hello', 'world'], ' ')); // using call

The function can be used, for example, to invoke anonymous functions:

console.log((function(){console.log(this.length)}).call([1,2,3]));

The function is very similar to the function, but a little more useful:

console.log(Math.max(1,2,3)); // returns 3 console.log(Math.max([1,2,3])); // won't work for arrays though console.log(Math.max.apply(null, [1,2,3])); // but this will work

The fundamental difference is that, while the function accepts a list of arguments, the function accepts an array of arguments.

The and functions allow you to write a function once and then inherit it in other objects without writing the function over again. And they are both members themselves of the argument.

Note

This is bonus material, but when you use the function on itself, some really cool things can happen:

// these two lines are equivalent func.call(thisValue); Function.prototype.call.call(func, thisValue);

Binding arguments

The function allows you to apply a method to one object with the keyword assigned to another. Internally, it's the same as the function, but it's chained to the method and returns a new bounded function.

It's especially useful for callbacks, as shown in the following code snippet:

function Drum(){   this.noise = 'boom';   this.duration = 1000;   this.goBoom = function(){console.log(this.noise)}; } var drum = new Drum(); setInterval(drum.goBoom.bind(drum), drum.duration);

This solves a lot of problems in object-oriented frameworks, such as Dojo, specifically the problems of maintaining the state when using classes that define their own handler functions. But we can use the function for functional programming too.

Tip

The function actually does partial application on its own, though in a very limited way.

Function factories

Remember our section on closures in , Fundamentals of Functional Programming? Closures are the constructs that makes it possible to create a useful JavaScript programming pattern known as function factories. They allow us to manually bind arguments to functions.

First, we'll need a function that binds an argument to another function:

function bindFirstArg(func, a) {   return function(b) {     return func(a, b);   }; }

Then we can use this to create more generic functions:

var powersOfTwo = bindFirstArg(Math.pow, 2); console.log(powersOfTwo(3)); // 8 console.log(powersOfTwo(5)); // 32

And it can work on the other argument too:

function bindSecondArg(func, b) {   return function(a) {     return func(a, b);   }; } var squareOf = bindSecondArg(Math.pow, 2); var cubeOf = bindSecondArg(Math.pow, 3); console.log(squareOf(3)); // 9 console.log(squareOf(4)); // 16 console.log(cubeOf(3));   // 27 console.log(cubeOf(4));   // 64

The ability to create generic functions is very important in functional programming. But there's a clever trick to making this process even more generalized. The function itself takes two arguments, the first being a function. If we pass the function as a function to itself, we can create bindable functions. This can be best described with the following example:

var makePowersOf = bindFirstArg(bindFirstArg, Math.pow); var powersOfThree = makePowersOf(3); console.log(powersOfThree(2)); // 9 console.log(powersOfThree(3)); // 27

This is why they're called function factories.

Назад: Partial function application and currying
Дальше: Partial application

bsn
thank
Vesa Karvonen
I hope you don't mind, but I’d like to point you and your readers to my high-performance optics library for JavaScript that is in production use in multiple projects, has comprehensive support for partial optics and interactive documentation: https://calmm-js.github.io/partial.lenses/ (this takes a moment to load — be patient!)