Wednesday, May 16, 2012

Functional Closure

When you look at it, the closure library is perfect for functional style programming. The whole library is given to you as functions rather than methods that have to be put on objects.

Unfortunately it is lacking though. goog.bind and goog.partial only get us some of the way and there could be a better way to do it. That's why I'm happy to introduce Functional Closure which will help all your dreams come true (well, at least help you in your functional style efforts).

The main function in functional closure is func.curry. This will not only allow you to partially apply only the variables you select but will also return a function that will continue to curry itself until you tell it to stop. You can also set a minimum number of inputs which when passed will give you back a value.

So how does it work? say we want to find the maximum of 10 numbers. We can curry Math.max like so:

var max = func.curry(Math.max, 10);
max = max(1,2,3); // we can pass in any number of values at a time
max = max(undefined, 5); // we can pass in undefined to skip a value
max = max(4)(6)(7); // you can pass in values like this (the 4 will be used where the undefined was put)
second = max(8) // the curry returns a new function you can assign to another function
second(); // 8 - passing no arguments will execute the function as it stands
max(8, 9, 10, 11, 12); // 12 - once you pass the minimum passed in you get a result

You can also not pass a minimum to just keep returning the curry until you call it with no arguments.

Great, now what else does it have? Well now we have curry we might want another way to curry the right arguments. Here we have func.flip. Say you want to map something that will increment the number, you can flip around the closure libraries array functions to do that for you:

var addOneToAll = func.curry(func.flip(goog.array.map), 2)(function(a) {return a+1;});

Want even more? Well the library already has these made for you. You can just use func.map which is already curried so the above is equivalent to:


var addOneToAll = func.map(function(a) {return a+1;});

There are a range of functions you can use - checkout the read me for more information.

Great, how about point-free style? Well we've got that covered to. func.compose will let you join up functions the way you want to. For instance let's say I want a filter function that will look at the models of an object and see if they're not in an array of existing models:

var notInModels = func.compose('!x', func.isIn(models), 'x.getModel()');

WOAH! slow down there, what happened? Well most the 'func' functions can also take strings and convert them to functions. If you want a simple lambda that's a single line just write it with x as the input and it will return the result.

Want to learn more? Checkout the github repository. The library is built to run with closure tools and is built with inspiration from functional javascript and http://drboolean.tumblr.com/


3 comments:

  1. http://osteele.com/sources/javascript/functional

    guess you already have seen this?

    ReplyDelete
  2. yep - was one of the big things that contributed to me doing this. If you have a look at the last line of the article I put two links up and the first one is actually that url

    ReplyDelete