Functional programming with Ramda

I watched this YouTube video Hey, Underscore, You’re Doing It Wrong given by Brian Lonsdorf. This dude is so smart. Thanks to the fact that he was also very articulate and funny while presenting it, I was able to understand most of it. This kind of drew my interests to Ramda. I started using it. The more I use and get to know Ramda, the more I love it. It allows me to write code so concisely.

But first, there seems to be a problem with the way Ramda implements their R.gt and R.lt (two functions that do greater than and less than comparison respectively). Let’s say I have an array of integers and I want to to filter all elements greater than 10. In the documentation, it says this function R.gt (likewise for R.lt, but we’ll just focus on 1 case, because everything about R.gt will apply to R.lt) returns true if the first parameter is greater than the second. This in my opinion cause a problem when I try to create a partial function that takes 1 fewer argument and awaits to be executed when supplied with this remaining argument. This is how I define my gt10 function:

var gt10 = R.gt(10); //gt10 is curried or partially applied
var myArray = [9,10,11,12,13,20,22];
console.log('x > 10: ', R.filter(gt10, myArray));
//This does not work.  It returns [9]

What am I doing wrong? When I take a Ramda function R.gt in this case which expects 2 arguments, and I turn it into a new function called gt10 which expects only 1 argument. I can do so because of 2 reasons:

  1. Ramda functions are automatically curried. Later, I will show how I can a function and in order for me to curry it, I have to explicitly call curry on it.
  2. To go from expecting 2 arguments to expecting 1 argument means I have to supply 1 argument. In this case, because I am interested in comparing any input to see if it’s greater than 10, I supply 10 as the argument.

Since currying in Ramda proceeds from right to left, the argument I supply (which is 10) will be the first argument to R.gt. Remember what the doc says, R.gt returns true if the first parameter is greater than the second, so then when I apply gt10 over the map of my array, it would result in the opposite effect. There are a few work-arounds. The first one is kind of counter-intuitive and it’s done as below:

var gt10 = R.lt(10);
var myArray = [9,10,11,12,13,20,22];
console.log('x > 10: ', R.filter(gt10, myArray));

The second way:

var myArray = [9,10,11,12,13,20,22];
var gt10 = x => R.gt(R.__, 10)(x);
console.log('x > 10: ', R.filter(gt10, myArray));

And for the third way, I’ll write a replacement for R.gt myself. Since any function that we write is not auto-curried, I’ll have to curry it myself too. Fortunately, Ramda provides a R.curry. My implementation of the function gt just reverses the role of the first and second arguments from those in Ramda’s R.gt function.

//http://jsfiddle.net/kevinle/bjuy00ea/6/
var gt = (lowerBound, input) => input > lowerBound;
var curriedGt = R.curry(gt);
console.log(gt(10, 11));
console.log(curriedGt(10, 11));
console.log(curriedGt(10)(11));
var lt = (upperBound, input) => input < upperBound;
var curriedLt = R.curry(lt);
var gt10 = curriedGt(10);
var lt20 = curriedLt(20);
var between = R.and(gt10, lt20);
var myArray = [9,10,11,12,13,20,22];
console.log(R.filter(between, myArray));

If the first line seems peculiar to you, it’s because I’m using a couple of new features of ES6. I have been using ES6 and have never since looked back. This first line

var gt = (lowerBound, input) => input > lowerBound;

essentially is equivalent to the following in ES5:

var gt = function(lowerBound, input) {
return input > lowerBound;
}

In ES6, there are a lot less ceremonies. The keyword function is dropped, and the fat arrow is “borrowed” from CoffeeScript and/or Swift (skinny arrow). The other things that is worth to mention is by currying my gt function, I would be able to call it one time if I supply both arguments, or call it with one argument at a time, but that would require 2 invocations.

So where’s my love for Ramda? I’ll show it to you in next post when I combine it with React. You don’t want to miss the chance to see this pattern that I’ll present.