Function Currying in Javascript & AS3

Function currying is a concept and programmatic technique usually relegated to senior developers. The concept seems so esoteric and difficult to grasp… but that could not be farther from the truth. In fact, you are probably already using closures in your code… and that means you are only a short step away from using Function Currying.

According to John Resig “Partially applying a function is a, particularly, interesting technique in which you can pre-fill-in arguments to a function before it is ever executed. Capturing or pre-filling in 1 or more arguments of a function (and returning a new function) is typically called partial application. And Function currying is the partial application of arguments one at-a-time, in left-to-right order…”

Function Currying (in Javascript)

Consider the scenario where I want to use an AngularJS custom dataservice BlogService to load a list of blog posts. Specifically, I want to display in an HTML5 list all available post titles.

Below is a sample snapshot of the data expected from the remote Blog server.

{
    "author": "hughfdjackson",
    "url" : "http://hughfdjackson.com/javascript/2013/07/06/why-curry-helps/"
    "posts": [
        { "title": "why curry?", "contents": "..." },
        { "title": "prototypes: the shortest possible story", "contents": "..." }
    ]
}

Not only do I need to load the remote JSON data, but I need to iterate and extract the titles from each post entry.

Version #1 – Traditional Solution (Javascript)
var BlogListController = function( blogService, $scope, $q )
  {
      /**
       * Use the promise-returning `blogService` to load a list
       * of all post `title`(s)
       */ 
    var loadAllPosts = function()
        {
          blogService
            .loadAllPosts()
            .then( function( response ){
              return JSON.parse(response);
            })
            .then( function( data ){
              return data.posts;
            })
            .then( function( posts ) {
              return posts.map( function(post){
                return post.title;
              });
            }).
            .then( function( titles ) {
              $scope.$apply(function() {
                  $scope.allPosts = titles;
              });            
            }).
        };
      
    $scope.allPosts= [ ];
    $scope.refresh = loadAllPosts;
    
    loadAllPosts();
  };

Nothing is shocking or surprising here… we simply chained our response handlers to iteratively extract the title list desired. If we applied, however, a Function Curry technique to our code, the code becomes surprisingly and significantly more terse, elegant, and graceful.

