Extending, Currying and Monkey Patching. part 2

Currying

Currying got it’s name from Haskell Curry,

Haskell Curry

originally discovered by Moses Schönfinkel.

schonfinkel

The programming language Haskell named after Haskell Curry is a purely functional language.
So the concept of Currying has it’s roots in functional programming.

It seems that the concepts of Currying and Partial Function Application are often used interchangeably, although they are different.
Lets try and shed some light on the confusion.

Function Application

In carrying on from part 1 of this topic “Extending, Currying and Monkey Patching”
When it comes to functional programming languages, strictly speaking we don’t so much use the terms calling or invoking a function.
We apply functions.
As you can see in the next example, calling or applying a function has the same effect.
Lines 36, 40 and 45 all do the same thing.

// In JavaScript
var coffeeAttributes;
var BINARYMIST;

BINARYMIST = (function (binMist) {
   return binMist;
} (BINARYMIST || {}));

BINARYMIST = (function (binMist) {

  var capitaliseFirstChar = function (target) {
    return target.replace(/^\w/, function (character) { return character.toUpperCase(); });
  };

   binMist.coffeeAttributes = function (myPoison) {
      try {
        // If String.prototype.toLowerCase fails, myPoison isn't a string
        var poison = (myPoison || "").toLowerCase();
      } catch (e) {
        return "Looks like the argument you passed wasn't a string.";
      }

      if(poison === "real coffee")
        return capitaliseFirstChar(poison) + " provides great taste and a good buzz.";
      if(poison === "instant coffee")
        return capitaliseFirstChar(poison) + " provides terrible taste and minimal buzz.";
      if(poison)
        return "I don't recognise " + poison + ". It's attrbutes could be anyones guess.";

      return "well it depends on what type of coffee we're talking about.";
  };
  return binMist;
}(BINARYMIST || {}));

// Call or invoke your function.
coffeeAttributes = BINARYMIST.coffeeAttributes( new String("Real coffee"));
document.writeln(coffeeAttributes + '<br>');
// Real coffee provides great taste and a good buzz.

coffeeAttributes = BINARYMIST.coffeeAttributes('instant Coffee');
document.writeln(coffeeAttributes + '<br>');
// Instant coffee provides terrible taste and minimal buzz.

// Apply your function.
coffeeAttributes = BINARYMIST.coffeeAttributes.apply(null, ["pseudo coffee"]);
document.writeln(coffeeAttributes + '<br>');
// I don't recognise pseudo coffee. It's attrbutes could be anyones guess.

In essence, how we code  a function call / invocation is syntactic sugar for the slightly longer form “function application”.

Partial Application

Or partial function application…

  • returns a function which behaves like the function you pass in but which takes fewer arguments, because the others have been bound into the returned function.
  • takes a function and from it builds a function which takes fewer arguments.

Implementing Partial Application

Now we could continue with the same theme as above, but for the purpose of providing easy understanding, I’m going to use a simpler theme.
I’ve seen the add function used a few times to explain the topic, so I’m going to use it as well.
We’re going to look at the examples in both JavaScript and C#.
Don’t get to caught up on the C# examples, as I’ve never had a need to curry in C#.
They’re just there to provide some contrast.

// In JavaScript
var BINARYMIST;
var fullApplicationResult;
var add9;
var partialApplicationResult;

BINARYMIST = (function (binMist) {
   return binMist;
} (BINARYMIST || {}));

BINARYMIST = (function (binMist) {
  binMist.add = function (firstParam, secondParam) {
    var firstLocal = (typeof firstParam === 'number') ? firstParam : 0;
    var secondLocal = (typeof secondParam === 'number') ? secondParam : 0;
    return firstLocal + secondLocal;
  }
  return binMist;
}(BINARYMIST || {}));

BINARYMIST.partialApply = (function () {
  return function (localFunction, param2) {
    return function (param3) {
      return localFunction(param2, param3);
    }
  }
}());

fullApplicationResult = BINARYMIST.add.apply(null, [9, 6]);
document.writeln('Full Function Application results: ' + fullApplicationResult + '<br>');
// Full Function Application results: 15

add9 = BINARYMIST.partialApply.apply(null, [BINARYMIST.add, 9]);
partialApplicationResult = add9(6);
document.writeln('Partial Function Application results: ' + partialApplicationResult + '<br>');
// Partial Function Application results: 15
// In C#
using System;

namespace BinaryMist {
    class Program {

        static string Add(int firstParam, int secondParam) {
            return (firstParam + secondParam).ToString();
        }

        static Func<T2, TResult> PartialApply<T1, T2, TResult>(Func<T1, T2, TResult> localFunction, T1 param2) {
            return (param3) => localFunction(param2, param3);
        }

        static void Main(string[] args) {
            Func<int, int, string> kimsAdd = Add;

            Func<int, string> add9 = PartialApply(kimsAdd, 9);
            string partialApplicationResult = add9(6);
            Console.WriteLine("Partial Function Application results: {0}", partialApplicationResult);
            // Partial Function Application results: 15
        }
    }
}

