I want to demonstrate two foundational techniques you need to know to practice functional programming: function composition and curried functions. We’ll learn what these terms mean, how to implement them, and the advantages of using them.

These techniques are applicable in any programming language where functions are first-class values, meaning they can be passed around like any primitive value. For the purposes of this post, we will be implementing these patterns in JavaScript.

Function Composition

Function composition sounds fancy, but it’s really not. It’s actually just a way to automate something we all do manually anyway.

Imagine we have these three functions:

const getDescription = (obj) => obj.description
const truncate = (str) => str.slice(0, 100)
const appendEllipsis = (str) => `${str}...`

And we want to get the description from an item and format it to be 100 characters max and with a trailing ellipsis.

Without function composition, we might do something this:

const description = getDescription(item)
const truncatedDescription = truncate(description)
const descriptionWithEllipsis = appendEllipsis(truncatedDescription)

We set the return value of some function to a variable, and then turn around and pass that variable into the next function, and so on. This is a really common practice for most programmers. The only purpose of those variables is to pass them to the next function, so really we could just do this:

appendEllipsis(truncate(getDescription(item))))

But that’s a little awkward to read and evaluate in your head, so folks generally don’t do that. But are one-off intermediate variables really the solution? Must we choose between being writing verbose readable code or concise unreadable code? We’re programmers; can’t we automate the process of passing output to input?

We can do that by writing a function called composeLTR (read: compose left-to-right) 1, which takes any number of functions as arguments, and then returns a new function that will pass its arguments to the first function, then pass the return value to the next function, and so on.

Here’s the sales pitch. Using composeLTR would transform our code into this:

const extractFormattedDescription = composeLTR(
    getDescription,
    truncate,
    appendEllipsis
)

extractFormattedDescription(item) // => 'This is a truncated description...'

No more setting return values on temporary values and it’s still pretty readable. That’s great, because I hate having to come up with unique names for everything and I hate hard-to-read code.

Implementing It

Implementing composeLTR isn’t much work, but it can make your head spin a little bit at first. It looks like this:

const composeLTR = (...fns) => fns.reduce((first, second) => {
    return (...args) => second(first(...args))
})

All it does is exactly what we said: it takes many functions and returns a new function that automates the passing of input and output between those functions.

Curried Functions

Currying is a concept named after Haskell Curry, who was a logician and mathematician by vocation. It’s an odd term for an easier-done-than-said programming technique. I’d rather just show you a curried function than try to explain what it is.

Say you have function replaceAtIdx, that takes index, value, and array, and returns a copy of the array with the value at index set to value. It might look like this:

const replaceAtIdx = (index, value, array) => {
    return array.map((val, idx) => idx === index ? value : val)
}

replaceAtIdx(2, 'hi!', ['zero', 'one', 'two']) // => ['zero', 'one', 'hi!']

The curried version of replaceAtIdx wouldn’t look too terribly different. It would just look like this:

const replaceAtIdx = (index) => (value) => (array) => {
    return array.map((val, idx) => idx === index ? value : val)
}

replaceAtIdx (2) ('hi') (['zero', 'one', 'two']) // => ['zero', 'one', 'hi!']

Instead of taking all three arguments at once, our curried version of replaceAtIndex breaks the original “trinary”2 function into three “unary”3 functions, each returning another function which serves to act as a closure over the previous argument(s) and to take the next argument for the computation. When the last function is applied to its argument, then the block of code runs. That’s really all there is to currying. You just break a function of arity N down into N functions of arity 1.

Currying is admittedly a very strange concept when first learning functional programming from a procedural and/or object-oriented background. But it begins to make a lot more sense when you regularly make use of functional composition patterns, which is what we’re trying to do!

I’ll try to illustrate with example. Let’s adapt the code from the section on function composition:

Imagine we have these three curried functions:

const get = (propName) => (obj) => obj[propName]
const truncate = (length) => (str) => str.slice(0, length)
const append = (appendage) => (str) => `${str}${appendage}`

Since they are curried, we can use composeLTR like this:

const extractFormattedDescription = composeLTR(
    get('description'),
    truncate(100),
    append('...')
)

extractFormattedDescription(item) // => 'This is a truncated description...'

Each function requires two arguments in order to evaluate a result, but in the composeLTR pipeline, we only provide the first argument to each function so that we are composing the functions they return. The term for this idea of supplying some-but-not-all of the arguments a curried function requires is called “partial function application,” or more succinctly, “partial application.” Partial application is often conflated with currying because it is so closely related, but the distinction is that partial application is made possible by currying.

Once you start using composition, it becomes very natural to use curried functions and partially apply them. Currying allows you to build specialized functions from more generic functions (like creating getDescription with get('description')). Both of these together form a very powerful little technique that can transform your code base from verbose and full of intermediate variables, to very concise and expressive.

Currying and composition are arguably two of the most fundamental and versatile programming design patterns for code reuse. You use currying to build specialized functions from more general ones. Simply changing an argument creates a whole new specialized function, yet you didn’t have to write any new code; you just invoked a function! You use composition to string together however many functions you need to perform your desired transformation on the value, (leveraging your curried general functions along the way), to build up a super-specialized function that would have taken you twice the code to implement imperatively.

Once you experience the level productivity and flow that comes from solving problems this way, you’ll wonder how you ever got anything done before. And once you’re hooked on this power, you’ll start to get frustrated by the fact that native JS methods and most JS libraries don’t use currying. You’ll start to wish there were libraries that made it easier to use these basic techniques on every project because of how productive they make you and how tidy they make your code.

Hmm… that sounds like a really good segue for talking about ramda.js. All of their functions are curried and designed specifically for functional composition!


  1. composeLTR is commonly known as pipe ↩︎

  2. trinary - arity three; i.e., takes three arguments ↩︎

  3. unary - arity one; i.e., takes one argument ↩︎