When delving into functional programming techniques, the initial intimidation often gives way to simplicity when solving problems like this. Utilizing libraries such as Ramda (full disclosure: I am one of the authors; however, these techniques are available in various other functional programming libraries), tasks can be achieved effortlessly:
var countAvailable = R.pipe(R.filter(R.propEq('available', 'true')), R.prop('length'));
var pagesRead = R.pipe(R.pluck('current_page'), R.sum);
var maxTitleLength = R.pipe(R.pluck('title'), R.pluck('length'), R.max);
Each function provided here can be called with the data from bookarrays
. The functionality is demonstrated on the Ramda REPL.
The key takeaway is that common functions like pluck
offer the ability to transform lists into simpler forms for further manipulation. For example,
pluck('title')(bookarrays);
//=> ["Fast Cars", "Slow Cars", "Big Cars", "Small Cars", "Cars"]
This highlights how using functions like pluck
, max
, and pipe
allows for the creation of easily accessible functions like maxTitleLength
. Functional programming emphasizes the development of simple, composable functions that operate on the same data structures, such as lists.
Update
This approach isn't solely about the library itself but rather focuses on creating multiple small, reusable, composable components to construct more intricate functions. Below is a curated selection of functions designed to address these specific issues:
var add = function(a, b) {
return a + b;
};
var sum = function(list) {
return list.reduce(add, 0);
};
var max = function(list) {
return Math.max.apply(Math, list);
};
var map = function(fn) {
return function(list) {
return list.map(fn);
};
};
var prop = function(name) {
return function(obj) {
return obj[name];
};
};
var pipe = function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = 0; i < funcs.length; i++) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
var pluck = pipe(prop, map);
var filter = function(fn) {
return function(list) {
return list.filter(fn);
};
};
var propEq = function(name, val) {
return function(obj) {
return obj[name] === val;
};
}
To utilize this utility library, combine these functions in your code. Notice the straightforward definition of pluck
.
You could also simplify it by writing:
var pluck = function(name) {
return map(prop(name));
};
However, leveraging pipe
for combining functions makes it easier:
var pluck = pipe(prop, map);
Although not the most direct method for completing this task, having these versatile functions readily available will streamline future processes. This essence captures the crux of functional programming.
This discussion excludes one crucial tool in functional programming known as currying. An insightful article by Hugh Jackson explores its benefits (link here), while I have elaborated on it in another piece (additional details here). Currying would enhance the simplicity of these functions significantly. For instance, instead of
var propEq = function(name, val) {
return function(obj) {
return obj[name] === val;
};
}
We could achieve the same result with:
var propEq = curry(function(name, val, obj) {
return obj[name] === val;
});
This alteration paves the way for a cleaner and more flexible approach. Embracing a curry
function would not only refine the existing code but also enhance its versatility.