JavaScript: fun with lists

December 05, 2005

...

JavaScript, as many other popular programming languages, uses a lot of sugar to sweeten the syntax. This causes the code to be quite verbose. Much more verbose than they have to be. To help this, we can look to functional programming languages, such as ML and Scheme, and apply some of their principles. Specifically, we can perform the operation known as currying to make the code less verbose.

Consider the following JavaScript code:

var myfield = <.some HTML field…>;  
var value = new Array();
for (var i = 0; i < myfield.options.length; i++) {  
  if (field.options[i].selected) {  
    value[value.length] = field.options[i].value;  
  }  
}

function isSelected(option) { return (option.selected) ? option.value : null; }  
var value = map(isSelected, myfield.options);

So, what is this mysterious map function? Well, consider the following ML code:

map (fn x => x+1) [1,2,3,4];

which will return the list [2,3,4,5]. The map function in ML is used to apply a function to every element of a list, and collect a list of results, given that the function is an unary function (that is, takes only one argument). Luckily for us, in JavaScript, functions are first-class objects, and may be passed as a parameter to another function. Here is the map function declaration in JavaScript:

function map(lambda, values) {  
  switch (values.length) {  
    case 0: return values;  
    case 1: return [lambda(values.shift())];  
    default: return [lambda(values.shift())]
      .concat(map(lambda, values));  
  }  
}

Basically, this is a recursive function that we use instead of the iteration in the original code snippet. We declare an unary function that performs the wanted operation on a single value, and apply this function on every element in a list. I named the parameter lambda with reference to the Scheme language where lambda denotes an anonymous function. This in turn, refers to lambda calculus which is the foundation of functional languages.

Hence, the previous example in ML would look like this in JavaScript:

map(function(x){return x+1;}, [1,2,3,4]);

Another case where a similar approach becomes handy, is where the result of one function application is the input for the next. If we define the following function:

function foldr( lambda, start, values ) {  
  if (1 == values.length) {  
    return lambda(values.shift(), start);  
  }  
  return lambda( values.shift(), foldr( lambda, start, values ));  
}

We can use it to add all values in array:

foldr( function(a, b) { return a+b; }, 0, [1,2,3,4]);

which will return the value 10 by caculating 1 + (2 + (3 + (4 + 0) ) ).

Might be useful if you want to write more compact code.


Profile picture

Written by Vidar Kongsli who is a software professional living in Oslo, Norway. Works as a consultant, system architect and developer at Bredvid. You should follow him on Twitter