Tennent’s Principle of Correspondence

After watching the incredibly insightful Adventures in Functional Programming I was intrigued by the different refactoring tools he used to arrive at the Y Combinator.

The first of which was Tennent’s Principle of Correspondence. In my research I’ve found two different explanations of it. First from Neal Gafter’s Blog: “The principle dictates that an expression or statement, when wrapped in a closure and then immediately invoked, ought to have the same meaning as it did before being wrapped in a closure.”

console.log("Printed!");
 
(function() {
  console.log("Printed!");
}());

Second from Techscursion, “for any parameter mechanism, an analogous definition mechanism is possible, and vice versa.”

var incr = (function() {
  var n = 0; //Definition mechanism
  return function() {
    return n++;
  };
}());
 
var incr = (function(n) { //Parameter mechanism
    return function() {
       return n++;
    };
}(0));

They both seem rather silly in such simple contexts, but they give you a good way to functionally express things in JavaScript. As an exercise, I converted a pretty simple Curry function:

//Imperative
Function.prototype.curry = function() {
  var args = Array.prototype.slice.call(arguments),
      fn = this;
 
  return function() {
    var innerArgs = Array.prototype.slice.call(arguments);
    return fn.apply(this, args.concat(innerArgs));
  }
}
 
//Tennentive
Function.prototype.curry = function() {
  return (function(args, fn) {
    return function() {
      return (function (innerArgs, context) {
        return fn.apply(context, args.concat(innerArgs));
      })(Array.prototype.slice.call(arguments), this);
    }
  })(Array.prototype.slice.call(arguments), this);
}

What About Performance?

Now I was curious, is there a performance difference between the two implementations? Here’s a jsperf to examine the performance currying and of calling the curried function: Imperative vs Functional.

As of writing this, I ran the test 10 times each in Chrome 20, Firefox 10 and IE 9.

Chrome 20:

  • Imperative Currying was about 8% faster than Functional
  • Calling the curried function was nearly identical.
  • Overall the performance was more than double the others

Firefox 10:

  • Functional Currying was actually almost 4% faster
  • Calling the imperatively curried function was 11% faster though.

IE 9:

  • Functional Currying was a whopping 33% faster in IE 9
  • Calling the imperatively curried function was, once again, 11% faster.

This and Return

There’s a few sort of wonky workarounds you have to manage in certain situations. Yehuda Katz covers the issues around this and return in his article JavaScript Needs Blocks. You can see how I had to handle them in my Tennentive version, extra returns and binding this to a parameter.

Function.prototype.curry = function() {
  //Extra return to pass on return of anonymous function
  return (function(args, fn) {
    return function() {
      //Extra return to pass on return of anonymous function
      return (function (innerArgs, context) {
        return fn.apply(context, args.concat(innerArgs));
      })(Array.prototype.slice.call(arguments), this); //Bind this to an argument
    }
  })(Array.prototype.slice.call(arguments), this); //Bind this to an argument
}
Written on July 11, 2012