Version #2 – Function Curry Solution (Javascript)
var BlogListController = function( blogService, $scope, $q )
    {
      var map     = curry( function( fn, list )    { ... },
          apply   = curry( function( fn, list )    { ... },
          extract = curry( function( key, source ) { ... };

          /**
           * Use the promise-returning `blogService` to load a list
           * of all post `title`(s)
           *
           * Note: loadAllPosts() returns a Promise, so let's use
           *       Function Currying to make our handler implementations
           *       very functional.
           */ 
          loadAllPosts = function()
          {
            blogService
              .loadAllPosts()
              .then( JSON.parse )
              .then( extract("posts") )
              .then( apply(map( extract("title") )) );
          };

      $scope.allPosts= [ ];
      $scope.refresh = loadAllPosts;

      loadAllPosts();
    };

First let me discuss the curry() function; source code is accessible at the GitHub or NPM registry.

To summarize what is happening here, you should realize that the curry( fn(arg1, arg2) ) method creates a function that will pre-fill or capture the first argument and return another Function. When .then( proxyFn ) is invoked, the currying gathers the pre-filled argument and the response argument and calls the original function with BOTH arguments.

Here is the full expansion of the Controller code:

var BlogListController = function( blogService, $scope, $q )
    {
        /**
         * Iterate all items in a list and
         * apply a `curried` function to return a new list.
         */
      var map = curry( function(fn, list)
          {
            return list.map(fn);
          }),
          /**
           * Curry a promise responseHandler to a method
           * that automatically uses $apply() to update the DOM
           * when the allPosts data changes.
           */
          apply = curry( function( fn, list ) 
          {
              list = fn.apply(null, list);

              // Update the $scope model to update DOM table
              $scope.$apply( function() 
              {
                $scope.allPosts = list;
              });

              return list;
          }),
          /**
           * For any object extract its property value based
           * on `curried` property key.
           */
          extract = curry( function( key, source) 
          {
            return source.hasOwnProperty(key) ? source[key] : null;
          });
          /**
           * Use the promise-returning `blogService` to load a list
           * of all post `title`(s)
           *
           * Note: loadAllPosts() returns a Promise, so let's use
           *       Function Currying to make our handler implementations
           *       very functional.
           */ 
          loadAllPosts = function()
          {
            blogService
              .loadAllPosts()
              .then( JSON.parse )
              .then( extract("posts") )
              .then( apply(map( extract("title") )) );
          };

      $scope.allPosts= [ ];
      $scope.refresh = loadAllPosts;

      loadAllPosts();
    };

The invocation of extract("posts") captures the “posts” value as the first argument and returns ANOTHER `proxy` function in preparation to capture the second argument source. Hopefully the code .then( extract("posts") ) should be more understandable now.

I highly recommend, however, that you study apply(map( extract("title") )) to see how I nested Curried functions to create a functional flow. Best of all, this functional flow supports AngularJS and its data-binding processes.

The above code samples are derivations of ideas presented by Hugh Jackson in his July blog “Why Curry Helps“.

The striking changes here are the radical change in Promise response handlers. We used a realistic, functional programming approach that was easily achieved with Function Currying. The resulting code is amazingly clean and terse. The only requirements was a mental shift to use [as the then() parameter] Curried Function references instead of Anonymous Function definitions.

If you want to evolve your coding to a Functional Programming-style then Function Currying can be your best friend.

The issue with Function Currying, however, is that the capture of the arguments is critical and must be left-to-right. If we want to capture the arguments in random order or even introduce extra arguments, we must instead use the Partial Application technique.


Function Currying (in ActionScript3)

Let’s start with an Actionscript3 sample.

The scenario here is that we want to filter array elements based on searchCriteria. Each element in the array is a Car object. I want to check the filter searchCriteria against multiple properties of each Car instance… and the comparisons should be case-insensitive. The filter function will return TRUE if the element should be included in the final filtered dataset.

Let’s start with a traditional approach that does not use currying or partial application techniques.

Version #1: Blunt-force
/**
 * Filter the specified items by search criteria
 *
 * @param allCars Array of known cars
 * @param searchTerm String used as filter critera
 *
 * @return ListCollectionView filtered list of cars matching the filter critera
 */
public function filterByCriteria( allCars:Array, searchTerm:String ) : ListCollectionView
{
  searchTerm ||= "";  // default value is ""

    var collection  : ListCollectionView =  new ArrayCollection( allCars );
    var carFilter   : Function = function (car:CarVO ) : Boolean 
        {
          /**
           * Filter function used for filtered allCars collection
           */
     
            if ( car.hidden )                               return false;
            if ( !searchTerm || searchTerm == "")           return true;

            if ( car.title.toLowerCase().indexOf( searchTerm.toLowerCase() ) > -1) return true;
            if ( car.description.toLowerCase().indexOf( searchTerm.toLowerCase() ) > -1) return true;
            if ( car.owner.name.toLowerCase().indexOf( searchTerm.toLowerCase() ) > -1) return true;
     
            return false;
        };

    // Refresh (to invoke filter processing) and publish

    collection.filterFunction = carFilter;
    collection.refresh();
 
    return collection;
}

In the above code I used String::toLowerCase() 6x… for each item in the collection. Ouch!

Obviously this code works, but it is not terse nor is it DRY.

Version #2 – Closures

Now, let’s refactor the above solution to centralize our comparison operation.

If we refactor Version #1, we can create an named closure assertFound() to perform the string matching.

 


public function filterByCriteria( allCars:Array, searchTerm:String ) : ListCollectionView
{
      function assertFound( searchTerm:String, value:String ) : Boolean 
      {
        return value.toLowerCase().indexOf( searchTerm ) > -1;
      }

    searchTerm ||= "";  // default value is ""
    searchTerm   = searchTerm.toLowerCase();

    var collection  : ListCollectionView =  new ArrayCollection( allCars );
    var carFilter   : Function = function (car:CarVO ) : Boolean 
        {
            if ( car.hidden )                               return false;
            if ( !searchTerm || searchTerm == "")           return true;

            if ( assertFound( searchTerm, car.title) )         return true;
            if ( assertFound( searchTerm, car.owner.name) )    return true;
            if ( assertFound( searchTerm, car.description)  ) return true;
     
            return false;
        };
     
 
    collection.filterFunction = carFilter;
    collection.refresh();

    return collection;
}

This is better; but not DRY enough. The duplicate code at issue here is that searchTerm is used as an argument for each call to assertFound.

Version #3 – Function Currying

We can also improve upon the code/technique used in Version #2.

With function currying we can capture the searchTerm value (the 1st argument) so it can never be changed while the filterFunction is running. It also allows us think of a function curry as a ‘factory’ technique which when called will also generate or return another function. Analogous to the way classes manage state and attach behaviors, function currying manage behaviors and attach state.

Here the Functional.curry factory captured the searchTerm value as a state value and generated a runtime Function that will internally use that captured value.
 


/**
 * Search and filter list of cars based on searchTerm criteria
 */
public function filterByCriteria( allCars:Array, searchTerm:String ) : ListCollectionView
{
        function hasSearchTerm( searchTerm:String, targetToSearch:String ) : Boolean 
        {
          return targetToSearch.toLowerCase().indexOf( searchTerm ) > -1;
        }

      searchTerm = searchTerm ? searchTerm.toLowerCase() : "";

          /**
           * Use the static method `curry` to build a special `curried` function 
           * of the `hasSearchTerm` function; where the `searchTerm` argument is pre-captured. 
           * @see https://gist.github.com/ThomasBurleson/6999692
           */
      var foundIn     : Function = Functional.curry( hasSearchTerm, searchTerm );

      var collection  : ListCollectionView =  new ArrayCollection( allCars );
      var carFilter   : Function = function (car:CarVO ) : Boolean 
          {
              if ( car.hidden )                   return false;
              if ( searchTerm == "")              return true;

              if ( foundIn( car.title ))          return true;
              if ( foundIn( car.owner.name ))     return true;
              if ( foundIn( car.description ))   return true;
       
              return false;
          };
       
      
      collection.filterFunction = carFilter;
      collection.refresh();

      return collection;
}

 

Functional.curry is an AS3 Implementation of the `curry` function to pre-capture target function arguments left-to-right. I must emphasize that only when all the arguments have been captured does the original target function get invoked with the accumulated argument values.

Version #4 – Functional Programming with Function Currying

Finally let’s refactor one (1) more time to combine a more functional approach with Function Currying:


/**
 * Search and filter list of cars based on searchTerm criteria
 */
public function filterByCriteria( allCars:Array, searchTerm:String ) : ListCollectionView
{
        function hasSearchTerm( searchTerm:String, targetToSearch:String, ...rest ) : Boolean 
        {
          return targetToSearch.toLowerCase().indexOf( searchTerm ) > -1;
        }

      searchTerm = searchTerm ? searchTerm.toLowerCase() : "";

          /**
           * Use the static method `curry` to build a special `curried` function 
           * of the `hasSearchTerm` function; where the `searchTerm` argument is pre-captured. 
           * @see https://gist.github.com/ThomasBurleson/6999692
           */
      var foundIn     : Function = Functional.curry( hasSearchTerm, searchTerm );

      var collection  : ListCollectionView =  new ArrayCollection( allCars );
      var carFilter   : Function = function (car:CarVO ) : Boolean 
          {
              if ( car.hidden )                   return false;
              if ( searchTerm == "")              return true;

              return [ car.title, car.owner.name, car.description ].some( foundIn );
          };
       
      
      collection.filterFunction = carFilter;
      collection.refresh();

      return collection;
}

With this solution, I condensed the final comparison code to use [ ].some() and the callback is the curried function. Now that is pretty cool! [ Thanks to my friend Andrew Gscheidle for the suggestion ]


Other Resources

I encourage you to continue Part 2: Partial Applications with Javascript & AS3.

BTW, Douglas Crockford and John Resig both have excellent articles and discussions on the differences of partial applications and function currying. Here is an additional resource for interested developers: Curry Implementations and Performance.

 

Tags: , , ,

Function Currying in Javascript & AS3

2 Responses

  1. Well written Mr. Burleson. Partial applications ARE very useful. For me, they can make the code easier to read – though at times (in AS3 with IJ at least), harder to debug.

    Another oft-overlooked and DRY benefit to partials is the ability to unit test the common functionality with its’ own unit test – depending on scope/context/language. This can reduce the complexity of individual unit tests. I also like that by using the above approach, I can make single changes that effect multiple locations (assuming good composition). Some would argue that is dangerous – sure. I would agree that it shouldn’t be used everywhere – and to be Agile – not until it becomes necessary. However, if one knows they’re building an application with multiple service calls that share common functionality, writing that functionality one time is a plus.

    An additional benefit to the above (“Version #2: Refactored with Partial Applications), when combined with appropriate libs and frameworks, is that these functions that handle repetitive and common tasks can be ‘injected’ or supplied to any class where they’re needed, resulting in very concise implementations of logic and as mentioned, making coding, maintenance, and testing more direct.

    Andrew Gscheidle October 17, 2013 at 9:29 am #
Trackbacks/Pingbacks
  1. Partial Applications with AS3 & Javascript | The Solution OptimistThe Solution Optimist - October 17, 2013

    […] This is essential a continuation of my earlier article “Function Currying in Javascript & AS3” […]

Leave a Reply