The latest version of Ramda contains 235 individual functions.
To help you on your path to functional greatness, here are our picks for the top 10 functions from the Ramda library. We’ve used these across three large, complex web applications developed at Media Suite. The method used for collecting this data is tracked here.
A key concept in functional programming is writing functions that work on other functions. One of the most important examples of this is the concept of currying.
Consider this example: We have a regular function add which we pass as an argument to R.curry . The result of this is a function which can not be called without passing in all of the defined parameters. When addCurried(1) is called, we get a version of the add function where the first parameter is always the value “1”. All functions in the Ramda library are curried by default.
const add = (a, b) => a + b
console.log(add(1, 2))
// > 3
const addCurried = R.curry(add)
const addOne = addCurried(1)
console.log(addOne(9))
// > 10
R.propEq
This function takes three parameters: a property name (string), a value and an object. It checks if the property name on the object is equal to the value provided. Most of the time, this function is used in a filter clause or if clause .
const isCircle = R.propEq('type', 'circle')
const shapes = [
{ type: 'circle', width: 10, height: 10},
{ type: 'square', width: 10, height: 10},
]
console.log(isCircle(shapes[0]))
// > true
console.log(isCircle(shapes[1]))
// > false
R.merge
This function is similar in function to Object.assign. It expects two object arguments and returns an object. The behaviour is to merge all fields from the right hand object into the left hand object. This is typically used within a “map” function to apply fields to another object.
const circle = { type: 'circle', width: 10, height: 10}
const boldBorder = R.merge({ border: '5px' })
console.log(boldBorder(shapes[0]))
// > { border: '5px', type: 'circle', width: 10, height: 10}
R.isNil
Part of writing good reusable functions is checking that the correct parameters are used. R.isNil lets us check if the value is nil or undefined. In our projects over the last year we have used this function 79 times.
R.isNil(null) // > true
R.isNil(undefined) // > true
R.isNil(0) // > false
R.isNil("functions are great") // > false
R.filter
This works like Array.prototype.filter, but with more currying and switched around parameters to what you may expect, coming from other utility libraries like lodash. It expects two parameters. First, a function which takes one parameter and returns truthy or falsy values. Second, an array. We use this function frequently to get the right array of things before passing that array into another function for further processing.
const shapes = [
{ type: 'circle', width: 10, height: 10},
{ type: 'square', width: 10, height: 10},
]
const getCircles = R.filter(isCircle)
console.log(getCircles(shapes))
// > [{ type: 'circle', width: 10, height: 10}]
R.pluck
At number four out of 10, we used the pluck function, 111 times. It takes a string and array of objects as parameters. The return is an array of values picked out from each object in the input array.
const shapes = [
{ label: 'Fierce Circle', type: 'circle', width: 10, height: 10},
{ label: 'Obtuse Square', type: 'square', width: 10, height: 10},
]
const getLabels = R.pluck('label')
console.log(getLabels, shapes)
// > ['Fierce Circle', 'Obtuse Square']
R.map
Map takes the same parameters, and returns the same type of value as filter. They are best friends. Often the output of a map is the input to a filter (or vice versa). It was used 200 times.
const shapes = [
{ label: 'Fierce Circle', type: 'circle', width: 10, height: 10},
{ label: 'Obtuse Square', type: 'square', width: 10, height: 10},
]
const isSquare = R.propEq('type', 'square')
const getSquares = R.filter(isSquare)
const getAreas = R.map(shape => shape.width * shape.height)
console.log(getArea(getSquares(shapes)))
// > [100]
R.pipe
In the previous nine functions I have demonstrated, we have made some neat little functions. Using currying, these functions now operate on a single value. To use a food as an analogy, R.pipe is the bread holding our tasty functions together to make a delicious sandwich.
In the previous example we used getArea , getSquares and finally console.log to print the results. The problem with nesting functions like this is that our eyes have to scan in an un-natural way to figure out how the data flows through functions. We have to find the value shapes , then scan each function to the left to understand the how the function operates on that parameter. The following example shows how we can create the same function by using pipe.
const printSquareAreas = R.pipe(
getSquares,
getAreas,
values => console.log(values)
)
printSquareAreas(shapes)