Partial application is like making tea. The person making the tea needs two pieces of information: what kind of tea, and how many people to serve. We can save time by knowing one of those pieces of information before we begin.
Let’s say we have a tea shop. Whenever a new person comes in with a group, you need to ask them two questions: what kind of tea would they like, and how many cups do they need? After that, you know how to do the rest. Of course, sometimes the customer hems and haws about what kind of tea so it can take a while…
But then the door opens and one of your regulars comes in. You know that she always asks for a green tea, but you’re never sure who she’s coming to meet, so you still have to ask her how many cups she’d like. Because you already know the kind of tea, you only need one piece of information instead of two. You’ve kept the first piece of information in your memory. This is partial application.
When programming, you may be writing a function that takes two (or more!) arguments. If you often use that function in a particular way, you can prepare it by creating a partially applied version that only takes one argument instead of two, keeping the missing argument in memory (often through the clever use of closures). Then when you want to call it, you can call the partially applied version.
Partial application means taking a function and partially applying it to one or more of its arguments, but not all, creating a new function in the process. (Dave Atchley)
A little harder to explain is why you’d want to do that. Well, for me the main reason is to be able to pipe the result of a series of functions together.
That is, when you have a series of functions that need to be run on the same piece of data, you might write something like:
adjustedData = adjustData( data ); preparedData = prepareData( properties, adjustedData ); doSomething( preparedData );
That works fine, but in some cases it can get messy. Also, we’ve created two temporary variables whose entire purpose is to pass the result of one function on to the next. We can do better!
doSomething( prepareData( properties, adjustData( data ) ) );
Ok, that gets rid of the variables, but it’s way less readable. Just think what it would look like if there were ten functions in that chain! What we need is a way to pipe data from one function to the next just like the
| character in UNIX shells. There is a type of function which does this, sometimes called “pipe”, “compose”, or “flow”.
composedFunction = flow( adjustData, prepareData, doSomething ); composedFunction( data );
Wow, that’s so much better! It’s even easy to add or remove steps in the chain. But you may have noticed that I skipped a step:
prepareData takes two arguments, so how can we get that second argument in there?
What we need is a way to transform
prepareData from a function that accepts two arguments into a function that accepts one argument. This is partial application.
prepareDataWithProperties = partiallyApply( prepareData, properties ); composedFunction = flow( adjustData, prepareDataWithProperties, doSomething ); composedFunction( data );
Now the partially applied version can be used in our pipe because its first argument is already saved. This is like knowing what kind of tea to make already. We go from needing two pieces of information to only needing one.