DEV Community

Discussion on: Function Currying, What's the use?

Collapse
 
avalander profile image
Avalander • Edited

Basically, curried and partially applied functions allow you to inject data to the function at different stages, which is convenient to reuse functionality without having to inject the same data all over the place.

One example is a function that has two or more parameters and one of them will always be the same while the other can change.

For instance, imagine that we are writing a function to read an entry from a database by id. That function would need a connection to the database and an id to query. We could write it like this.

const getPony = (connection, id) =>
    connection.select('ponies')
        .where({ id })

getPony(connection, 1)

But now you need to pass the connection object around every time you want to query the database. Even worse, any code that reads ponies from the database will have to know both, about the getPony function and the connection object.

Let's consider what happens if we curry that function.

const makeGetPony = connection => id =>
    connection.select('ponies')
        .where({ id })

// When we initialise our app.
const getPony = makeGetPony(connection)

// Anywhere else
const twilight = getPony(1)

Now we can create the function getPony with the connection object and any code needing to read ponies only needs to know about that function.

What if our database stores other kinds of data besides ponies? –no clue why anybody would store anything other than ponies, but for the sake of the example, let's imagine it has a real use case. We might want to pass the name of the table we are querying to the function, so that it can query different tables. However, passing the same string over an over would be inconvenient, especially if we need to change the name of the table in the future. Better have it only in one place. We could add a new parameter to our curried function.

const makeGetTable = connection => table => id =>
    connection.select(table)
        .where({ id })

// When we initialise our app
const makeGetById = makeGetTable(connection)

const getPony = makeGetById('ponies')
const getDragon = makeGetById('dragons')
const getCat = makeGetById('cats')

// Anywhere else in our application
const twilight = getPony(1)
const fluffykins = getDragon(1)
const garfield = getCat(1)

Voilà, we only need to pass our connection object once, and we can use the intermediate function to create functions to query a different table each. Then we can pass these functions around and the rest of the code doesn't need to know about the connection object or table names that might change in the future or may be hard to remember or we will type incorrectly.