What is the difference between currying and partial application?

Viewed 62135

I quite often see on the Internet various complaints that other peoples examples of currying are not currying, but are actually just partial application.

I've not found a decent explanation of what partial application is, or how it differs from currying. There seems to be a general confusion, with equivalent examples being described as currying in some places, and partial application in others.

Could someone provide me with a definition of both terms, and details of how they differ?

16 Answers

Currying is converting a single function of n arguments into n functions with a single argument each. Given the following function:

function f(x,y,z) { z(x(y));}

When curried, becomes:

function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

In order to get the full application of f(x,y,z), you need to do this:

f(x)(y)(z);

Many functional languages let you write f x y z. If you only call f x y or f(x)(y) then you get a partially-applied function—the return value is a closure of lambda(z){z(x(y))} with passed-in the values of x and y to f(x,y).

One way to use partial application is to define functions as partial applications of generalized functions, like fold:

function fold(combineFunction, accumulator, list) {/* ... */}
function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);
function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);

/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list)  //returns 10

Simple answer

Curry: lets you call a function, splitting it in multiple calls, providing one argument per-call.

Partial: lets you call a function, splitting it in multiple calls, providing multiple arguments per-call.


Simple hints

Both allow you to call a function providing less arguments (or, better, providing them cumulatively). Actually both of them bind (at each call) a specific value to specific arguments of the function.

The real difference can be seen when the function has more than 2 arguments.


Simple e(c)(sample)

(in Javascript)

We want to run the following process function on different subjects (e.g. let's say our subjects are "subject1" and "foobar" strings):

function process(context, successCallback, errorCallback, subject) {...}

why always passing the arguments, like context and the callbacks, if they will be always the same?

Just bind some values for the the function:

processSubject = _.partial(process, my_context, my_success, my_error)
// assign fixed values to the first 3 arguments of the `process` function

and call it on subject1 and foobar, omitting the repetition of the first 3 arguments, with:

processSubject('subject1');
processSubject('foobar');

Comfy, isn't it?


With currying you'd instead need to pass one argument per time

curriedProcess = _.curry(process);   // make the function curry-able
processWithBoundedContext = curriedProcess(my_context);
processWithCallbacks = processWithBoundedContext(my_success)(my_error); // note: these are two sequential calls

result1 = processWithCallbacks('subject1');
// same as: process(my_context, my_success, my_error, 'subject1');

result2 = processWithCallbacks('foobar'); 
// same as: process(my_context, my_success, my_error, 'foobar');

Disclaimer

I skipped all the academic/mathematical explanation. Cause I don't know it. Maybe it helped


EDIT:

As added by @basickarl, a further slight difference in use of the two functions (see Lodash for examples) is that:

  • partial returns a pre-cooked function that can be called once with the missing argument(s) and return the final result;
  • while curry is being called multiple times (one for each argument), returning a pre-cooked function each time; except in the case of calling with the last argument, that will return the actual result from the processing of all the arguments.

With ES6:

here's a quick example of how immediate Currying and Partial-application are in ECMAScript 6.

const partialSum = math => (eng, geo) => math + eng + geo;
const curriedSum = math => eng => geo => math + eng + geo;

I had this question a lot while learning and have since been asked it many times. The simplest way I can describe the difference is that both are the same :) Let me explain...there are obviously differences.

Both partial application and currying involve supplying arguments to a function, perhaps not all at once. A fairly canonical example is adding two numbers. In pseudocode (actually JS without keywords), the base function may be the following:

add = (x, y) => x + y

If I wanted an "addOne" function, I could partially apply it or curry it:

addOneC = curry(add, 1)
addOneP = partial(add, 1)

Now using them is clear:

addOneC(2) #=> 3
addOneP(2) #=> 3

So what's the difference? Well, it's subtle, but partial application involves supplying some arguments and the returned function will then execute the main function upon next invocation whereas currying will keep waiting till it has all the arguments necessary:

