Note: This is part of the “Javascript and Functional Programming” series on learning functional programming techniques in JavaScript ES6+. To start from the ground up check out <Part 1>
Currying is when we call a function with fewer arguments than it expects. In turn, the invoked function returns a function that takes the remaining arguments.
const magicPhrase =(magicWord) =>(muggleWord) =>magicWord + muggleWord
We could then invoke this function with the following pattern
Call it maaagic
Writing functions that return functions, that in turn return some output (possibly another function!) can get quite cumbersome. Luckily we have functional JS helper libraries like Ramda and lodash which provide us with utility methods such as curry. The curry utility wraps normally declared functions and transforms them into a series of one-argument functions. So we could convert the previous code to:
import _ from "lodash"
const magicPhrase = _.curry((magicWord, muggleWord) => magicWord + muggleWord)
const muggleWordAccepter = magicPhrase("Abra kedabra ")
muggleWordAccepter("dishwasher")
Another example would be a revamped implementation of our favorite add function
import _ from "lodash"
const addFunction = _.curry((a, b) => a + b)
const addOne = add(1)
addTen(1)
So we are essentially, “pre loading” the add function with the first variable. Our function has the ability to remember the first value passed thanks to JS closure.
2. We use these functions as clean, testable units of logic to compose the more logically complex parts of our programs.
3. With currying, any function that works on single elements can be converted into a function that works on arrays (lists), simply by wrapping it with map.
const getObjectId = (obj) => obj.id // works on single object
const arrayOfObjects = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
const arrayOfIDs = arrayOfObjects.map(getObjectId)
BAM! Our function that worked on single elements can work on arrays!
The only real way to get familiar with these concepts is to practice :) Let’s get to it. We shall start with one more example of converting a function that operates on a single element to a function that operates on an array.
const getFirstTwoLettersOfWord = (word) => word.substring(0,2)
// We can convert it, by wrapping it in the map method
["aabb", "bbcc", "ccdd", "ddee"].map(getFirstTwoLettersOfWord)
The next example comes out of the amazing Mostly Adequate guide, with a small ES6 refactors :)
Let’s refactor the max function so that it won’t reference any arguments.
arr = [2,4,6,8,9]
// LEAVE BE:const getMax = (x, y) => { return x >= y ? x : y;};// REFACTOR THIS ONE:const max = (arr) => { return arr.reduce((acc, x) => { return getMax(acc, x); }, -Infinity);};
const max = arr.reduce(getMax, -Infinity)
Let’s wrap the native JS slice method so that it functional and curried.
import _ from "lodash"
const arr = ["barney", "fred", "dave"]
arr.slice(0, 2) // ["barney", "fred"]
const slice = _.curry((start, end, arr) => arr.slice(start, end));const sliceWithSetIndexes = slice(0,2)
sliceWithSetIndexes(arr) // ["barney", "fred"]
We’ve seen several examples where we curry JS functions. Currying refers to the process of transforming a function with multiple arity (arguments accepted) into the same function with less arity. It utilizes JS closure to remember the arguments used in the previous invocations. Currying twists functions around so that they can work more naturally together. Its biggest advantage is that it easily allows for function composition, which we will explore in depth in the next post!