Mastering functional programming with Ramda Part 1: Why ‘both’ instead of ‘and’

Imab Asghar
Code道
Published in
3 min readNov 6, 2020

When I was first introduced to ramda by our tech lead, I wanted to use it asap. The first thing I did was replace my && operator with the and function. It worked like a charm! The next time I had to use || operator, I accidentally used either instead of the or function. And guess what, It did not work. I replaced with the or function and it worked and I reported to my tech lead that either does not work, I don’t even know why it exists. True Story!

However as time passed and I dived more into pipe chaining functions, curried functions and higher order functions, I came to know the usage of some of the logic functions of ramda.

Basically there are two types of logic functions in ramda:

  • that accept value(s) as argument
  • that accept other function(s) as argument. (aka higher order functions)

As example let’s compare the syntax for and vs both. Let’s first look at an example using the and function.

const isPendingDebitTransaction = (transaction) => {
const isPendingTransaction = transaction.status === 'Pending'
const isDebitTransaction = transaction.type === 'Debit'

return and(isPendingTransaction, isDebitTransaction)
};

Here is the ramda repl for the above and functions code snippet.

Now let’s look at the same example but using the both function now.

const isPendingTransaction = transaction => transaction.status === 'Pending'
const isDebitTransaction = transaction => transaction.type === 'Debit'
const isPendingDebitTransaction = (transaction) => {
return both(isPendingTransaction, isDebitTransaction)(transaction)
};
// Above function could also be shortened to
const isPendingDebitTransaction = both(
isPendingTransaction,
isDebitTransaction
);

Here is the ramda repl for the above both functions code snippet.

The end result of both functions is same however one can see the number of reusable functions increased by using the both functions without any extra effort. Additionally higher order functions help us with composing other functions with less code and less complexity. Guess what we would do if we want to create a function called isPendingDebitTransactionUnder10?

const isTransactionUnder10 = transaction => transaction.amount < 10const isPendingDebitTransactionUnder10 = both(
isPendingDebitTransaction,
isTransactionUnder10,
)

Here are some more examples of ramda’s logic functions which accept value arguments (similar to the and function):

Here are some more examples of logic functions which accept other functions as arguments (similar to the both function):

either and both work with two conditions. On the other hand anyPass and allPass work with multiple conditions. anyPass and allPass expect the first argument to be an array of functions.

As an example usage of allPass , I will use the exact code from one of our angular app’s async validator:

public fishingActivityAlreadyAddedValidator = ({ value: { fishingDate, aln, areaCode, potSoaked, targetSpecies }}: FormGroup) =>
this.fishingActivityStore.select(this.selectFishingActivities)
.pipe(
take(1),
map((fishingActivities) =>
fishingActivities
.some(allPass([
(fa: FishingActivity) => moment(fishingDate).isSame(prop('fishingDate', fa), 'day'),
propEq('aln', aln),
propEq('areaCode', areaCode),
propEq('potSoaked', potSoaked),
propEq('targetSpecies', targetSpecies),
])
) ? { fishingActivityAlreadyExists: true } : null,
),
)

Here is the ramda repl for the above code showcasing the allPass.

Note about above code: Inside the fishingActivity object, fishingDate will have date and time both. However we want to just check against the date of each objects. I used Moment.js isSame function inside our arrow function. This also means we can use any similar custom functions and not necessarily we need to use ramda functions as arguments to the higher order functions of ramda.

Although ramda is not yet fully typescript friendly, it is still very powerful and useful if you want to do functional programming.

If you are keen on trying out ramda, I would suggest you read a bit more about functional programming. If you think the learning curve of functional programming is a bit too much, I would suggest stick to imperative programming while using the ramda functions which pass value arguments (like and, or, not, etc.). Then gradually transition to more functional programming by trying out higher order functions and composing your own higher order functions.

Thanks for reading! Feel free to ask any questions.

--

--