DEV Community

Cover image for Programming concepts in JS: Currying 🍛
Paul Bricout
Paul Bricout

Posted on

Programming concepts in JS: Currying 🍛

What does Currying mean?

According to Wikipedia:

"In mathematics and computer science, currying is the technique of converting a function that takes multiple arguments into a sequence of functions that each take a single argument."

Okay, but what does it mean?

Imagine that you have a function that takes a value in meters and a unit of distance as inputs and convert the value to the given unit, here is a basic implementation of such a function:

const convertMetersTo = (toUnit, value) => {
    switch (toUnit) {
        case 'mm':
            return value * 1000
        case 'cm':
            return value * 100
        case 'dm':
            return value * 10
        case 'm':
            return value * 1
        case 'dam':
            return value * 0.1
        case 'hm':
            return value * 0.01
        case 'km':
            return value * 0.001
    }
}

convertMetersTo('km', 3)  // returns 0.003
Enter fullscreen mode Exit fullscreen mode

Now, currying this function means that we want to make it return another function in order to be sequential, taking our example we would change it to look like this:

const convertMetersTo = (toUnit) => (value) => {
    switch (toUnit) {
        case 'mm':
            return value * 1000
        case 'cm':
            return value * 100
        case 'dm':
            return value * 10
        case 'm':
            return value * 1
        case 'dam':
            return value * 0.1
        case 'hm':
            return value * 0.01
        case 'km':
            return value * 0.001
    }
}

convertMetersTo('km')(3) // returns 0.003
Enter fullscreen mode Exit fullscreen mode

Okay, but why would I do that?

So, obviously both method works, but here is why I believe you should try to identify opportunities to curry functions. Let's say that you will use this function multiple times in a row (for one reason or another), in the first case you will write it as:

const convertedValue1 = convertMetersTo('km', value1)
const convertedValue2 = convertMetersTo('km', value2)
const convertedValue3 = convertMetersTo('km', value3)
const convertedValue4 = convertMetersTo('km', value4)
Enter fullscreen mode Exit fullscreen mode

It is straightforward enough, but this is a simple example and remember that as a dev your job is too be as lazy as possible and avoid repeating yourself. With Currying, you would just need to declare the unit once, and then it gives a function that you can reuse as you like.

const convertMetersToKm = convertMetersTo('km')

const convertedValue1 = convertMetersToKm(value1)
const convertedValue2 = convertMetersToKm(value2)
const convertedValue3 = convertMetersToKm(value3)
const convertedValue4 = convertMetersToKm(value4)
Enter fullscreen mode Exit fullscreen mode

Or, we could reverse the order of the arguments for, let's say, displaying one value in different units:

const convertMetersTo = (value) => (toUnit) => {
    switch (toUnit) {
        case 'mm':
            return value * 1000
        case 'cm':
            return value * 100
        case 'dm':
            return value * 10
        case 'm':
            return value * 1
        case 'dam':
            return value * 0.1
        case 'hm':
            return value * 0.01
        case 'km':
            return value * 0.001
    }
}

const value = 1000
const convertValueTo = convertMetersTo(value)

const convertedValue1 = convertValueTo('mm') // 1000000
const convertedValue2 = convertValueTo('cm') // 100000
const convertedValue3 = convertValueTo('dm') // 10000
const convertedValue4 = convertValueTo('km') // 1
Enter fullscreen mode Exit fullscreen mode

Now imagine this with more complex functions: you get to avoid repetition and make your code simpler and more efficient.

In some other examples, you could have some computation made in the first function, and that way you avoid having your code making the same computation multiple time!

A couple of examples that React/Redux devs uses all the time

  1. Redux's connect function

    Redux's connect function is a good example of a use for currying, since it is a function that returns another function passing down mapped props from the redux store to our component.

    It wouldn't be impossible nor unthinkable to use the same base connect function to pass down the same props to different component like so:

    const RedPriceBase = ({ price }) => {
        return <p style={{ color: 'red' }}>{ price } in red!</p>
    }
    
    const BluePriceBase = ({ price }) => {
        return <p style={{ color: 'blue' }}>{ price } in blue!</p>
    }
    
    const mapStateToProps = (state) => {
        return {
            price: state.price
        }
    }
    
    // one redux connect function
    const connector = connect(mapStateToProps)
    
    // reused for two components
    export const RedPrice = connector(RedPriceBase)
    export const BluePriceBase = connector(BluePriceBase)
    
  2. Redux Thunk

    Here is what a typical Thunk Action used in redux looks like:

    const fetchData = (params) => {
        return async (dispatch) => {
            dispatch(fetchDataRequest())
            try {
               const response = Api.fetchData(params)
               dispatch(fetchDataSuccess(response))
            } catch (e) {
                dispatch(fetchDataFailure(e))
            }
        }
    }
    

    The pattern looks familiar? Yup it's another example of currying! Here behind the scenes, when the action gets dispatched to the redux store, the redux-thunk middleware sees if the returned value of the action is a function (instead othe the typical action object with keys type and payload), and in that case it calls it with dispatch and getState!

Conclusion

This short article was made to explore what is currying in a programming context, how and why we could use it, and give some example for JS devs to give a better understanding. Currying is such a simple concept that I would love to see implemented in more and more codebases!

I don't write a lot of articles, this is the second write I wrote in a year, but I would love to get on writing more often about programming and such so if you have feedback to give me, as well as ideas and suggestions on how I could make this article better and easier to read, please leave a comment saying so!

Top comments (0)