Omer Goldberg
28 Feb 2018
•
3 min read
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
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.
Currying gives us the ability to compose terse, concise and reusable functions.
We use these functions as clean, testable units of logic to compose the more logically complex parts of our programs.
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)
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)
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!
And most importantly! I am creating these tutorials using Mindflow.ai. Mindflow creates smart summaries of your workflow (nearly) automatically. It makes documenting my work a breeze!
If you’re passionate about Front End development, check out the JavaScript Works job-board here!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!