Javascript and Functional Programming: Currying (Pt.4)

Written by omergoldberg | Published 2017/12/16
Tech Story Tags: javascript | currying | functional-programming | programming | software-development

TLDRvia the TL;DR App

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.

Why You Should Care About Currying

  1. Currying gives us the ability to compose terse, concise and reusable functions.

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!

Examples

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"]

Summary

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!

If this post was helpful, please click the clap 👏 button below to show your support! ⬇⬇

You can follow me on Instagram, Linkedin and Medium.


Published by HackerNoon on 2017/12/16