Now with an add method that takes 3 arguments:

// In JavaScript
var BINARYMIST;
var add9;
var partialApplicationResult;

BINARYMIST = (function (binMist) {
   return binMist;
} (BINARYMIST || {}));

BINARYMIST = (function (binMist) {
  binMist.add = function (firstParam, secondParam, thirdParam) {
    var firstLocal = (typeof firstParam === 'number') ? firstParam : 0;
    var secondLocal = (typeof secondParam === 'number') ? secondParam : 0;
    var thirdLocal = (typeof thirdParam === 'number') ? thirdParam : 0;
    return firstLocal + secondLocal + thirdLocal;
  }
  return binMist;
}(BINARYMIST || {}));

BINARYMIST.partialApply = (function () {
  return function (localFunction, param2) {
    return function (param3, param4) {
      return localFunction(param2, param3, param4);
    }
  }
}());

add9 = BINARYMIST.partialApply.apply(null, [BINARYMIST.add, 9]);
partialApplicationResult = add9(6, 2);
document.writeln('Partial Function Application results: ' + partialApplicationResult + '<br>');
// Partial Function Application results: 17
// In C#
using System;

namespace BinaryMist {
    class Program {

        static string Add(int firstParam, int secondParam, int thirdParam) {
            return (firstParam + secondParam + thirdParam).ToString();
        }

        static Func<T2, T3, TResult> PartialApply<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> localFunction, T1 param2) {
            return (param3, param4) => localFunction(param2, param3, param4);
        }

        static void Main(string[] args) {
            Func<int, int, int, string> kimsAdd = Add;

            Func<int, int, string> add9 = PartialApply(kimsAdd, 9);
            string partialApplicationResult = add9(6, 2);
            Console.WriteLine("Partial Function Application results: {0}", partialApplicationResult);
            // Partial Function Application results: 17
        }
    }
}

and again, but broken out into stages:

// In JavaScript
var BINARYMIST;
var add9;
var add6;
var add2;
var partialApplicationResult;

BINARYMIST = (function (binMist) {
   return binMist;
} (BINARYMIST || {}));

BINARYMIST = (function (binMist) {
  binMist.add = function (firstParam, secondParam, thirdParam) {
    var firstLocal = (typeof firstParam === 'number') ? firstParam : 0;
    var secondLocal = (typeof secondParam === 'number') ? secondParam : 0;
    var thirdLocal = (typeof thirdParam === 'number') ? thirdParam : 0;
    // Time to un-wind the call stack
    return firstLocal + secondLocal + thirdLocal;
  }
  return binMist;
}(BINARYMIST || {}));

BINARYMIST.partialApply = (function () {
  // Because of JavaScript's dynamic typing, we don't need to overload our methods.
  return function (localFunction, param2) {
    return function (param3, param4) {
      return localFunction(param2, param3, param4);
    }
  }
}());

add9 = BINARYMIST.partialApply.apply(null, [BINARYMIST.add, 9]);
add6 = BINARYMIST.partialApply.apply(null, [add9, 6]);
add2 = BINARYMIST.partialApply.apply(null, [add6, 2]);
// Time to wind the call stack up.
partialApplicationResult = add2();
document.writeln('Partial Function Application results: ' + partialApplicationResult + '<br>');

 

// In C#
using System;

namespace BinaryMist {
    class Program {

        static string Add(int firstParam, int secondParam, int thirdParam) {
            // Time to un-wind the call stack.
            return (firstParam + secondParam + thirdParam).ToString();
        }

        // Because of C#'s static typing, we need 3 overloaded methods.
        static Func<T2, T3, TResult> PartialApply<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> localFunction, T1 param2) {
            return (param3, param4) => localFunction(param2, param3, param4);
        }

        // Because of C#'s static typing, we need 3 overloaded methods.
        static Func<T2, TResult> PartialApply<T1, T2, TResult>(Func<T1, T2, TResult> localFunction, T1 param2) {
            return param3 => localFunction(param2, param3);
        }

        // Because of C#'s static typing, we need 3 overloaded methods.
        static Func<TResult> PartialApply<T1, TResult>(Func<T1, TResult> localFunction, T1 param2) {
            return () => localFunction(param2);
        }

        static void Main(string[] args) {
            Func<int, int, int, string> kimsAdd = Add;

            Func<int, int, string> add9 = PartialApply(kimsAdd, 9);
            Func<int, string> add6 = PartialApply(add9, 6);
            Func<string> add2 = PartialApply(add6, 2);
            // Time to wind the call stack up.
            string partialApplicationResult = add2();
            Console.WriteLine("Partial Function Application results: {0}", partialApplicationResult);
            // Partial Function Application results: 17
        }
    }
}

