functional programming curry

Welcome to the second installation in my series on functions and patterns in functional programming. This bit focuses on curry. For more, visit the Index where I share the rest.

Haskell Curry is a giant. His first name denotes a textbook functional programming language, his last name a technique in functional programming. It’s his surname that I shall address here.

While learning to program, currying to me seemed some esoteric concept in FP reserved for practitioners of Haskell and Clojure. But, in practical usage, it’s remarkably simple.

As a general rule, any time I find myself calling the same function — and passing it the same arguments — it’s a good time to curry the function. When a function is curried, we can preload it with certain arguments, and then pass it whatever its remaining arguments at will.

Say our codebase relies heavily on a third-party API method bearing the following signature:

makeApiRequest(requestType = '', url = '', headers = {}, body = {}) → Response

Where requestType is one of GET, POST, or PUT.

It won’t take long before we tire of writing makeApiRequest('GET', ...) and makeApiRequest('POST', ...) over and again.

Now, we could abstract our own helper functions like so:

export async function post(url = '', headers = {}, body = {}) {
  return makeApiRequest('POST', url, headers, body)
}

export async function put(url, headers = {}, body = {}) {
  return makeApiRequest('PUT', url, headers, body)
}

export async function get(url, headers = {}) {
  return makeApiRequest('GET', url, headers)
}

But I find it a bit tedious to rewrite all the arguments for each function definition. Instead, we could simply curry the function:

import {curry} from 'ramda'

export async function makeCurriedApiRequest() {
  return curry(makeApiRequest)
}

And then leverage our curried variation to preload any desired arguments:

export async function get() {
  return makeCurriedApiRequest('GET')
}

export async function post() {
  return makeCurriedApiRequest('POST')
}

export async function put() {
  return makeCurriedApiRequest('PUT')
}

Though not impossible to write your own curry function, I would advise use of Lodash/FP or Ramda, as their variations are more flexible and more powerful.

Resources

Further reading

We're building an AI-powered Product Operations Cloud, leveraging AI in almost every aspect of the software delivery lifecycle. Want to test drive it with us? Join the ProdOps party at ProdOps.ai.