Curry On Wayward Son

Currying is so hot right now in the functional-ish JavaScript community. If you’ve used libraries like Ramda, chances are you’ve had some exposure. Either way, let’s spell it out to be safe:

Functions in languages like Haskell or Elm take one input and return one output, whether you like it or not. If we want two arguments, we write a function that returns a function (because functions are also values!) and nest them:

const add = x => y => x + y // a la ES6

So, to add 2 and 3, we write add(2)(3). Currying a function means converting it from the usual style ((x, y) => x + y) to this style. With that said, we’ll see later that most of our favourite implementations of curry functions are more like curryish

Is there a point to this?

Yes! Obviously, writing add(2)(3) is ugly - and we’ll fix that later - but the power of this comes from the instances where you don’t supply all the arguments up front.

Think about it: add(2) returns a function that takes a value and adds 2 to it. Why do we have to give it that second number immediately? We could do all sorts of things:

// 1, 2, 3, 4, 5 - Oooooo
[-1, 0, 1, 2, 3].map(add(2))

When we play with functions that don’t have all their arguments yet, we call it partial application. In practice, what we’re doing is taking a very general function (add) and specialising it with some of its arguments.

Here’s a slightly more useful (although still majorly contrived) example of how we can wrap String.replace to be more flexible:

const replace = from => to => str =>
        str.replace(from, to)

const withName  = replace(/\{NAME\}/)
const withTom   = withName('Tom')
const withTrump = withName('tiny hands')

const stripVowels = replace(/[aeiou]/g)('')

withTom('Hello, {NAME}!') // Hello, Tom!
withTrump('Hello, {NAME}!') // Hello, tiny hands!

stripVowels('hello') // hll

// ['hll', 'wmbldn']
['hello', 'wimbledon'].map(stripVowels)

I don’t know about you, but I think this is really exciting: we’ve taken a single function and used partial application to specialise it in several exciting ways. Instead of writing a whole new replace for each function, we just partially apply some number of its arguments! So hot right now.

This is the inherent power of partial application: we can write very general functions, and specialise them for different purposes. This massively reduces boilerplate code, and looks super pretty.

But it’s hideous

Yeah, it’s kinda ugly when you see a call like replace(/a/)('e')(str) (all those brackets touching!) rather than replace(/a/, 'e', str), but we don’t want to be forced to supply all the arguments at once.

What we’d really like is to be able to write these arguments in any flexible grouping we need:

  == replace(/a/, 'e')(str)
  == replace(/a/)('e', str)
  == replace(/a/, 'e', str)

So, notice we haven’t uncurried the function - we’re just saying that, if we pass in more than one argument, we’d like them to be applied one at a time. To be technical, we’ve sort of uncurried it a little bit. This means we can hence write an appropriately-named function:

const uncurryish = f => {
  if (typeof f !== 'function')
    return f // Needn't curry!

  return (... xs) => uncurryish(
    xs.reduce((f, x) => f (x), f)

Maybe a bit ugly, but the gist of it is:

  • Any non-function gets returned unharmed.
  • Functions get wrapped in a function that takes one or more arguments, applies them one by one, then returns uncurryish of the result.

It’s that pesky recursion again! If you define the replace and uncurryish functions as above, you’ll see it all working. Yay!

Wait, uncurry? I wanted curry!

Well, no, this isn’t uncurry - it just looks a bit like it - but I see your point. When you use something like Ramda’s curry, they mean curryish. The only real difference between curryish and uncurryish is that curryish starts from a “normal” function (e.g. (x, y) => x + y), and uncurryish starts from a function in this article’s style. The end result is the same, although uncurryish has a much simpler implementation*… Whether you use one or the other is totally up to you!

Anyway, I hope this has shed some light. I thought it might be easier to start with uncurry and then bastardise it until it matched the curry we’re used to. All you need to know is that curry and uncurryish achieve the same result: they collect up a function’s arguments until they have enough to run the function, and then they return the function’s results.

It’s a really nifty little trick, and you can do some incredible refactoring with it. Of course, if anything doesn’t make sense, drop me a tweet or something, and I’ll try to clear it up!

Thanks so much for reading!

Take care ♥

* Not entirely fair - Ramda does some other stuff like placeholders - but it’s definitely more complex because of having to track the argument “state” explicitly.