?

Log in

No account? Create an account
entries friends calendar profile Elf Sternberg's Pendorwright Projects Previous Previous Next Next
Underscore Rail Command (Compose with Predicates) - Elf M. Sternberg
elfs
elfs
Underscore Rail Command (Compose with Predicates)

This is my very simple secret weapon in doing complicated data transforms on the client side, which I do a lot of when I’m working with Splunk data.


<rail.js>=
_ = require('underscore');

_.mixin({
    makerail: function(predicate) {
        if (_.isUndefined(predicate)) {
            predicate = _.isUndefined;
        }
        return function() {
            var args = arguments;
            return function() {
                var result = args[0].apply(this, arguments);
                if (predicate(result)) {
                    return result;
                }
                for(var i = 1, l = args.length; i < l; i++) {
                    result = args[i].call(this, result);
                    if (predicate(result)) {
                        return result;
                    }
                }
                return result;
            };
        };
    }
});

_.mixin({rail: _.makerail()});

In its default configuration, rail() calls each argument in the sequence, much like compose(), passing to the first function in any arguments to the resultant composed function call, then passing the result of that function to each subsequent function. It’s basically like the arrow operator in Lisp, performing each step in a left-to-right fashion, rather than the right-to-left of underscore’s compose function. However, it also *terminates* the moment any function produces undefined as a result, shorting out the composition and returning undefined right then.


It’s possible to call makerail with an alternative predicate:


<alternative_predicate_example>=

var railway = _.makerail(function(result) {
    return (result instanceof Error);
});


In this example, makerail() is describing what F#calls “railway oriented programming”, whereby when any function returns an object of the exception class, all the other functions are immediately skipped without generating an exception and all of the performance or flow-control headaches of invoking the exception handler.  It’s actually rather nifty, and encourages a much more holistic approach to dealing with long data flows.

Leave a comment