A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://javascriptweblog.wordpress.com/2010/04/14/compose-functions-as-building-blocks/ below:

functions as building blocks – JavaScript, JavaScript…

As regular readers have probably noticed, a recurring theme of these posts is function manipulation as an expressive device. JavaScript treats functions as first class objects, that is they can be created and modified dynamically and passed as data to other functions and objects. Shamelessly continuing this theme, allow me to introduce functional composition…

Here’s a couple of simple examples to start:-

var  alertPower = alert.compose(Math.pow);
alertPower(9,8); //alert shows 43046721
var  roundedSqRoot = Math.round.compose(Math.sqrt);
roundedSqRoot(28); //5

The compose function allows us to define a new function based on two existing (or anonymous) functions. In generic form:

myFunction = function1.compose(function2);

and when we call…

myFunction(myArgs);

…function 2 gets invoked with myArgs and the result is passed to the invocation of function 1. Like curry, compose is not a native JavaScript function but its easy to augment the Function prototype to support it.

Function.prototype.compose  = function(argFunction) {
    var invokingFunction = this;
    return function() {
        return  invokingFunction.call(this,argFunction.apply(this,arguments));
    }
}

Now a meatier example – this creates a rudimentary parseAlpha function (it also makes use of the curry function described in an earlier post) :-

//use curry  to make a slice(0,x) function, then use compose to wrap it around  search.
var sliceToRegEx =  String.prototype.slice.curry(0).compose(String.prototype.search);

//now curry with a regEx that returns first non alpha character
var parseAlpha = sliceToRegEx.curry(/[^ a-zA-Z]/);
parseAlpha.call("Pork Bellies #45678"); //Pork Bellies

Compose and curry often work well together – forging new functions from old, in a concise and readable way. Here’s another example:-

var  queryString =  String.prototype.substring.compose(String.prototype.indexOf).curry('?');
queryString.call("http://www.wunderground.com?query=94101&weekday=Tuesday");  //?query=94101&weekday=Tuesday

Going deeper, the following function loops through an Enumerable looking for the longest sequence for which the given function holds true (notice I’m ignoring blank string members) :-

var longestSequence = function(compareFunc,myEnum) {
    var result = {member:null, count:0};
    var thisCount = 1;
    for (var i=1; i<myEnum.length; ++i) {
        if ((myEnum[i]!==" ") && compareFunc(myEnum[i-1], myEnum[i])) {
            if (++thisCount >= result.count) {
                result = {member: myEnum[i], count: thisCount};
            }
        } else {
            thisCount = 1;
        }
    }
    return result.member + " (" + result.count + ")";
}

So for example, to look for the longest successive run of equal members

longestSequence(function(a,b){return  a==b},'skiing'); //i (2)

We can use curry to create a reuseable function to get the longest run of the same member.

var  longestEqualRun = longestSequence.curry(function(a,b){return a==b});
longestEqualRun([1,1,2,2,2,2,3,3]); //2 (4)

Now here comes compose…and voilà…we have a function to return the most frequent member:-

var  mostFrequent = longestEqualRun.compose(function(myEnum){return myEnum.split('').sort()});
mostFrequent("The quick brown fox jumps over the lazy dog"); //o  (4)

How about a function to return the most frequent character in the current page source? No problem – just compose once more:-

function getInnerText(elem) {
    return elem.innerText || elem.textContent;    
}

var  mostFrequentInPage = mostFrequent.compose(function() {return getInnerText(document.body)});
mostFrequentInPage(); //e (263)

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4