Is the entire world of aspiring functional programmers generally confused about partial function application and currying, or is it just me? I like to feel well-informed when I think to myself that these two are not the same thing, but I still couldn’t tell you what the difference is. To me they are like Bill and Ted on their Excellent Adventure; I know them when I see them, but I don’t know which is which. I have just decided it is time to dive in and get this straight. So here we go.
Divide and Conquer
Partial function application and currying both have to do with decomposing multi-parameter functions into smaller functions with fewer parameters. For example, in Haskell we might have an add function that takes two integers and returns their sum:
If I had this function available and wanted another function that took one number and added 3 to it, I could do this:
Now this function does just what we want.
When I see this kind of thing, I can say with confidence, “Ah, that’s that currying/partial application deal.” But which is it? Either one? Both?
After spending a little time digging in, I think my main problem here is that I’m only concerned about these concepts when working in languages whose functions support it implicitly, in my case Haskell and F#. I get these two bits of functional magic free in a gift bag, but since they’re always wrapped up together, they feel like one thing instead of two.
Break It Down
Of the two concepts, partial application is the easier to understand, thanks to its meaningful name. It is just what it sounds like. You have a function that takes more than one parameter, you pass it fewer parameters than it wants, and it returns a new function that will take the remaining parameters and return you your result, as we just demonstrated with our add3 function. It is partially applied, applied to some of its parameters with the option to apply the resulting function to the rest later.
So what is currying? Currying is the transformation of one multi-parameter function into a chain of single-parameter functions that ultimately yield the same result. The problem with trying to discuss currying in Haskell and F# is that they don’t have multi-parameter functions in first place. A function such as add, which logically has multiple parameters, is defined implicitly as a chain of single-parameter functions, or in the curried style. So when does the currying take place? I would have to say at compile time. No wonder I was missing it!
In Haskell and F#, currying is more their style of implementing multi-parameter functions than it is a technique that we use when writing in these languages. The functions are curried, period, whether or not we choose to partially apply them, which is the only time we would think to notice.
Now we can build a function to partially apply another two-parameter function by taking it and its first parameter, and returning a new function that takes the second parameter and returns the result.
Now we can use this function to build our add3 function by partially applying add.
We can use this function to create a curried version of add.
This function will return the same results as add but has to be called differently, since it is a chain of single-parameter functions.
Now back to the idea of how the curried style gives us partial application free of charge. Look at how we can partially apply our cAdd:
Do you see what we’ve got here? Currying is a way of defining a function; partial application is a way of applying a function. Currying is about construction; partial application is about consumption, with a by-product. Some functions are curried, but no functions are partial.
In the words of Blood, Sweat, and Tears, what goes up must come down, and curried functions can be uncurried (in languages that support multi-parameter functions). Uncurrying would be the transformation of a chain of single-parameter functions into one multi-parameter function. Here is a function that will do that for us:
Now we could use this function to create a new add function from our curried cAdd.
Excellent! We have separated partial application from currying. I think I might be able to remember the difference now. I hope you will, too.