FP in C++:
Partial application




Learn about partial application

As API creators we often wish to specialize functions or prefill certain parameters

This can be achieved with the help of partial application

We supply a subset of concrete arguments

and produce a function of smaller arity.

Let's look at a concrete example

This function calculates area of a circular sector

double secArea(double theta, double radius){
    return 0.5*theta*pow(radius,2);

pow requires the header <cmath>. Angle is expected in radians.

Let's specialize this function to calculate the area of a full circle

We wil need nested lambda to express partial application

auto papply = [](auto f, auto x) {
        return [=](auto y){
            return f(x,y);
auto op = papply(f, 6.28);

Outer lambda contains the argument known at the beginning, i.e. the specialized argument.

Specialization becomes easy

To achieve specialization we only have to pass the function and its first argument.

auto op = papply(secArea,2*M_PI); // full circle specialization
auto val = op(3.0); // area of a circle with radius 3.0

In the previous case, specialization concerned the first function argument.

double secArea(double rAngle, double radius);

However, often we have to deal with undesired argument ordering.

pow C library function raises the base to its exponent

double pow (double base, double exponent);

How do we specialize pow to return the base raised to the power of 2?

Not what we intended

This application would produce 2 raised to any power.

auto op = papply(pow,2); // 2 raised to any power
auto val = op(3); // 2^3 = 8

The pow function requires specialization of the second argument.

double pow (double base, double exponent);

This problem can be solved via argument swap

  1. with a general higher-order function
  2. with a dedicated lambda expression
  3. with std::bind and std::placeholders

Swap arguments with a general nested lambda

auto swapArgs = [] (auto f){
        return [=](auto x, auto y){
            return f(y,x);
auto op = papply(swapArgs(pow), 2); // raises to the power of 2
auto val = op(3); // 3^2 = 9, what we intended
This solution only works for binary functions.

Dedicated lambda works also for multi-argument problems

auto powS = [](auto exponent, auto base){
               return pow(base, exponent);
auto op = papply(powS, 2); // raises to the power of 2
auto val = op(3); // 3^2 = 9, what we intended

Dedicated solution can be expressed in a more compact form

auto op = papply([](auto exponent, auto base){
                     return pow(base, exponent);}, 2);

auto val = op(3); // 3^2 = 9, what we intended

Another option is to use the library function std::bind

This solution bypasses the use lambda expressions.

auto op = std::bind(pow, std::placeholders::_1, 2);
auto val = op(3); // 3^2 = 9, what we intended

std::bind and std::placeholders require the header <functional>

Test your knowledge on a concrete example

Age of objects containing organic material can be determined by radioisotope dating

This is a general equation for radioactive decay

double age(double remainingProportion, double halflife){
    return log(remainingProportion)*halflife / -log(2);

T1: Specialize the general equation for C14

Substitute half-life with the half-life of carbon C14, i.e. 5730 years. Mark all the correct answers.

T2: Determine age

How old is a fossil that has 40% of C14 compared to a living sample?

Use e.g. auto val = op2(0.4);

Specialization of functions related to regular expressions can be also very useful.

Let's specialize std::regex_match

std::regex_match determines if a regular expression re matches the entire character sequence s.
bool std::regex_match( const std::string& s,
                  const std::regex& re,
                  std::regex_constants::match_flag_type flags =

We are going to ignore the third parameter since it has a default value.

How could we specialize std::regex_match to validate email addresses?

We use dedicated lambda to achieve the desired argument ordering

auto op = papply([](auto re, auto str){
        return std::regex_match(str, re);}, 
auto val1 = op("test@walletfox.com") // return 1, i.e. true
auto val2 = op("test@walletfoxcom") // return 0, i.e. false

std::regex_match requires the header <regex>

Let's move on to multi-argument problems

This is a formula for final velocity of a moving object

double velocity(double v0, double a, double t){
    return v0 + a*t;

How would we specialize this formula for free fall problems?

We want to specialize two arguments, initial velocity and acceleration.

We wil need nested lambda and parameter pack

auto papply = [](auto f, auto... args) {
    return [=](auto... rargs) {
        return f(args..., rargs...);
The use of multiple arguments is expressed with a parameter pack ...

args refers to the primary specialization, rargs refers to the rest of the arguments.

We apply it analogously to the binary case

auto op = papply(velocity, 0.0, 9.81);
auto val = op(4.5); // returns 44.15 m/s
In this specific case, no swaps were necessary.

How about specializing higher-order functions?

This function performs left fold on a collection

auto leftFold = [](auto col, auto op, auto init) {
    return std::accumulate(std::begin(col), std::end(col), 
           init, op);
The function leftFold combines elements of the collection col, using a binary operation op, starting from the value init.

std::accumulate requires the header <numeric>

This specialization of leftFold performs summation

auto op = papply([](auto op, auto init, auto col){
                    return leftFold(col, op, init);},
                    std::plus<>(), 0.0);
The function computes the sum of elements of the collection starting from the value 0.0.

std::plus requires the header <functional>

T3: Specialize leftFold to compute product

Fill in the blanks to compute a product of a collection:
auto op = papply([](auto op, auto init, auto col){
                    return leftFold(col, op, init);},
                    __________, ___);

Let's sum it all up

Partial application