27 November 2013

_part_, a meta-utility, proposes a pattern for creating utility functions from native methods using a more functional programming style. However, rather than settle the “argument” of function-first versus receiver-first, _part_ offers a simple, yet intuitive, way to use both styles.

Patterns

In object-oriented (O.O.) style programming, we see the “dot” between objects and their methods: <subject>.<verb>. The subject-verb (or receiver-method) pattern works well when you know the receiver, it has said method, and it does not change.

But in other situations, you may prefer a functional, or point-free, style: <verb>(<subject>). Most commonly, developers in loosely-typed languages, like JavaScript, use this pattern while mapping over several objects.

Arguments over arguments

While functional programmers agree on the power and utility of their programming style over traditional OO, there exists a fundamental argument over how to pass parameters to these functions. In the OO world, we simply add arguments to the end of the code sentence, <subject>.<verb>(<predicate>). In the functional world, which do you prefer, receiver-first <verb>(<subject>, <predicate>) or predicate-first <verb>(<predicate>, <subject>)? Does your preference change?

In many situations, like the mapping situation mentioned above, the method takes a function argument. When that argument precedes the receiver, you used the “function-first” approach. Because other methods, like reduce, may have additional parameters, many functional programmers use the object-first approach. This way, they do not need to decide where additional parameters go: before or after the predicate function.

Why not both?

both

In _part_, you use typical OO functions (like the ones in native prototypes) to create two functional counterparts, “left-part” and “right-part”, which partially apply the receiver or parameters respectively.

The OO map example:

var arr = [1,2,3];

function addOne( n ) {
  return n + 1;
}

arr.map( addOne ); // [2,3,4]

The “left-part” version:

_map( arr )( addOne ); //[2,3,4]

The “right-part” version:

map_( addOne )( arr ); //[2,3,4]

Include additional arguments, such as when using reduce on either side:

var arr = [1,2,3];

function sum( a, b ) {
  return a + b;
}

//standard pattern
arr.reduce( sum );    // 6
arr.reduce( sum, 4 ); // 10

//make _reduce and reduce_ global
_part_._augment( this )( Array.prototype.reduce, "reduce" );

//left-part pattern
_reduce( arr )( sum );     // 6
_reduce( arr, 4 )( sum );  // 10
_reduce( arr )( sum, 4 );  // 10

//right-part pattern
reduce_( sum )( arr );    // 6
reduce_( sum )( arr, 4 ); // 10
reduce_( sum, 4 )( arr ); // 10


Discussion:

blog comments powered by Disqus