Different Styles of Curry

We've shown you how to manually create curried functions. However, many dynamic languages, especially JavaScript, use a lot of libraries and most aren't written in a functional way. Just like you can use promisify in Node to convert a callback function to a Promise based one, Lodash, Ramda, Folktale, and Sanctuary have a curry function to convert non-curried functions to curried ones.

These help in:

  • help beginners ease into curried functions
  • using 3rd party code you don't own
  • code you've already written and want to quickly convert
  • expose public functions that doesn't force curried function calling style onto those using the API who may not be FP developers

Lodash' & Ramda's curry

Instead of converting our loadWebsite function to be manually curried, we can instead use Lodash's curry function:

const { curry } = require('lodash')

const loadWebsite = (request, url) =>
    new Promise( ( success, failure ) =>
        request.get(url, (error, response, html) =>
            error
            ? failure(error)
            : success(html)
        )
    )

const loadWebsiteCurried = curry(loadWebsite)

Now, we can make a partial application:

const loadWebsiteWithRequest = loadWebsiteCurried(request)

Or just call the function:

loadWebsiteCurried(request)('http://jessewarden.com')

What's cool, though, is it's a lot more flexible and nicer to beginners. You can also call it like a regular function:

loadWebsiteCurried(request, 'http://jessewarden.com')

Doesn't even look curried, but can act like it if you need to.

Curry Arity & Style with Lodash, Ramda, Folktale, and Sanctuary

Lodash, Ramda, Folktale, and Sanctuary differ in how they report function arity. Arity means how many arguments a function takes. You can learn more in the Arity section. Some frameworks such as Express care about a function's arity.

Let's compare these non-default argument, non-variadic functions:

const alwaysTrue = () => true
alwaysTrue.length // 0

const loadWebsite = (request, url) => {
    console.log("Load stuff.")
}
loadWebsite.length // 2

Lodash

Lodash will report an arity of 0 always. It supports function calling in curried style (a)(b), imperative style (a, b), and mixed (a, b)(c):

const { curry } = require('lodash')

curry(alwaysTrue).length // 0
curry(loadWebsite).length // 0

Ramda

Ramda will report the length of the original function which is helpful if you intend to use this function in frameworks who care about function arity or you're not sure how many parameters a function requires. Sometimes you'll call a function and you'll be confused why you're getting a function back instead a Promise or some other expected value, so checking the function length can help, at least with Ramda. It supports function calling in curried style (a)(b), imperative style (a, b), and mixed (a, b)(c):

const { curry } = require('ramda')

curry(alwaysTrue).length // 0
curry(loadWebsite).length // 2

Folktale

Folktale requires you to define the function arity ahead of time, but like Lodash reports 0 no matter what you put. Like Lodash and Ramda, it supports function calling in curried style (a)(b), imperative style (a, b), and mixed (a, b)(c):

const curry = require('folktale/core/lambda/curry')

curry(0, alwaysTrue).length // 0
curry(2, loadWebsite).length // 0

Sanctuary

Sanctuary cares about types, and as such, doesn't support taking in variadic functions to convert to curried functions. Instead, you have to choose the arity ahead of time using one of their functions. They support curry2, curry3, curry4, and curry5. Unlike the others, it technically reports the correct number of 1, despite the number in curry2 or the others being bigger than 1. It only supports a curry style (a)(b) of calling functions.

const { curry2 } = require('sanctuary')

curry2(alwaysTrue).length // 1
curry2(loadWebsite).length // 1

Conclusions

If you're just starting out, use Lodash or Ramda. Ramda's curry is safer for use in cases where function arity needs to be correct. Manual currying is great, and you should practice to make it feel more natural. However, using curry is great for 3rd party code, your own code that isn't curried, and exposing functions to users who don't know what currying is and expect functions to work "like the normally do".

results matching ""

    No results matching ""