Functional is a JavaScript library for functional programming. It defines the standard higher-order functions (map, reduce, filter) that you can read about elsewhere on the web. It also defines functions for partial function application and function-level programming: curry, partial, compose, guard, and until. Finally, it introduces “string lambdas”, which let you write 'x -> x+1', 'x+1', or even '+1' as synonyms for function(x) {return x+1}.
See the API and examples page for more examples, API documentation, and a link to the source.
String lambdas
Welcome to functional programming! You’ve probably already discovered map and filter. (If not, curl up with Google for a few minutes. I’ll wait.) Try using them in JavaScript. Isn’t it a pain?:
map(function(x){return x+1}, [1,2,3]) -> [2,3,4] filter(function(x){return x>2}, [1,2,3,4]] -> [3,4] some(function(w){return w.length < 3}, ‘are there any short words?’.split(‘ ‘)) ->false
String lambdas let you write these this way, instead:
map(‘x+1’, [1,2,3]) select(‘x>2’, [1,2,3,4]) some(‘_.length < 3’, ‘are there any short words?’.split(‘ ‘))
Some more examples, using just map, filter, and reduce:
// double the items in a list: map(‘*2’, [1,2,3]) -> [2, 4, 6] // find just the odd numbers: filter(‘%2’, [1,2,3,4]) -> [1, 3] // or just the evens: filter(not(‘%2’), [1,2,3,4]) -> [2, 4] // find the length of the longest word: reduce(Math.max, 0, map(‘_.length’, ‘how long is the longest word?’.split(‘ ‘))) -> 7 // parse a binary array: reduce(‘2*x+y’, 0, [1,0,1,0]) -> 10 // parse a (non-negative) decimal string: reduce(‘x*10+y’, 0, map(‘.charCodeAt(0)-48’, ‘123’.split(/(?=.)/))) -> 123
Function-level programming
Value-level programming manipulates values, transforming a sequence of inputs into an output. Function-level programming manipulates functions, applying operations to functions to construct a new function. It’s this new function that transforms inputs into outputs.
Here are some examples of function-level programming with Functional. There’s more in the documentation.
// find the reciprocal only ofvalues that test true: map(guard(‘1/’), [1,2,null,4]) -> [1, 0.5, null, 0.25] // apply ’10+’ only to even values, leaving the odd ones alone: map(guard(‘10+’, not(‘%2’)), [1,2,3,4]) -> [1, 12, 3, 14] // write a version of map that only applies to the evens: var even = not(‘%2’); var mapEvens = map.prefilterAt(0, guard.rcurry(even)); mapEvens(‘10+’, [1,2,3,4]) // find the first power of two that’s greater than 100: until(‘>100’, ‘2*’)(1) -> 128 // or the first three-digit power of two (these are equivalent): until(‘String(_).length>2’, ‘2*’)(1) until(compose(‘>2’, pluck(‘length’), String), ‘2*’)(1) until(sequence(String, pluck(‘length’), ‘>2’), ‘2*’)(1)
Partial function application
Partial function application, or specialization, creates a new
function out of an old one. For example, given a division function:
function div(a, b) {return a/b}
a partial application of div is a new function that divides its argument by two:
var halve = div.partial(_, 2);
Partial application is especially useful as an argument to the higher-order functions such as map, where, given a function div, we can apply it (the first line below) without an explicit wrapper (the second).
map(div.partial(_, 10), [10, 20, 30]) map(lambda(n) {return div(n, 10)}, [10, 20, 30])
The curry function handles a special case of partial function application, and the previous example could have been handled via curry. Partial function application in all its generality is only necessary when you’re specializing not just on all the arguments on the left, or all the arguments on the right, but some distribution of arguments with holes in the middle. To illustrate this requires a function with more than two parameters.
JavaScript doesn’t have many functions with more than two parameters. (splice takes three, but splice isn’t very functional). Here’s a contrived example to start (and a real-world example next).
We’ll borrow one of the few trinary predicates from math: “between”. increasing(a, b, c) tests whether b (the middle argument) lies in the open interval bounded by a and c. Specialize the first and last arguments to produce a functions that tests whether a number is positive, for example.
function increasing(a, b, c) { return a < b && b < c; } var positive = increasing.partial(0, _, Infinity); map(positive, [-1, 0, 1]) -> [false, false, true] var negative = increasing.partial(-Infinity, _, 0); map(negative, [-1, 0, 1]) -> [true, false, false]
Here’s how to use compose and curry to generalize some of the examples from the first section into reusable functions. (You’ll probaby like or hate these function definitions to the extent that you like or hate Haskell.)
var longest = compose(reduce.curry(Math.max, 0), map.curry(‘.length’), ".split(’ ‘)"); longest("how long is the longest word?"); -> 7 longest("I bet floccinaucinihilipipification is longer."); -> 29 var parseUnsignedInt = compose(reduce.curry(‘x*10+y.charCodeAt(0)-48’, 0), ‘_.split(/(?=.)/)’) parseUnsignedInt(‘123’) -> 123
Here’s real-world example: The following line attaches a sum method to Array. Note how the 'this' string lambda, which is short for function(){return this}, moves the object from object position to argument position so that the curried reduce can apply to it.
Array.prototype.sum = reduce.curry(‘+’, 0).compose(‘this’) [1,2,3].sum() -> 6
Here’s another example: If you’re using Prototype, you can replace the first line below by the second:
Event.observe(‘myobj’, ‘click’, function() {...}) onclick(‘’myobj‘, function() {...})
by defining a specialized version of Event.observe:
var onclick = Event.observe.bind(Event).partial(_, ‘click’);
A Question of Taste
Is this:
var onclick = Event.observe.bind(Event).partial(_, ‘click’);
really better than the following?
function onclick(element, handler) { Event.observe(elenent, ‘click’, handler); }
It’s a matter of taste, with some performance considerations as well.
The function-level version is less efficient. To the inexperienced eye, it’s also harder to read.
On the other hand, the functional version doesn’t include as much plumbing, with its attendent opportunity for error. The second definition of onclick, considered as a general replacement for Event.observer(..., 'click', ...), has two such errors. One shows up as soon as you use it; the second is considerably more subtle.
Whether functional programming is appropriate, for reasons of efficiency or readability, in any particular instance, it’s nice to have it, at least for prototyping, in your arsenal.
Performance Notes
In most languages, including JavaScript, invoking a function is one of the slowest things you can do. The implementations of languages designed for functional programming use a variety of techniques to optimize function calls. JavaScript is not one of those languages.
Functional attempts to reduce the cost of higher-order-programming where doing so doesn’t add to the code complexity or readability too much. Each higher-order function and method is a small number of lines, and each function-returning method attempts to do as much work as possible outside the function that it returns, to optimize the case where the returned function is called more than once (as an argument to a higher-order function such as map, for example).
Still, using Functional is expensive. Invoking a constructed function results in at least twice as many invocations as invoking the underlying function. This isn’t any different from using bind in the Prototype library, say, but, the more of your program you write in a functional style —- and therefore the more method calls you introduce —- the slower it will be. As with any library, be aware that you may have to hand-compile performance-critical sections of your code into an approximation of you would have written without the library anyway. If you think you already know what needs to be optimized (or that your whole program does), or you aren’t comfortable with measuring performance periodically in order to intelligently trade execution time against implementation time, you may want to eschew libraries, especially higher-order ones.
Compatibility
Functional is known to work in Firefox 2.0, Safari 3.0, and MSIE 6.0. I didn’t intentionally use any non-standard ECMAScript constructs, but meta-programming such as this tends to turn up corners in the browser implementations.
I’ve used this with Prototype and jQuery. If you call Functional.install, it will replace Prototype’s bind, but with a compatible version. Functional.install defines a number of other top-level functions (all documented), but to my knowledge these all have unusual names (e.g. curry), or standard semantics (e.g. map), so you’re unlikely to run into any problems unless you try to use this with another library of higher-order functions. In which case, don’t call Functional.install.
Update: The current version also defines equal as a functional, for doing things like this: select(equal(pluck('x'), K(1)), [{x:1,y:2}, {x:3,y:4}]). This is more likely to conflict with a method from your code or another library, so beware!
Defining String.prototype.apply and ...call seems potentially skanky, although the ECMAScript standard permits it and i haven’t run into any trouble. These methods could be removed without breaking anything except a few of the example; internally, the Functional functions use Function.toFunction instead.
The implementation of string lambdas uses regular expressions and eval. The rest of the code doesn’t. The intent of this separation is that the code might be portable to environments that don’t include these features, such as Flash and OpenLaszlo. I haven’t tested it against any of these environments, thoug, so I’ve kept the code in one file for now.
Future Directions
Credits
(Temporarily deleted while I debug why this text borks WordPress.)
Comments
This library rocks!
[...] E outro carinha criou uma biblioteca para escrever javascript funcional (map, reduce, filter), chamada “Functional Javascript” [...]
Thomas, you're right; thanks for the find and the fix. I've fixed it above now.
I wrote the code that splices the output values into the "examples page":http://osteele.com/sources/javascript/functional exactly because I knew I wouldn't successfully keep them up to date with the expressions, but I couldn't (or didn't take the time to) do the same thing on this blog page :-(
Scott: I agree completely about [1,2,3,4].map(‘x*x’) versus map(‘x*x’, [1,2,3,4]): I find the first more readable too. I didn't add these to Functional first because extending Array.prototype breaks associative array iteration. (See these postings by "Erik Arvidsson":http://erik.eae.net/archives/2005/06/06/22.13.54/, "James Mc Parlane":http://blog.metawrap.com/blog/WhyIDontUseThePrototypejsJavaScriptLibrary.aspx, and "davber":http://blog.davber.com/2006/08/24/prototype-arrays-improving-upon-ajax/). And second, because several of the DOM frameworks come with their own collection methods, and I didn't want to duplicate their work.
So, although I prefer [1,2,3,4].map(‘x*x’) myself and I'm willing to give up associative array iteration to get it, I didn't want to compile that tradeoff into this library.
Dean, thanks for the kind words --- I've enjoyed reading your code too. :-) I'll incorporate your improvement into the next version of the library.
Just a quick fix: The example
"map(guard('10+', not('%2')), [1,2,3,4])" in your Function-level programming section should probably produce
"-> [1,12,3,14]", or shouldn't it?!
[...] Jul 27th, 2007 by kiterminal วันนี้บังเà¸à¸´à¸à¹„ปเจภBlog ขà¸à¸‡ Oliver Steele ซึ่งเค้าไปทำ Functional JavaScript ไว้ ลà¸à¸‡à¸¡à¸²à¸”ูตัวà¸à¸¢à¹ˆà¸²à¸‡à¸—ี่เค้าทำให้ดูละà¸à¸±à¸™ map(function(x){return x+1}, [1,2,3]) -> [2,3,4] filter(function(x){return x>2}, [1,2,3,4]] -> [3,4] some(function(w){return w.length < 3}, ‘are there any short words?’.split(’ ‘)) -> false // double the items in a list: map(’*2′, [1,2,3]) -> [2, 4, 6] // find just the odd numbers: filter(’%2′, [1,2,3,4]) -> [1, 3] // or just the evens: filter(not(’%2′), [1,2,3,4]) -> [2, 4] ทั้งนี้เค้ายังได้ทำ API documentation ไว้ให้à¸à¹ˆà¸²à¸™à¹à¸¥à¸°à¸¨à¸¶à¸à¸©à¸²à¸à¸±à¸™à¸”้วย [...]
We had wrote such library for our product, as almost all developers was experienced Scheme developers ;-)
JavaScript code in functional looks very elegant and readable
[...] Functional Javascript 26 07 2007 Currently i am working on Javascript and i am learning a lot.While searching for some code samples in Javascript I came across a new term Functional Javascript.We all know what is “Functions” in javascript.But what is functional javascript???Let’s see. [...]
[...] Functional JavaScript at Oliver Steele (tags: javascript functional) [...]
[...] Oliver Steele has a new library called Functional JavaScript that defines the standard higher-order functions (map, reduce, filter) as well as functions for partial function application and function-level programming: curry, partial, compose, guard, and until. Finally, it introduces “string lambdasâ€, which let you write 'x -> x+1', 'x+1', or even '+1' as synonyms for function(x) {return x+1}. [...]
[...] Functional JavaScript at Oliver Steele In most languages, including JavaScript, invoking a function is one of the slowest things you can do. The implementations of languages designed for functional programming use a variety of techniques to optimize function calls. JavaScript is not one of tho (tags: JavaScript webdesign) digg_url='http://xiled.rss-central.net/blog/2007/07/23/links-for-2007-07-24/'; digg_skin = 'compact'; digg_bgcolor = '#FFFFFF'; digg_title = 'links for 2007-07-24'; digg_bodytext = ''; digg_topic = ''; Powered by Gregarious (41) Share This [...]
[...] Functional JavaScript attempts to reduce the cost of higher-order-programming where doing so doesn’t add to the code complexity or readability too much. The implementations of languages designed for functional programming use a variety of techniques to optimize function calls. JavaScript is not one of those languages. [...]
[...] Functional JavaScript at Oliver Steele “In most languages, including JavaScript, invoking a function is one of the slowest things you can do. The implementations of languages designed for functional programming use a variety of techniques to optimize function calls. JavaScript is not one of th (tags: functional fp declarative map reduce filter mapreduce javascript viapopular) [...]
[...] Functional JavaScript at Oliver Steele (tags: ** article development filter functions functional programming javascript library webdev haskell guide) [...]
[...] Functional JavaScript (tags: programming javascript) [...]
[...] Functional JavaScript at Oliver Steele Functional is a JavaScript library for functional programming, a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. (tags: article filter javascript library programming tutorial tips functional development webdev webdesign) [...]
I'm having great fun pouring over your library. It is very well written and I'm learning a lot about functional programming from reading the source.
Regarding speed, you can improve performance by giving up your favourite idiom:
var args = [].slice.call(arguments, 0);
This is expensive because it creates a new Array object every time you slice an arguments object. Which is very often.
Mozilla provides a static slice method on the Array object. Or you can fake it yourself:
if (!Array.slice) { // Mozilla already supports this
Array.slice = function(array) {
// Slice an array-like object.
var slice = Array.prototype.slice;
return slice.apply(array, slice.call(arguments, 1));
};
}
And use it like this:
var args0 = Array.slice(arguments); // cast to Array
var args1 = Array.slice(arguments, 1); // a normal slice
I use it so often I make it global.
var slice = Array.slice;
var args = slice(arguments);
Hope that helps. Back to reading your source code for me. :)
[...] Did you ever use Haskell?Haskell is a functional programming language (you’ll soon see what it means), and now, there’s a library for Functional JavaScript.And that’s what you can do with it: instead of…var numbers = [2, 93, 8894, 491, 7]; var sum = 0; for( var i = 0; i < numbers.length; i++ ) { sum += numbers[i] * 20; alert(sum); You would just say:alert( reduce( 'x+y', 0, map('*20', [2,93,8894,491,7]) ) );Okay, while this is just some loosy nonsense example, the possibilities opened up by the library are huge. Still, the greatest benefits from Functional JavaScript are higher order functions: now, even Currying or partial function application are possible!Look here:// Create functions on the fly! var divide = 'x/y'.lambda(); // Apply only one parameter and create a new function. var halve = divide.partial(_,2); alert( halve(6) ); // "3"! So… This is really, really hot so far. What’s missing are good functions for working with lists (or even List comprehension). Also, I’d doubt that this has good performance. However, especially in web desing, while working with DOM or those things, I’m sure Functional JavaScript will find it’s place.Give it a try, it’s hot! (And use the "live demo feature" on the site linked above! ) [...]
I think it would be more readable if the map/filter/reduce functions worked on the enumerable objects themselves instead of having to be passed in.
Instead of this:
map('x*x', [1,2,3,4])
Why not this:
[1,2,3,4].map('x*x')