Currying

  • is creating a function that understands partial application and implements it.
  • builds functions which take multiple arguments by composition of functions which each take a single argument.

Implementing Currying

Now the function that takes the single argument is on line 48.
The composition of functions is performed in the same function where we return that (which is the original add applied to the parameter of 9 for the first test).
So in this function we actually return add applied to 9 concatenated to 6.
The original 9 is held in argumentsArray.
I’ve also modified the add method to be a little more flexible and deal with n number of arguments.

// In JavaScript
// Setup our global
var BINARYMIST;

// Variables for testing
var add9;
var sixteen;
var addOne;
var fortyOne;
var addSix;

// First up we add a method to Function's prototype.
// In JavaScript every object (incl Function) is linked to a prototype object
// This allows us to add any function to Function's prototype
Function.prototype.method = (function (name, func) {
  // Add the function (func) as a property of Function's prototype object.
  this.prototype[name] = func;
  return this;
});

// This is our add method repeated from above.
BINARYMIST = (function (binMist) {
  binMist.add = function () {
    var addend;
    var sum = 0;
    for (arg in arguments) {
      if (arguments.hasOwnProperty(arg)) {
        addend = arguments[arg];
        sum += (typeof addend === 'number') ? addend : 0
      }
    }
    return sum;
  }
  return binMist;
}(BINARYMIST || {}));

// Second we add a function called curry to the global Functions prototype.
Function.method('curry', function ( ) {
  // Because we want to concatenate 2 lots of the arguments, we need arguments to be of type Array.
  // Because the arguments parameter is not a real array, we need to borrow the slice method from Array.prototype.
  var slice = Array.prototype.slice;
  // Create an array from arguments.
  var argumentsArray = slice.apply(arguments);
  // In our case, this is bound to add because it's add's prototype's curry method that we invoked.
  var that = this;
  return function ( ) {
    // We now apply add (which is referenced by that) to the current scope, which is the curried function (add9, in this case).
    return that.apply(null, argumentsArray.concat(slice.apply(arguments)/*Create a real array from arguments.*/)/*Concatenate it with the curry parameter*/);
  };
});

Testing curry

// In JavaScript

// Execute the curry method which is a member of add's prototype.
add9 = BINARYMIST.add.curry(9);
document.writeln("Curry results: " + add9(6) + '<br>'); // Curry results: 15

// Single-step currying. Works with any number of arguments.
addSixteen = BINARYMIST.add.curry(1, 2, 3)(5, 5);
document.writeln("Curry results: " + addSixteen + '<br>'); // Curry  results: 16

// Two-step currying.
addOne = BINARYMIST.add.curry(1);
addSix = BINARYMIST.add.curry(3, 1, 2);
fortyOne = addOne(10, 10, 10, 10);
six = addOne(2, 3);
sixteen = addSix(5, 5);

As you can see from the C# example below, dynamic languages such as JavaScript, make currying less verbose and provide considerably more flexibility.

Currying in C# feels a little awkward.

// In C#
using System;

namespace BinaryMist {
    class Program {

        static int Add(int firstParam, int secondParam, int thirdParam) {
            // Time to un-wind the call stack.
            return firstParam + secondParam + thirdParam;
        }

        static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function) {
            return a => b => c => function(a, b, c);
        }

        // Testing curry
        static void Main(string[] args) {
            Func<int, int, int, int> kimsAdd = Add;

            string curryResult = "Curry results: {0}";

            // Single-step currying.
            var curried = Curry(kimsAdd);
            Console.WriteLine(curryResult, curried(9)(6)(3));
            // Curry results: 18

            // Two-step currying.
            Func<int, Func<int, Func<int, int>>> curryAdd = Curry(kimsAdd);
            Func<int, Func<int, int>> add9 = curryAdd(9);
            Func<int, int> add15 = add9(6);
            Console.WriteLine(curryResult, add15(3));
            // Curry results: 18
        }
    }
}

Why / where would we want to Curry

If you are making calls to a particular function with some of the same arguments every time.
You could dynamically create a function that holds on to the previously repeated parameters, thus saving you the effort of passing them every time.
This function will supply the original function with it’s saved parameters, so the original function has the full set.
Currying is not really needed in C#. The examples provided are for academic purposes only.

To wrap up:

Although I don’t think there is much use for explicit Partial Application or Currying in C#,
Jon Skeet has an interesting blog post on Partial Application and Currying in C#, with:

  1. some sample code useful for stepping through
  2. a good controversial and thought provoking conversation following

This post also provided some clarification.

Other Insights obtained from the excellent:

  1. Doug Crockfords JavaScript The Good Parts
  2. Stoyan Stefanov’s JavaScript Patterns

Tags: , , ,

One Response to “Extending, Currying and Monkey Patching. part 2”

  1. JavaScript Object Creation Patterns | Binarymist Says:

    […] https://blog.binarymist.net/2012/05/14/extending-currying-and-monkey-patching-part-2/ […]

Leave a comment