curriedAdd = curry(add) # notice, no args are provided
addOne = curriedAdd(1) # returns a function that can be used to provide the last argument
addOne(2) #=> returns 3, as we want

partialAdd = partial(add) # no args provided, but this still returns a function
addOne = partialAdd(1) # oops! can only use a partially applied function once, so now we're trying to add one to an undefined value (no second argument), and we get an error

In short, use partial application to prefill some values, knowing that the next time you call the method, it will execute, leaving undefined all unprovided arguments; use currying when you want to continually return a partially-applied function as many times as necessary to fulfill the function signature. One final contrived example:

curriedAdd = curry(add)
curriedAdd()()()()()(1)(2) # ugly and dumb, but it works

partialAdd = partial(add)
partialAdd()()()()()(1)(2) # second invocation of those 7 calls fires it off with undefined parameters

Hope this helps!

UPDATE: Some languages or lib implementations will allow you to pass an arity (total number of arguments in final evaluation) to the partial application implementation which may conflate my two descriptions into a confusing mess...but at that point, the two techniques are largely interchangeable.

I'm going to assume most people who ask this question are already familiar with the basic concepts so their is no need to talk about that. It's the overlap that is the confusing part.

You might be able to fully use the concepts, but you understand them together as this pseudo-atomic amorphous conceptual blur. What is missing is knowing where the boundary between them is.

Instead of defining what each one is, it's easier to highlight just their differences—the boundary.

Currying is when you define the function.

Partial Application is when you call the function.

Application is math-speak for calling a function.

Partial application requires calling a curried function and getting a function as the return type.

A lot of people here do not address this properly, and no one has talked about overlaps.

Simple answer

Currying: Lets you call a function, splitting it in multiple calls, providing one argument per-call.

Partial Application: Lets you call a function, splitting it in multiple calls, providing multiple arguments per-call.

One of the significant differences between the two is that a call to a partially applied function returns the result right away, not another function down the currying chain; this distinction can be illustrated clearly for functions whose arity is greater than two.

What does that mean? That means that there are max two calls for a partial function. Currying has as many as the amount of arguments. If the currying function only has two arguments, then it is essentially the same as a partial function.

Examples

Partial Application and Currying

function bothPartialAndCurry(firstArgument) {
    return function(secondArgument) {
        return firstArgument + secondArgument;
    }
}

const partialAndCurry = bothPartialAndCurry(1);
const result = partialAndCurry(2);

Partial Application

function partialOnly(firstArgument, secondArgument) {
    return function(thirdArgument, fourthArgument, fifthArgument) {
        return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
    }
}

const partial = partialOnly(1, 2);
const result = partial(3, 4, 5);

Currying

function curryOnly(firstArgument) {
    return function(secondArgument) {
        return function(thirdArgument) {
            return function(fourthArgument ) {
                return function(fifthArgument) {
                    return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
                }
            }
        }
    }
}

const curryFirst = curryOnly(1);
const currySecond = curryFirst(2);
const curryThird = currySecond(3);
const curryFourth = curryThird(4);
const result = curryFourth(5);

// or...

const result = curryOnly(1)(2)(3)(4)(5);

Naming conventions

I'll write this when I have time, which is soon.

Currying

Wikipedia says

Currying is the technique of converting a function that takes multiple arguments into a sequence of functions that each takes a single argument.

Example

const add = (a, b) => a + b

const addC = (a) => (b) => a + b // curried function. Where C means curried

Partial application

Article Just Enough FP: Partial Application

Partial application is the act of applying some, but not all, of the arguments to a function and returning a new function awaiting the rest of the arguments. These applied arguments are stored in closure and remain available to any of the partially applied returned functions in the future.

Example

const add = (a) => (b) => a + b

const add3 = add(3) // add3 is a partially applied function

add3(5) // 8

The difference is

  1. currying is a technique (pattern)
  2. partial application is a function with some predefined arguments (like add3 from the previous example)
Related